//#16.0.1.0 WDSQL.js
//VersionVI: 30A160057k
// Le seul support technique disponible pour cette librairie est
// accessible a travers le service "Assistance Directe".

//////////////////////////////////////////////////////////////////////////
// Gestion des requetes

// Classe de base des requetes
function WDSQLRequete(sNomRequete, sSQL, fCallback)
{
	// Si on est pas dans l'init d'un protoype
	if (sNomRequete)
	{
		this.m_sNomRequete = sNomRequete;
		this.m_sSQL = sSQL;
		this.m_fCallback = fCallback;

		// Derniere erreur (pour SQL.Erreur et SQL.MesErreur)
		// On distingue l'erreur absente de l'erreur 0
		this.m_sErreurN = "00000";
		this.m_sErreur = "";
		// ID unique de la requete (pour SQL.Requete)
		this.m_nID = WDSQLRequete.prototype.ms_nIDSuivant++;

		// Description des rubriques (declarees dans l'ordre avec un objet de type
		this.m_tabRubriques = [];
	}
};

WDSQLRequete.prototype.ms_nIDSuivant = 0;

// Nom de la requete
WDSQLRequete.prototype.sGetNomRequete = function sGetNomRequete()
{
	return this.m_sNomRequete;
};

// Derniere erreur (pour SQL.Erreur et SQL.MesErreur)
WDSQLRequete.prototype.nGetErreur = function nGetErreur()
{
	// On distingue l'erreur absente de l'erreur 0
	return this.m_sErreurN;
};
WDSQLRequete.prototype.sGetErreur = function sGetErreur()
{
	return this.m_sErreur;
};

// Nombre de rubriques (pour SQL.NbCol)
WDSQLRequete.prototype.nGetNbRubriques = function nGetNbRubriques()
{
	return this.m_tabRubriques.length;
};

// ID de la requete (pour SQL.Requete)
WDSQLRequete.prototype.nGetID = function nGetID()
{
	return this.m_nID;
};

// Retourne le tableau des titres des rubriques (SQL.TitreCol)
WDSQLRequete.prototype.tabGetTitreRubriques = function tabGetTitreRubriques()
{
	var tabRubriques = this.m_tabRubriques;
	var i;
	var nLimiteI = tabRubriques.length;
	var tabTitreRubriques = new Array(nLimiteI);
	for (i = 0; i < nLimiteI; i++)
	{
		tabTitreRubriques[i] = tabRubriques[i].m_sNomRubrique;
	}
	return tabTitreRubriques;
};

// Ouvre (execute) la requete
WDSQLRequete.prototype.vbOuvre = function vbOuvre(oConnexion)
{
	// => Rien de non specifique
	return false;
};

// Ferme la requete
WDSQLRequete.prototype.vFerme = function vFerme()
{
	// => Rien de non specifique
};

// Avance a l'enregistrement suivant
WDSQLRequete.prototype.vnAvance = function vnAvance()
{
	// => Rien de non specifique
	return 0;
};

// Recupere le contenu de la rubrique pour l'enregistrement courant
WDSQLRequete.prototype.sGetRubriqueValeur = function sGetRubriqueValeur(nRubrique)
{
	// Si l'indice est valide
	if ((0 <= nRubrique) && (this.m_tabRubriques.length > nRubrique))
	{
		// Rebond sur la methode specifique mais avec l'acces par nom ou par indice (selon la methode specifique de la source)
		return this._vsGetRubriqueValeur(nRubrique, this.m_tabRubriques[nRubrique].m_sNomRubrique);
	}
	// Erreur
	return "";
};

// Recupere le contenu de la rubrique pour l'enregistrement courant
WDSQLRequete.prototype._vsGetRubriqueValeur = function _vsGetRubriqueValeur(nRubrique, sNomRubrique)
{
	// => Specifique a la base de donnee
	return "";
};

// Trouve les infos sur les rubriques
WDSQLRequete.prototype.sGetRubriques = function sGetRubriques(bDetails)
{
	var tabRubriques = this.m_tabRubriques;
	var i;
	var nLimiteI = tabRubriques.length;
	var tabResultat = [];
	for (i = 0; i < nLimiteI; i++)
	{
		var sDetails = tabRubriques[i].m_sNomRubrique;
		if (bDetails)
		{
			// Presente le texte comme du WCHAR, les nombres comme des doubles et ne donne pas de taille
			sDetails += tabRubriques[i].m_bTexte ? "\tT\t0\t" : "\tN\t16\t"
		}
		tabResultat.push(sDetails);
	}
	return tabResultat.join("\r\n");
};

