/****************************************** Variables et Constantes *************************************/
var ns4=document.layers;		// Netscape 4
var ie4=document.all;			// A partir d'IE 4
var ns6=document.getElementBy;	// Netscape 6

/*
Schéma XML d'un TClientDataset Delphi

<?xml version="1.0" standalone="yes"?>
  <DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="ALPHA" fieldtype="string" WIDTH="20"/>
<FIELD attrname="INTEGER" fieldtype="i4"/>
<FIELD attrname="DATETIME" fieldtype="dateTime"/>
<FIELD attrname="MEMO" fieldtype="bin.hex" SUBTYPE="Text"/>
<FIELD attrname="FLOAT" fieldtype="r8"/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW ALPHA="ABCDEF" INTEGER="1024" DATETIME="20041213T23:30:05000" MEMO="Ceci est un champ mémo&#13;&#10;Ligne 2&#13;&#10;Ligne 3" FLOAT="55.65"/>
<ROW ALPHA="GHIJKL" INTEGER="2048" DATETIME="20041214T22:30:05000" MEMO="Champ mémo" FLOAT="125.56"/>
</ROWDATA>
</DATAPACKET>
*/

var ftUnknown	= 0;
var ftString 	= 1;
var ftInteger	= 2;
var ftFloat	 	= 3;
var ftMemo	 	= 4;
var ftDateTime	= 5;

var dsInactive	= 0;
var dsBrowse	= 1;
var dsEdit		= 2;
var dsInsert	= 3;

/***********************************************************************************
******************************* TDATASET *******************************************
************************************************************************************/
function TDataSet() {
	this.Record 		= new Array(1024); 	// Nombre maxi d'enregistrements = 1024
	this.RecordParam	= new Array(1);		// Nombre de record possible pour les params = 1 !
	this.Pointeur		= -1;
	this.FieldDefs 		= new TFieldDefs(this);
	this.Params 		= new TParams();
	this.RecordCount	= 0;
	this.State			= dsBrowse;
	this.PrimaryKey 	= "";
	this.Eof			= true;
	this.OnStateChange 	= null;
	this.OnCancel		= null;
}

/***********************************************************************************
********************************* TParam *******************************************
************************************************************************************/
function TParam() {
	this.FieldName	= "";
	this.DataType 	= ftUnknown;
	this.Size	  	= 0;
}

/***********************************************************************************
****************************** TFieldDef *******************************************
************************************************************************************/
function TFieldDef() {
	this.FieldName	= "";
	this.DataType 	= ftUnknown;
	this.Size	  	= 0;
	this.NotEmpty 	= false;
	this.DisplayLabel= "";
}

/***********************************************************************************
********************************* ParamAdd *****************************************
************************************************************************************/
function ParamAdd(FieldName,DataType,Size) {
this.Items[this.Count] 				= new TParam();
this.Items[this.Count].FieldName	= FieldName;
this.Items[this.Count].DataType		= DataType;
this.Items[this.Count].Size	  		= Size;	
this.Count++;
}

/***********************************************************************************
***************************** TFieldDefs.prototype.Add *****************************
************************************************************************************/
TFieldDefs.prototype.Add = function(FieldName,DataType,Size,DisplayLabel,NotEmpty) {
this.Items[this.Count] = new TFieldDef();
this.Items[this.Count].FieldName	= FieldName;
this.Items[this.Count].DataType		= DataType;
this.Items[this.Count].Size	  		= Size;	
this.Items[this.Count].DisplayLabel	= DisplayLabel;
this.Items[this.Count].NotEmpty		= NotEmpty;
this.Count++;
/* Ajout du DisplayLabel */
var FieldNameSys = "SYS_"+FieldName+"_DL";
if (FieldNameSys.length >= 30)
	throw new Error(0,"TFieldDefs.Add FieldNameSys="+FieldNameSys+" trop grand >=30 !");
this.Parent.Params.Add(FieldNameSys,ftString,30);
this.Parent.ParamByName(FieldNameSys,DisplayLabel);
}