// Declare une rubrique
WDSQLRequete.prototype._RubriqueDeclare = function _RubriqueDeclare(sNomRubrique, bTexte)
{
	this.m_tabRubriques.push({ m_sNomRubrique : sNomRubrique, m_bTexte : bTexte});
};

// Requete Web SQL Database
function WDSQLRequeteWebSQL(sNomRequete, sSQL, fCallback)
{
	// Si on est pas dans l'init d'un protoype
	if (sNomRequete)
	{
		// Appel le constructeur de la classe de base
		WDSQLRequete.prototype.constructor.apply(this, arguments);

		// Callback pour l'execution de la requete
		var oThis = this;
		this.m_fCallbackTransaction = function(pclTransaction) { return oThis.__OnTransaction(pclTransaction); };
		this.m_fCallbackExecute = function(pclTransaction, pclResulSet) { return oThis.__OnExecute(pclTransaction, pclResulSet); };
		this.m_fCallbackTransactionErreur = function(pclErreur) { return oThis.__OnErreur(pclErreur); };
		this.m_fCallbackExecuteErreur = function(pclTransaction, pclErreur) { return oThis.__OnErreur(pclErreur); };

		// Resultat de la requete (structure specifique au format)
		this.m_pclResulSet = null;
		// Sans enregistrement courant
		this.m_nEnregistrement = -1;
	}
};

// Declare l'heritage
WDSQLRequeteWebSQL.prototype = new WDSQLRequete();
// Surcharge le constructeur qui a ete efface
WDSQLRequeteWebSQL.prototype.constructor = WDSQLRequeteWebSQL;

// Ouvre (execute) la requete
WDSQLRequeteWebSQL.prototype.vbOuvre = function vbOuvre(oConnexion)
{
//	// Appel de la classe de base
//	WDSQLRequete.prototype.vbOuvre.apply(this, arguments);

	oConnexion.m_oDatabase.transaction(this.m_fCallbackTransaction, this.m_fCallbackTransactionErreur);

	return true;
};

// Ferme la requete
WDSQLRequeteWebSQL.prototype.vFerme = function vFerme()
{
//	// Appel de la classe de base
//	WDSQLRequete.prototype.vFerme.apply(this, arguments);

	// Libere le resultat
	this.m_pclResulSet = null;
	delete this.m_pclResulSet;
};

// Avance a l'enregistrement suivant
WDSQLRequeteWebSQL.prototype.vnAvance = function vnAvance()
{
	// Appel de la classe de base
	var nRes = WDSQLRequete.prototype.vnAvance.apply(this, arguments);
	if (-1 == nRes)
	{
		return nRes;
	}

	// Si la requete est valide
	if (this.__bEstResultSetValide())
	{
		// Si le parcours n'est pas commence
		if (-1 == this.m_nEnregistrement)
		{
			// On le commence
			this.m_nEnregistrement = 0;
		}
		else
		{
			// passe a l'enregistrement suivant
			this.m_nEnregistrement++;
		}
		// Le resultat est selon la validite de la position
		return this.__bEstPositionValide() ? 0 : -1;
	}
	// Echec
	return -1;
};

// Recupere le contenu de la rubrique pour l'enregistrement courant
WDSQLRequeteWebSQL.prototype._vsGetRubriqueValeur = function _vsGetRubriqueValeur(nRubrique, sNomRubrique)
{
	// Si la requete et la position sont valides
	if (this.__bEstResultSetValide() && this.__bEstPositionValide())
	{
		return this.m_pclResulSet.rows.item(this.m_nEnregistrement)[sNomRubrique];
	}
	// Echec
	return "";
};

// Indique si la requete est valide
WDSQLRequeteWebSQL.prototype.__bEstResultSetValide = function __bEstResultSetValide()
{
	// Si on a des donnees
	return (this.m_pclResulSet && this.m_pclResulSet.rows && this.m_pclResulSet.rows.length);
};

// Indique si la position est valide
WDSQLRequeteWebSQL.prototype.__bEstPositionValide = function __bEstPositionValide()
{
	return (0 <= this.m_nEnregistrement) && (this.m_pclResulSet.rows.length > this.m_nEnregistrement);
};

// Appel pour executer la requete
WDSQLRequeteWebSQL.prototype.__OnTransaction = function __OnTransaction(pclTransaction)
{
	// Execute la requete
	pclTransaction.executeSql(this.m_sSQL, null, this.m_fCallbackExecute, this.m_fCallbackExecuteErreur);
};

// Appel sur le resultat de la requete
WDSQLRequeteWebSQL.prototype.__OnExecute = function __OnExecute(pclTransaction, pclResulSet)
{
	// Recupere le resultat
	this.m_pclResulSet = pclResulSet;
	// Et reste en dehors (il faut faire un SQLAvance)
	this.m_nEnregistrement = -1;

	// Et declare les rubriques (si on un enregistrement)
	if (this.__bEstResultSetValide())
	{
		var oEnregistrement = this.m_pclResulSet.rows.item(0);
		var sRubrique;
		for (var sRubrique in oEnregistrement)
		{
			var bTexte = true;
			switch ((typeof (oEnregistrement[sRubrique])).toLowerCase())
			{
			case "boolean":
			case "number":
				bTexte = false;
			}
			this._RubriqueDeclare(sRubrique, bTexte);
		}
	}

	// Appel la callback du client
	this.__AppelCallbackClient();
};

// Callback en cas d'erreur
WDSQLRequeteWebSQL.prototype.__OnErreur = function __OnErreur(pclErreur)
{
	// Remplie les valeurs d'erreurs
	this.m_sErreurN = pclErreur.code + "";
	this.m_sErreur = pclErreur.message;

	// Appel de la callback du client
	this.__AppelCallbackClient();
};

// Appel de la callback du client en fixant la requete en cours correctement
WDSQLRequeteWebSQL.prototype.__AppelCallbackClient = function __AppelCallbackClient()
{
	clWDSQLManagerMain.AppelCallbackClient(this, this.m_fCallback);
};

//////////////////////////////////////////////////////////////////////////
// Gestion des connexions

// Classe de base des connexions
function WDSQLConnexion (bPasInitPrototype)
{
	// Si on est pas dans l'init d'un protoype
	if (bPasInitPrototype)
	{
		// Tableau des requetes
		this.m_tabRequetes = [];
	}
};

// Database de la connexion (pour SQL.Base)
WDSQLConnexion.prototype.sGetDatabase = function sGetDatabase()
{
	return this.m_sDatabase;
};

// Ouvre la connexion
WDSQLConnexion.prototype.vbConnecte = function vbConnecte(sSource, sUtilisateur, sMotPasse, sDatabase)
{
	// Sauve la base de donnee (pour SQL.Base)
	this.m_sDatabase = sDatabase;

	return true;
};

// Ferme la connexion
WDSQLConnexion.prototype.vDeconnecte = function vDeconnecte()
{
	// Ferme toutes les requetes
	this.__RequeteFermeTout();
};

// Ouvre une requete
WDSQLConnexion.prototype.pclRequeteOuvre = function pclRequeteOuvre(sSQL, sNomRequete, fCallback)
{
	// Cree la requete
	var oRequete = this._vpclCreeRequete(sNomRequete, sSQL, fCallback);
	if (oRequete)
	{
		// Et l'execute
		if (oRequete.vbOuvre(this))
		{
			this.m_tabRequetes.push(oRequete);
			return oRequete;
		}
	}
	// Erreur/Echec
	return null;
};

// Cree une requete
WDSQLConnexion.prototype._vpclCreeRequete = function _vpclCreeRequete(sNomRequete, sSQL, fCallback)
{
	// => Specifique a la base de donnee
	return null;
};

// Ferme toutes les requetes
WDSQLConnexion.prototype.__RequeteFermeTout = function __RequeteFermeTout()
{
	// La fermeture des requetes modifie le tableau donc on ferme les requetes en utilisant toujours le premier element et pas un parcourt
	while (0 < this.m_tabRequetes.length)
	{
		this.__RequeteFerme(0);
	}
};