/***********************************************************************************
********************************* TParams ******************************************
************************************************************************************/
function TParams() {
this.Items 	= new Array(64); /* Nombre maxi de champs = 64 */
this.Count 	= 0;
this.Add	= ParamAdd;
}

/***********************************************************************************
********************************* TFieldDefs ***************************************
************************************************************************************/
function TFieldDefs(Aowner) {
this.Items 	= new Array(64); /* Nombre maxi de champs = 64 */
this.Count 	= 0;
this.Parent	= Aowner;
}

TDataSet.prototype.XmlData = function() {
var XmlData = "";
var value   = new String();
XmlData = "<?xml version=\"1.0\" standalone=\"yes\"?>";
XmlData +="<DATAPACKET Version=\"2.0\">";
XmlData +="<METADATA>";
XmlData +="<FIELDS>";
for (var i=0; i < this.FieldDefs.Count; i++)
	switch (this.FieldDefs.Items[i].DataType) {
		case ftString	:
			XmlData += "<FIELD attrname=\""+this.FieldDefs.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"string\" WIDTH=\""+this.FieldDefs.Items[i].Size+"\"/>";
	    	break;
		case ftInteger	:
			XmlData += "<FIELD attrname=\""+this.FieldDefs.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"i4\"/>";
	    	break;
		case ftFloat	:
			XmlData += "<FIELD attrname=\""+this.FieldDefs.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"r8\"/>";
	    	break;
		case ftMemo	 	:
			XmlData += "<FIELD attrname=\""+this.FieldDefs.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"bin.hex\" SUBTYPE=\"Text\"/>";
	    	break;
		case ftDateTime :
			XmlData += "<FIELD attrname=\""+this.FieldDefs.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"dateTime\"/>"
	    	break;
	default : throw new Error(0,"XmlData DataType="+this.FieldDefs.Items[i].DataType+" non géré");
	}
XmlData +="</FIELDS>";
XmlData +="<PARAMS/>";
XmlData +="</METADATA>";
XmlData +="<ROWDATA>";
this.First();
while (!this.Eof) {
	XmlData +="<ROW";
// ARRET ICI : 21/12/04 Ok pour AS-CONTENTIEUX Mais gérer le format DATE pour le XML + FLOAT avec le . (point)
// + les " doivent être &quot;
// + les CrLf doivent être &#13;&#10;
// Surveiller les accents mais devrait être ok
	for (var i=0; i < this.FieldDefs.Count; i++) {
		XmlData += " "+this.FieldDefs.Items[i].FieldName.toUpperCase()+"=\"";
		switch (this.FieldDefs.Items[i].DataType) {
			case ftString	:
				value = this.FieldByName(this.FieldDefs.Items[i].FieldName,null);
				if (value==undefined) value="";
				value = value.replace(/["]/g,"&quot;");
				value = value.replace(/[/]/g,"&#047;");
				XmlData += value;
		    	break;
			case ftInteger	:
				value = this.FieldByName(this.FieldDefs.Items[i].FieldName,null);
				if (value==undefined) value="0";
				XmlData += parseInt(value);
	    		break;
			case ftFloat	:
				value = this.FieldByName(this.FieldDefs.Items[i].FieldName,null);
				if (value==undefined) value="0";
				if (value.length==0) value="0";
				value = value.replace(/[,]/g,".");
				XmlData += parseFloat(value);
		    	break;
			case ftMemo	 	:
				value = this.FieldByName(this.FieldDefs.Items[i].FieldName,null);
				if (value==undefined) value="";
				value = value.replace(/\r\n|\n|\r/g, "&#13;&#10;");
				value = value.replace(/["]/g,"&quot;");
				XmlData += value;
		    	break;
			case ftDateTime :
				value = this.FieldByName(this.FieldDefs.Items[i].FieldName,null);
				if (value==undefined) value="30/12/1899";
				XmlData += value.substring(6,10)+value.substring(3,5)+value.substring(0,2);
		    	break;
		default : throw new Error(0,"XmlData DataType="+this.FieldDefs.Items[i].DataType+" non géré");}
		XmlData += "\"";
		}
	XmlData +="/>";
	this.Next();
	}
XmlData +="</ROWDATA>";
/***********************************************************************************
** Ci après détournement du format natif de Delphi !!! pour insérer mes paramètres *
** systèmes																		   *
************************************************************************************/
XmlData +="<SYSTEM>";
XmlData +="<METADATA>";
XmlData +="<FIELDS>";
for (var i=0; i < this.Params.Count; i++)
	switch (this.Params.Items[i].DataType) {
		case ftString	:
			XmlData += "<FIELD attrname=\""+this.Params.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"string\" WIDTH=\""+this.Params.Items[i].Size+"\"/>";
	    	break;
		case ftInteger	:
			XmlData += "<FIELD attrname=\""+this.Params.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"i4\"/>";
	    	break;
		case ftFloat	:
			XmlData += "<FIELD attrname=\""+this.Params.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"r8\"/>";
	    	break;
		case ftMemo	 	:
			XmlData += "<FIELD attrname=\""+this.Params.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"bin.hex\" SUBTYPE=\"Text\"/>";
	    	break;
		case ftDateTime :
			XmlData += "<FIELD attrname=\""+this.Params.Items[i].FieldName.toUpperCase()+"\" fieldtype=\"dateTime\"/>"
	    	break;
	default : throw new Error(0,"XmlData DataType="+this.Params.Items[i].DataType+" non géré");
	}
XmlData +="</FIELDS>";
XmlData +="<PARAMS/>";
XmlData +="</METADATA>";
// ARRET ICI : 21/12/04 Ok pour AS-CONTENTIEUX Mais gérer le format DATE pour le XML + FLOAT avec le . (point)
// + les " doivent être &quot;
// + les CrLf doivent être &#13;&#10;
// Surveiller les accents mais devrait être ok
XmlData +="<ROWDATA>";
XmlData +="<ROW";
for (var i=0; i < this.Params.Count; i++) {
		XmlData += " "+this.Params.Items[i].FieldName.toUpperCase()+"=\"";
		switch (this.Params.Items[i].DataType) {
			case ftString	:
				value = this.ParamByName(this.Params.Items[i].FieldName,null);
				value = value.replace(/["]/g,"&quot;");
				value = value.replace(/[/]/g,"/");
				XmlData += value;
		    	break;
			case ftInteger	:
				XmlData += parseInt(this.ParamByName(this.Params.Items[i].FieldName,null));
	    		break;
			case ftFloat	:
				value = this.ParamByName(this.Params.Items[i].FieldName,null);
				value = value.replace(/[,]/g,".");
				XmlData += parseFloat(value);
		    	break;
			case ftMemo	 	:
				value = this.ParamByName(this.Params.Items[i].FieldName,null);
				value = value.replace(/\r\n|\n|\r/g, "&#13;&#10;");
				value = value.replace(/["]/g,"&quot;");
				XmlData += value;
		    	break;
			case ftDateTime :
				value = this.ParamByName(this.Params.Items[i].FieldName,null);
				XmlData += value.substring(6,10)+value.substring(3,5)+value.substring(0,2);
		    	break;
		default : throw new Error(0,"XmlData DataType="+this.Params.Items[i].DataType+" non géré");}
		XmlData += "\"";
		}
XmlData +="/>";
XmlData +="</ROWDATA>";
XmlData +="</SYSTEM>";
XmlData +="</DATAPACKET>";
return XmlData;
}

/***********************************************************************************
************************************** ONCANCEL ************************************
************************************************************************************/
function DataSetOnCancel(DataSet) {
if (DataSet.OnCancel==null) return;
OnCancel(DataSet);
}

/***********************************************************************************
********************************* ONSTATECHANGE ************************************
************************************************************************************/
TDataSet.prototype.DataSetOnStateChange = function() {
if (this.OnStateChange==null) return;
OnStateChange(this);
}

/***********************************************************************************
****************************** INSERT **********************************************
************************************************************************************/
TDataSet.prototype.Insert = function() {
if ((this.State==dsInsert) || (this.State==dsEdit)) {
	alert("Erreur Le Dataset est déjà en Insertion ou Edition");
	return false; }
/* Changement du State */
this.State=dsInsert;
this.DataSetOnStateChange();
this.Record[this.RecordCount] = new Array(this.FieldDefs.Count);
/* this.Pointeur sur l'enregistrement en cours */
this.Pointeur = this.RecordCount;
/* Nombre d'enregistrements */
this.RecordCount++;
return true;
}

/***********************************************************************************
********************************* CANCEL *******************************************
************************************************************************************/
TDataSet.prototype.Cancel = function() {
if ((this.State!=dsInsert) &&  (this.State!=dsEdit))
	return;
if (this.Pointeur < 0)
	return;
if (this.State==dsInsert) {
	/* Raz de l'enregistrement */
	this.Record[this.Pointeur] = null;
	/* Recalage des compteurs */
	this.Pointeur--;
	this.RecordCount--;	}
/* Evènement sur le OnCancel */
DataSetOnCancel(this);
/* Changement du State */
this.State=dsBrowse;
this.DataSetOnStateChange();
if (this.Pointeur<-1)
	throw new Error(0,"Erreur Cancel le pointeur est égal à "+this.Pointeur);
}

/***********************************************************************************
****************************** PARAMBYNAME *****************************************
************************************************************************************/
TDataSet.prototype.ParamByName = function(FieldName,Value) {
/* Recherche de l'occurence du champ */
var Occurence = -1;
for (var i=0; i < this.Params.Count; i++) {
	if (this.Params.Items[i].FieldName.toLowerCase() == FieldName.toLowerCase()) {
		Occurence = i;
		break; }}
/* Renvoi de la valeur du champ */
if (Occurence == -1)
	throw new Error(0,"Erreur ParamdByName FieldName "+FieldName+" non trouvé");

if (this.RecordParam [0]==null) {
	this.RecordParam[0] = new Array(this.Params.Count);
	}
if (Value!=null) 
	{
	if (typeof(Value) == "boolean") {
		this.RecordParam[0][Occurence] = "False";
		if (Value)
			this.RecordParam[0][Occurence] = "True";
		}
	else 
		this.RecordParam[0][Occurence] = Value;
	}
if (this.RecordParam[0] == null) 
	return;
return this.RecordParam[0][Occurence];
}

/***********************************************************************************
****************************** FIELDBYNAME *****************************************
************************************************************************************/
TDataSet.prototype.FieldByName = function(FieldName,Value) {
if ((this.State!=dsInsert) &&  (this.State!=dsEdit) && (Value!=null))
	throw new Error(0,"Erreur Le DataSet n'est pas en mode Edition ou Insertion");
/* Recherche de l'occurence du champ */
var Occurence = -1;
for (var i=0; i < this.FieldDefs.Count; i++) {
	if (this.FieldDefs.Items[i].FieldName.toLowerCase() == FieldName.toLowerCase()) {
		Occurence = i;
		break; }}
/* Renvoi de la valeur du champ */
if (Occurence == -1)
	throw new Error(0,"Erreur FieldByName: FieldName "+FieldName+" non trouvé");
if (Value!=null) 
	{
	if (typeof(Value) == "boolean") {
		this.Record[this.Pointeur][Occurence] = "False";
		if (Value)
			this.Record[this.Pointeur][Occurence] = "True";
		}
	else 
		this.Record[this.Pointeur][Occurence] = Value;
	}
if (this.Record[this.Pointeur] == null) 
	return;
return this.Record[this.Pointeur][Occurence];
}

/***********************************************************************************
******************************** FINDFIELD *****************************************
************************************************************************************/
TDataSet.prototype.FindField = function(FieldName) {
/* Recherche de l'occurence du champ */
var Occurence = -1;
for (var i=0; i < this.FieldDefs.Count; i++) {
	if (this.FieldDefs.Items[i].FieldName.toLowerCase() == FieldName.toLowerCase()) {
		Occurence = i;
		return true; }}
return false;
}

/***********************************************************************************
********************************* DELETE *******************************************
************************************************************************************/
TDataSet.prototype.Delete = function () {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est en en mode Edition ou Insertion");
if (this.Pointeur < 0)
	return;
/* Raz de l'enregistrement */
this.Record[this.Pointeur] = null;
/* Remontage des lignes */
for (var i=this.Pointeur+1; i < this.RecordCount; i++) {
	this.Record[i-1] = this.Record[i]; }
/* Recalage des compteurs */
this.Pointeur--;
this.RecordCount--;
if (this.Pointeur<-1)
	throw new Error(0,"Erreur Cancel le pointeur est égal à "+this.Pointeur);
if (this.Pointeur==-1) this.Eof = true;
this.DataSetOnStateChange();
}

function trim(Chaine) { 
return Chaine.replace(/(^\s*)|(\s*$)/g,''); 
} 

function ExtractFieldName(FieldNames, Pos) {
var Retour = new Array(0,"");
var i = Pos;
while ((i <= FieldNames.length) && (FieldNames.substr(i-1,1) != ";")) {i++};
Retour[1] = trim( FieldNames.substr(Pos-1, i - Pos ) );
if ((i <= FieldNames.length) && (FieldNames.substr(i-1,1) == ";")) i++;
Retour[0] = i;
return Retour;
}

function SortUnicite(Enreg1,Enreg2) {
if (Enreg1 == Enreg2)
	throw new Error(0,"Vous tentez d'ajouter un enregistrement en double");
return 1;
}

function IsUnicite(DataSet) {
var KeyFields 	= new Array(64); 	// Nombre maxi de champs = 64
var Record    	= new Array(1024);	// Nombre maxi d'enregistrements = 1024
var i			= 0;
var Pos 		= 1;
var Retour 		= new Array(0,"");
var FieldNames 	= new String(DataSet.PrimaryKey);
var BookMark	= DataSet.Pointeur+1;
var NbField		= 0;
/* Remplissage d'un tableau avec le nom des champs composants la clé */
while (Pos <= FieldNames.length) {
	Retour 	= ExtractFieldName(FieldNames, Pos);
	Pos		= Retour[0];
	KeyFields[NbField] = Retour[1];
	NbField++;
	}
/* Ajout dans un tableau la concaténation des valeurs de chaque enregistrement et chaque champ de clés */
DataSet.First();
while (!DataSet.Eof) {
	Record[DataSet.RecNo()-1] = "";
	for (i=0; i < NbField; i++)
		Record[DataSet.RecNo()-1] += DataSet.FieldByName(KeyFields[i],null);
	DataSet.Next();
	}
DataSet.GotoRecord(BookMark);
Record.sort(SortUnicite);
}

function IsNotEmpty(DataSet) {
for (var i=0; i < DataSet.FieldDefs.Count; i++)
	if ( (DataSet.FieldDefs.Items[i].NotEmpty == true) 
	&& ( (DataSet.FieldByName(DataSet.FieldDefs.Items[i].FieldName,null)==undefined)
	|| 	 (DataSet.FieldByName(DataSet.FieldDefs.Items[i].FieldName,null)=="")))
		throw new Error(0,"La zone \""+DataSet.FieldDefs.Items[i].DisplayLabel+"\" doit être renseignée");
}

/***********************************************************************************
*********************************** POST *******************************************
************************************************************************************/
TDataSet.prototype.Post = function() {
var i;
var Save_State = this.State;
try {
	if ((this.State!=dsInsert) &&  (this.State!=dsEdit))
		throw new Error(0,"Erreur Le DataSet n'est pas en mode Edition ou Insertion");
	this.State=dsBrowse; 
	try {
		IsUnicite(this);
		IsNotEmpty(this);
		this.Eof = false;
		this.DataSetOnStateChange();
		return true;
		}
	catch (err) {
		alert("Attention: "+err.message);
		this.State = Save_State;
		return false;
		}
	}
catch (error) {
	alert(error.message); }
}

/***********************************************************************************
*********************************** EDIT *******************************************
************************************************************************************/
TDataSet.prototype.Edit = function() {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est déjà en mode Edition ou Insertion");
if (this.Pointeur < 0) {
	this.Eof = true;
	return; }
this.State=dsEdit;
this.DataSetOnStateChange();
}

/***********************************************************************************
*********************************** NEXT *******************************************
************************************************************************************/
TDataSet.prototype.Next = function() {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est déjà en mode Edition ou Insertion");
if (this.Pointeur+1 >= this.RecordCount) {
	this.Eof = true;
	return; }
this.Pointeur++;
}

/***********************************************************************************
********************************** PRIOR *******************************************
************************************************************************************/
TDataSet.prototype.Prior = function() {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est déjà en mode Edition ou Insertion");
try {
	if (this.Pointeur < 1)
		return;
	this.Pointeur--; }
finally {
	if (this.Pointeur+1 >= this.RecordCount)
		this.Eof = true; }
}

/***********************************************************************************
********************************** RECNO *******************************************
************************************************************************************/
TDataSet.prototype.RecNo = function() {
return this.Pointeur+1;
}

/***********************************************************************************
********************************** FIRST *******************************************
************************************************************************************/
TDataSet.prototype.First = function() {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est déjà en mode Edition ou Insertion");
if (this.Pointeur < 0)
	return;
this.Pointeur = 0;
}

/***********************************************************************************
*********************************** EMPTYTABLE *************************************
************************************************************************************/
TDataSet.prototype.EmptyTable = function() {
for (var i=0; i < this.RecordCount; i++)
	this.Record[i] = null;
this.RecordCount = 0;
this.Pointeur = -1;
/* Fin de fichier */
this.Eof = true;
/* Changement du State */
this.State=dsBrowse;
this.DataSetOnStateChange();
}

/***********************************************************************************
**************************** GotoRecord ********************************************
************************************************************************************/
TDataSet.prototype.GotoRecord = function(PosRecord) {
if ((this.State==dsInsert) || (this.State==dsEdit))
	throw new Error(0,"Erreur Le DataSet est déjà en mode Edition ou Insertion");
if (this.Pointeur < 0)
	return;
if ((PosRecord<0) || (PosRecord>this.RecordCount))
	return;
this.Pointeur = PosRecord-1;
this.Eof = false;
}

/***********************************************************************************
***************************** FormToFields *************************************
************************************************************************************/
TDataSet.prototype.FormToFields = function(FormName) {
if (FormName=="") return;
var Formulaire = document.getElementById(FormName);
if (Formulaire==null) return;
for (var i=0; i<Formulaire.length;i++) {
	if (this.FindField(Formulaire[i].name)) 
		{
		/* Case case à cocher et radio */
		if ((Formulaire[i].type=="checkbox") || (Formulaire[i].type=="radio"))
			{if (Formulaire[i].checked) this.FieldByName(Formulaire[i].name,Formulaire[i].value);}
		/* Autres cas y compris les Combos et les boîtes listes */
		else this.FieldByName(Formulaire[i].name,Formulaire[i].value);
		}
	}	
}