// Ferme une requete manipule par son pointeur
WDSQLConnexion.prototype.RequeteFerme = function RequeteFerme(oRequete)
{
	// Recherche la requete a fermer
	for (var nRequete in this.m_tabRequetes)
	{
		if (this.m_tabRequetes[nRequete] == oRequete)
		{
			this.__RequeteFerme(nRequete);
			return;
		}
	}
};

// Ferme une requete manipule par indice
WDSQLConnexion.prototype.__RequeteFerme = function __RequeteFerme(nRequete)
{
	// Trouve la requete
	var oRequete = this.m_tabRequetes[nRequete];

	// Supprime la requete du tableau
	this.m_tabRequetes[nRequete] = null;
	this.m_tabRequetes.splice(nRequete, 1);
	// Supprime la requete dans le tableau general
	clWDSQLManagerMain.RequeteFerme(oRequete.sGetNomRequete());

	// Ferme la requete
	oRequete.vFerme();
	oRequete = null;
};

// Connexion Web SQL Database
function WDSQLConnexionWebSQL(bPasInitPrototype)
{
	// Si on est pas dans l'init d'un protoype
	if (bPasInitPrototype)
	{
		// Appel le constructeur de la classe de base
		WDSQLConnexion.prototype.constructor.apply(this, arguments);

		// Pas de base de donne
		this.m_oDatabase = null;
	}
};

// Declare l'heritage
WDSQLConnexionWebSQL.prototype = new WDSQLConnexion();
// Surcharge le constructeur qui a ete efface
WDSQLConnexionWebSQL.prototype.constructor = WDSQLConnexionWebSQL;

// Ouvre la connexion
WDSQLConnexionWebSQL.prototype.vbConnecte = function vbConnecte(sSource, sUtilisateur, sMotPasse, sDatabase)
{
	// Appel de la classe de base
	var bRes = WDSQLConnexion.prototype.vbConnecte.apply(this, arguments);
	if (!bRes)
	{
		return bRes;
	}

	// Calcule le nom de la source/base de donnee
	var sNomDatabase = sSource + (((0 < sSource.length) && (0 < sDatabase.length)) ? "." : "") + sDatabase;
// Ouvre la connexion
	this.m_oDatabase = window.openDatabase(sNomDatabase, "", sNomDatabase, 1024 * 1024);

	return (null != this.m_oDatabase);
};

// Ferme la connexion
WDSQLConnexionWebSQL.prototype.vDeconnecte = function vDeconnecte()
{
	// Appel de la classe de base
	WDSQLConnexion.prototype.vDeconnecte.apply(this, arguments);

	// Ferme la connexion
	this.m_oDatabase = null;
};

// Cree une requete
WDSQLConnexionWebSQL.prototype._vpclCreeRequete = function _vpclCreeRequete(sNomRequete, sSQL, fCallback)
{
	return new WDSQLRequeteWebSQL(sNomRequete, sSQL, fCallback);
};

//////////////////////////////////////////////////////////////////////////
// Manager

// Gestion des connexions et des requetes (point d'entree general)
function WDSQLManager ()
{
	// Tableau des connexions
	this.m_tabConnexions = [];
	// Tableau des requetes (indexe par nom) : c'est un tableau d'objet avec : connexion et la requete
	this.m_tabRequetes = [];
	// Connexion courante (il n'y a pas de requete courante)
	this.m_nConnexionCourante = -1;
	// Requete courante (c'est son nom car m_tabRequetes est indexe par nom)
	this.m_sRequeteCourante = "";
};

// Connexion a une source de donnees
WDSQLManager.prototype.__oCreeConnexion = function __oCreeConnexion(sType)
{
	switch (sType.toLowerCase())
	{
	case "web sql database":
	case "":
		// Seulement si le navigateur le supporte
		return window.openDatabase ? new WDSQLConnexionWebSQL(true) : null;
	default:
		return null;
	}
};

// Ferme une requete
WDSQLManager.prototype.RequeteFerme = function RequeteFerme(sNomRequete)
{
	if (this.m_tabRequetes[sNomRequete])
	{
		this.m_tabRequetes[sNomRequete] = null;
		delete this.m_tabRequetes[sNomRequete];
	}

	// Si c'est la requete courante
	if (sNomRequete == this.m_sRequeteCourante)
	{
		this.m_sRequeteCourante = "";
	}
};

// Retourne l'indice d'une connexion donnee
WDSQLManager.prototype.__nGetConnexion = function __nGetConnexion(oConnexion)
{
	var i;
	var nLimiteI = this.m_tabConnexions.length;
	for (i = 0; i < nLimiteI; i++)
	{
		if (this.m_tabConnexions[i] == oConnexion)
		{
			return i;
		}
	}
	// Non trouve (impossible normalement)
	return -1;
};

// Trouve la requete courante
WDSQLManager.prototype.__oGetRequeteCourante = function __oGetRequeteCourante()
{
	// Si on en a une
	if (0 < this.m_sRequeteCourante.length)
	{
		// Retourne undefined en cas d'erreur
		return this.m_tabRequetes[this.m_sRequeteCourante];
	}
	// Erreur
	return null;
};

// Appel la callback du client sur une requete
WDSQLManager.prototype.AppelCallbackClient = function AppelCallbackClient(oRequete, fCallback)
{
	// Sauve la requete courante
	var sRequeteCourante = this.m_sRequeteCourante;

	// Force la requete courante (pour avoir les SQL.Xxx corrects)
	this.m_sRequeteCourante = oRequete.sGetNomRequete();

	// Appel de la callback
	fCallback(this.m_sRequeteCourante);

	// Retablie la requete courante
	this.m_sRequeteCourante = sRequeteCourante;
};

// Retourne un objet global
var clWDSQLManagerMain = new WDSQLManager();

//////////////////////////////////////////////////////////////////////////
// Interface pour le WL

// Connexion a une source de donnees
WDSQLManager.prototype.SQLConnecte = function SQLConnecte(sSource, sUtilisateur, sMotPasse, sDatabase, sType)
{
	// Gestion des parametres optionnels
	if (sDatabase === undefined)
	{
		sDatabase = "";
	}
	if (sType === undefined)
	{
		sType = "web sql database";
	}

	// Cree la nouvelle connexion
	var oConnexion = this.__oCreeConnexion(sType);
	if (oConnexion)
	{
		// Et l'ouvre
		if (oConnexion.vbConnecte(sSource, sUtilisateur, sMotPasse, sDatabase))
		{
			// Et la place dans le tableau des connexions et comme connexion courante
			this.m_nConnexionCourante = this.m_tabConnexions.length;
			this.m_tabConnexions.push(oConnexion);
			// + 1 : Indice C/JS => WL
			return this.m_nConnexionCourante + 1;
		}
	}

	// erreur (type invalide ou erreur de connexion)
	// Retourne 0 par compat avec le WL serveur
	return 0;
};

// Deconnexion d'une source de donnees
WDSQLManager.prototype.SQLDeconnecte = function SQLDeconnecte()
{
	// Ferme la connexion courante si elle existe
	if (-1 != this.m_nConnexionCourante)
	{
		var oConnexion = this.m_tabConnexions[this.m_nConnexionCourante];
		// Ferme la connexion (inclus ses requetes)
		oConnexion.vDeconnecte();

		// La supprime
		this.m_tabConnexions[this.m_nConnexionCourante] = null;
		this.m_tabConnexions.splice(this.m_nConnexionCourante, 1);
		// Prend la connexion precedent (si elle existe) (avec un algo compatible 5.5)
		if (0 < this.m_nConnexionCourante)
		{
			this.m_nConnexionCourante--;
		}
		else if (0 < this.m_tabConnexions.length)
		{
			this.m_nConnexionCourante = 0;
		}
		else
		{
			this.m_nConnexionCourante = -1;
		}

		oConnexion = null;
	}

	// SQLDeconnecte est documente comme ne renvoyant rien mais en fait la fonction retourne (par compat 5.5)
	// un entier (declare en 16bits). Sauf que cette valeur est toujours 0.
	return 0;
};

// Change la connexion active
WDSQLManager.prototype.SQLChangeConnexion = function SQLChangeConnexion(nConnexion)
{
	// - 1 : Indice WL => C/JS
	nConnexion = nConnexion - 1;

	// Si la connexion est valide
	if ((0 <= nConnexion) && (this.m_tabConnexions.length > nConnexion))
	{
		this.m_nConnexionCourante = nConnexion;
		return true;
	}
	// Valeur invalide : echec
	return false;
};

// Execution d'une requete
WDSQLManager.prototype.SQLExec = function SQLExec(sSQL, sNomRequete, fCallback)
{
	// Ferme une possible requete deja existante avec ce nom
	this.SQLFerme(sNomRequete);

	// Execution de la requete dans la connexion courante
	if (-1 != this.m_nConnexionCourante)
	{
		// La fonction retourne l'indice de la requete dans la connexion
		var oConnexion = this.m_tabConnexions[this.m_nConnexionCourante];
		var oRequete = oConnexion.pclRequeteOuvre(sSQL, sNomRequete, fCallback);
		if (oRequete)
		{
			this.m_tabRequetes[sNomRequete] = { m_oConnexion: oConnexion, m_oRequete: oRequete };
			return true;
		}
	}

	// Pas de connexion courante ou echec de l'execution
	return false;
};

// Fermeture d'une requete
WDSQLManager.prototype.SQLFerme = function SQLFerme(sNomRequete)
{
	// Uniquement si une requete de ce nom existe
	var oRequete = this.m_tabRequetes[sNomRequete];
	if (oRequete)
	{
		// La ferme via sa connexion (supprime la requete de this.m_tabRequetes en interne
		oRequete.m_oConnexion.RequeteFerme(oRequete.m_oRequete);
	}
};

// Avance sur l'enregistrement suivant
WDSQLManager.prototype.SQLAvance = function SQLAvance(sNomRequete)
{
	// Uniquement si une requete de ce nom existe
	var oRequete = this.m_tabRequetes[sNomRequete];
	if (oRequete)
	{
		return oRequete.m_oRequete.vnAvance();
	}
	return -1;
};

// Recupere le contenu de la rubrique pour l'enregistrement courant
WDSQLManager.prototype.SQLLitCol = function SQLLitCol(sNomRequete, nRubrique)
{
	// Uniquement si une requete de ce nom existe
	var oRequete = this.m_tabRequetes[sNomRequete];
	if (oRequete)
	{
		// - 1 : indice WL vers indice C/JS
		return oRequete.m_oRequete.sGetRubriqueValeur(nRubrique - 1);
	}
	return "";
};

// Informations sur les rubriques
WDSQLManager.prototype.SQLColonne = function SQLColonne(sNomRequete, bDetails)
{
	// Gestion des parametres optionnels
	if (bDetails === undefined)
	{
		bDetails = true;
	}

	// Uniquement si une requete de ce nom existe
	var oRequete = this.m_tabRequetes[sNomRequete];
	if (oRequete)
	{
		return oRequete.m_oRequete.sGetRubriques(bDetails);
	}
	return "";
};

// Charge les variables composantes SQL.Xxx
WDSQLManager.prototype.SQLInfoGene = function SQLInfoGene(sNomRequete)
{
	// Fixe la requete courante (si elle existe)
	if (this.SQLReqExiste(sNomRequete))
	{
		this.m_sRequeteCourante = sNomRequete;
	}
};

// Indique si la requete existe
WDSQLManager.prototype.SQLReqExiste = function SQLReqExiste(sNomRequete)
{
	return this.m_tabRequetes[sNomRequete] ? true : false;
};

// Lecture des variables composantes pour les requetes
WDSQLManager.prototype.GetVariableRequete = function GetVariableRequete(nVariable)
{
	// Trouve la requete en cours (retourne l'objet de description de la requete : Requete + connexion
	var oRequete = this.__oGetRequeteCourante();
	if (oRequete)
	{
		// [0, 6] = SQL.Xxx sur les requetes
		switch (nVariable)
		{
		case 0:
			return oRequete.m_oConnexion.sGetDatabase();
		case 1:		// SQL.Connexion
			return this.__nGetConnexion(oRequete.m_oConnexion);
		case 2:		// SQL.Erreur
			return oRequete.m_oRequete.nGetErreur();
		case 3:		// SQL.MesErreur
			return oRequete.m_oRequete.sGetErreur();
		case 4:		// SQL.NbCol
			return oRequete.m_oRequete.nGetNbRubriques();
		case 5:		// SQL.Requete
			return oRequete.m_oRequete.nGetID();
		case 6:		// SQL.TitreCol
			return oRequete.m_oRequete.tabGetTitreRubriques();
		default:
			break;
		}
	}
	// Erreur
	return 0;
};
