﻿(function($)
{
	$.fn.Loginify = function (options)
	{
		var i;							//	Loop variable
		var j;
		var objet =
		{
			RGY :						//	For tri-stats fields
			{
				fields : [],			//	Array of concerned fields
				Temp : [],
				Pictures : ["RedLight.png", "YellowLight.png", "GreenLight.png"],			//	Names of Pictures
				Password : 0,			//	Store id of password field in the board
				
				ExecuteRules : function ()
				{
					var i;
					for (i=0; i < objet.RGY.fields.length; i++)
					{
						if (objet.RGY.fields[i].Step == objet.Step)
						{
							if ($(objet.RGY.fields[i].HTML).val() != "")
							{	objet.RGY.fields[i].IsValid = true;	}
						}
					}
				},
				EventManager : function (element)
				{
					$(element.HTML).focusin (function ()
					{
						objet.RGY.EnterStat (element);
					});
					$(element.HTML).focusout (function ()
					{
						objet.ErasePic (element.Pictures);
					});
					$(element.HTML).keydown (function ()
					{
						objet.ErasePic (element.Pictures);
						objet.RGY.EnterStat (element);
					});
					$(element.HTML).keyup (function ()
					{
						objet.ErasePic (element.Pictures);
						objet.RGY.EnterStat (element);
					});
				},
				EnterStat : function (element)//
				{
					var pictures = element.Pictures;
					var length = $(element.HTML).val().length;
					if (!length)
					{	$(pictures[0]).show();	}
					else
					{
						if (length < options.YLength)
						{	$(pictures[1]).show();	}
						else
						{	$(pictures[2]).show();	}
					}
				}
			},
			RG :						//	For two-stats fields
			{
				fields : [],
				Temp : [],
				Pictures : ["RedLight.png", "GreenLight.png"],
				Password : 0,			//	Store id of the password verificator
				
				ExecuteRules : function ()
				{
					$(objet.RG.fields).each (function ()
					{
						if (this.Step == objet.Step)
						{
							if ($(this.HTML).val() != $(this.HTML).parent().prev().children('input').val() || $(this.HTML).val() == "")
							{	this.IsValid = false;	}
							else
							{	this.IsValid = true;	}
						}
					});
				},
				EventManager : function (element)
				{
					$(element.HTML).focusin (function ()
					{	objet.RG.EnterStat (element);	});
					
					$(element.HTML).focusout (function ()
					{	objet.ErasePic (element.Pictures);	});
					
					$(element.HTML).keydown (function ()
					{
						objet.ErasePic (element.Pictures);
						objet.RG.EnterStat (element);
					});
					$(element.HTML).keyup (function ()
					{
						objet.ErasePic (element.Pictures);
						objet.RG.EnterStat (element);
					});
				},
				EnterStat : function (element)
				{
					if ($(element.HTML).val() != $(element.HTML).parent().prev().children('input').val() || $(element.HTML).val() == "")
					{	$(element.Pictures[0]).show();	}
					else
					{	$(element.Pictures[1]).show();	}
				}
			},
			ND :
			{
				fields : [],			//	For not defined stat fields
				Temp : [],
				
				ExecuteRules : function ()
				{
					$(objet.ND.fields).each (function ()
					{
						if (this.Step == objet.Step)
						{
							this.IsValid = ($(this.HTML).val() == "")?false:true;
							if (this.Type == objet.Types.Mail)
							{	this.IsValid = objet.ND.MailInput($(this.HTML).val());	}
						}
					});
				},
				EventManager : function (element)
				{
					$(element.HTML).keydown (function (event)
					{
						if (element.Type == objet.Types.Date)
						{
							if (!objet.ND.DateInput (event.keyCode))
							{	event.preventDefault();	}
						}
					});
					$(element.HTML).keyup (function (event)
					{
						if (element.Type == objet.Types.Date)
						{
							if (!objet.ND.DateInput (event.keyCode))
							{	event.preventDefault();	}
						}
					});
				},
				DateInput : function (keyCode)
				{
					if ((keyCode < 48 || keyCode > 57) && 
						keyCode != 190	&&	keyCode != 110 &&	//	. && num pad .
						keyCode != 8	&&	//	backspace
						keyCode != 13	&&	//	enter
						keyCode != 46	&&	//	Del
						(keyCode < 37 || keyCode > 40) &&
						(keyCode < 96 || keyCode > 105))
					{	return false;	}
					return true;
				},
				MailInput : function (mailString)
				{
					var RegExpr = /^[a-z0-9.-_]+@[a-z0-9]{2,}[.][a-z]{2,3}$/;
					var Result = RegExpr.exec(mailString);
					return (!Result)?false:true;
				}
			},
			Buttons :					//	For input button control
			{
				standard : [],
				Temp : [],
				reset : false,
				submit : false,
				
				EventManager : function (element)
				{
					$(element.HTML).click (function()
					{
						if (element.Type == objet.NextStep)
						{
							if (objet.Step < objet.StepMax)
							{
								if (objet.ValidStep())
								{
									objet.Step++;
									objet.PrepareDisp ();
								}
							}
							else
							{	alert ("Next step doesn't exist.");	}
						}
						if (element.Type == objet.PrevStep)
						{	//	We don't need to test step number (negativ) because of the previous button doesn't be displayied for the first step
							objet.Step--;
							objet.PrepareDisp ();
						}
					});
				}
			},
			Link :
			{	passwords : []	},
			PicturesPath : "./images/",
		//	Pictures : ["RedLight.png", "YellowLight.png", "GreenLight.png"],
			Title : false,				//	Form titles
			Legend : false,				//	Form legend
			Method : "POST",
			Destination : "",			//	Page destination of the XMLHTTPRequest
			Step : 1,
			StepMin : 1,
			StepMax : 1,
			PasswordName : "password",
			NextStep : "nextStep",
			PrevStep : "prevStep",
			Types :
			{
				Undef : false,
				Date : "date",
				Mail : "mail"
			},
			
		//	Extract step function
			getInputStep : function (domClass)
			{
				var Step = 0;
				var Patt = /step\d{1,9}/gi;
				var Match = new RegExp(Patt);
				if (domClass.search ("step") != -1)
				{
					Step = Match.exec (domClass);
					Patt = /\d{1,9}/gi;
					Match = new RegExp (Patt);
					Step = Match.exec (Step);
				}
				return Step;
			},
			SearchStepExtremum : function ()
			{
				var Max = 0;
				for (i=0; i<this.RGY.fields.length; i++)
				{
					if (this.RGY.fields[i].Step > Max)
					{	Max = this.RGY.fields[i].Step;	}
					if (this.RGY.fields[i].Step < this.StepMin)
					{	this.StepMin = this.RGY.fields[i].Step;	}
				}
				for (i=0; i<this.RG.fields.length; i++)
				{
					if (this.RG.fields[i].Step > Max)
					{	Max = this.RG.fields[i].Step;	}
					if (this.RG.fields[i].Step < this.StepMin)
					{	this.StepMin = this.RG.fields[i].Step;	}
				}
				for (i=0; i<this.ND.fields.length; i++)
				{
					if (this.ND.fields[i].Step > Max)
					{	Max = this.ND.fields[i].Step;	}
					if (this.ND.fields[i].Step < this.StepMin)
					{	this.StepMin = this.ND.fields[i].Step;	}
				}
				for (i=0; i<this.Buttons.standard.length; i++)
				{
					if (this.Buttons.standard[i].Step > Max)
					{	Max = this.Buttons.standard[i].Step;	}
					if (this.Buttons.standard[i].Step < this.StepMin)
					{	this.StepMin = this.Buttons.standard[i].Step;	}
				}
				return Max;
			},
			/*******
			 *	Initialization method
			 *		Create every element with two methods : CreateField and CreateButton
			 ******/
			Init : function ()
			{
				//	For RGY fields
				this.RGY.fields = new Array(this.RGY.Temp.length);
				for (i=0; i<this.RGY.Temp.length; i++)
				{	this.RGY.fields[i] = new this.CreateField (this.RGY.Temp[i], this.RGY.Pictures);	}
				
				//	For RG fields
				this.RG.fields = new Array (this.RG.Temp.length);
				for (i=0; i<this.RG.Temp.length; i++)
				{	this.RG.fields[i] = new this.CreateField (this.RG.Temp[i], this.RG.Pictures);	}
				
				//	For N/D fields (Not Defined)
				this.ND.fields = new Array (this.ND.Temp.length);
				for (i=0; i<this.ND.Temp.length; i++)
				{	this.ND.fields[i] = new this.CreateField (this.ND.Temp[i], false);	}
				
				//	For buttons fields
				this.Buttons.standard = new Array (this.Buttons.Temp.length);
				for (i=0; i<this.Buttons.Temp.length; i++)
				{	this.Buttons.standard[i] = new this.CreateButton (this.Buttons.Temp[i]);	}
				//	Reset button
				this.Buttons.reset = new this.CreateButton (this.Buttons.reset);
				//	Submit button
				this.Buttons.submit = new this.CreateButton (this.Buttons.submit);
				//	Max Step
				this.StepMax = this.Buttons.submit.Step;
				if (this.SearchStepExtremum() > this.StepMax)
				{	alert ("There is a problem in your Loginify form. Review your step assignment. Submit button needs to be the last step.");	}
			},
			CreateField : function (node, pictures)
			{
				if (options.DebugLevel >= 1)
				{	alert ("Function CreateField");	}
				var i;

				this.HTML = node;
				this.Step = objet.getInputStep ($(node).attr("class"));
				this.IsValid = false;
				this.Type = objet.Type ($(node).attr("class"));
				if (this.Type == "date")
				{	$(node).datepicker();	}
				if (pictures)
				{
					this.Pictures = new Array();
					for (i=0; i<pictures.length; i++)
					{
						var temp = document.createElement ("img");
						temp.setAttribute ("src", objet.PicturesPath+pictures[i]);
						temp.setAttribute ("width", "20px");
						temp.setAttribute ("height", "20px");
						$(temp).css("float", "right");
						this.Pictures.push (temp);
					}
				}
			},
			CreateButton : function (node)
			{
				this.HTML = node;
				this.Step = objet.getInputStep ($(node).attr("class"));
				this.Type = $(node).attr("name");
			},
			/****
			 *	Define node type by class string
			 *
			 *		Returns if found, type of the node by check class string
			 *	of current node. If not found, this method returns false.
			 ***/
			Type : function (nodeClass)
			{
				var Type = false, Pos, End;
				Pos = nodeClass.search (/type=/i);
				if (Pos != -1)
				{
					End = nodeClass.indexOf (" ", Pos);
					//	Extract from Pos to End position
					if (End != -1)
					{	Type = nodeClass.substring(Pos+"type=".length, End);	}
					//	Extract from Pos to end of the string.
					else
					{	Type = nodeClass.substring(Pos+"type=".length);	}
				}
				return Type;
			},
			/*****
			 *	Identification of passwords field
			 *
			 *		If there is two password field, the second is used as verification
			 *	of password. A link needs to be created between these two fields.
			 ****/
			SearchPassword : function ()
			{
				var i, Min, Max;
				for (i=0; i<this.RGY.fields.length; i++)
				{
					if ($(objet.RGY.fields[i].HTML).attr ("type") == objet.PasswordName)
					{	this.PasswordId ($(objet.RGY.fields[i].HTML).attr ("name"));	}
				}
				for (i=0; i<this.RG.fields.length; i++)
				{
					if ($(objet.RG.fields[i].HTML).attr ("type") == objet.PasswordName)
					{	this.PasswordId ($(objet.RG.fields[i].HTML).attr ("name"));	}
				/*	Not Used
					var pos = $(objet.RG.fields[i].HTML).attr("class").search (/rule=/i);
					if (pos != -1)
					{
						objet.RG.fields[i].EnterStat = $(objet.RG.fields[i].HTML).attr("class").substring
						(
							pos+"rule=".length,
							$(objet.RG.fields[i].HTML).attr("class").indexOf (" ", pos)
						);
					}*/
				}
				Min = this.Link.passwords[0];
				Max = Min;
				for (i=1; i<this.Link.passwords.length; i++)
				{
					if (this.Link.passwords[i] < Min)
					{	Min = this.Link.passwords[i];	}
					if (this.Link.passwords[i] > Max)
					{	Max = this.Link.passwords[i];	}
				}
				if (Min == Max)
				{
					alert ("There is a problem in your HTML password input numbers.\n"+
						   "You need to correct them."+
						   "\n\nThe main password need to be smallest number and password verificator needs to be highest number");
				}
				else
				{
					
				}
				//	Deux possibilités : Min == Max, Min < Max
			},
			PasswordId : function (name)
			{
				var Match = new RegExp (/[0-9]/);
				var Num = Match.exec (name);
				this.Link.passwords.push (Num);
			},
			DrawPic : function ()
			{
				if (options.DebugLevel >= 1)
				{	alert ("Function DrawPic");	}
				//	RGY fields
				for (i=0; i<this.RGY.fields.length; i++)
				{	$(this.RGY.fields[i].HTML).parent().append (this.RGY.fields[i].Pictures);	}
				for (i=0; i<this.RG.fields.length; i++)
				{	$(this.RG.fields[i].HTML).parent().append (this.RG.fields[i].Pictures);	}
			},
			PrepareDisp : function ()
			{
				var i;
				//Title of the form
				if (objet.Titles[this.Step-1] != "")
				{	$(objet.Title).text (objet.Titles[this.Step-1]);	}
				//RGY fields
				for (i=0; i<this.RGY.fields.length; i++)
				{
					this.ErasePic (this.RGY.fields[i].Pictures);
					if (this.RGY.fields[i].Step != this.Step)
					{	$(this.RGY.fields[i].HTML).parent().hide();	}
					else
					{	$(this.RGY.fields[i].HTML).parent().show();	}
				}
				//RG fields
				for (i=0; i<this.RG.fields.length; i++)
				{
					this.ErasePic (this.RG.fields[i].Pictures);
					if (this.RG.fields[i].Step != this.Step)
					{	$(this.RG.fields[i].HTML).parent().hide();	}
					else
					{	$(this.RG.fields[i].HTML).parent().show();	}
				}
				//	N/D fields
				for (i=0; i<this.ND.fields.length; i++)
				{
					if (this.ND.fields[i].Step != this.Step)
					{	$(this.ND.fields[i].HTML).parent().hide();	}
					else
					{	$(this.ND.fields[i].HTML).parent().show();	}
				}
				//	Standard buttons
				for (i=0; i<this.Buttons.standard.length; i++)
				{
					if (this.Buttons.standard[i].Step != this.Step)
					{	$(this.Buttons.standard[i].HTML).hide();	}
					else
					{
						//	Test for next step buttons
						if (this.Buttons.standard[i].Type == this.NextStep)
						{
							if (this.Step < this.StepMax)
							{	$(this.Buttons.standard[i].HTML).show();	}
							else
							{	$(this.Buttons.standard[i].HTML).hide();	}
						}
						else
						{
							//	Test for previous step buttons
							if (this.Buttons.standard[i].Type == this.PrevStep)
							{
								if (this.Step > this.StepMin)
								{	$(this.Buttons.standard[i].HTML).show();	}
								else
								{	$(this.Buttons.standard[i].HTML).hide();	}
							}
							//	All others standard buttons
							else
							{	$(this.Buttons.standard[i].HTML).show();	}
						}
					}
				}
				//	submit button
				if (this.Buttons.submit.Step != this.Step)
				{	$(this.Buttons.submit.HTML).hide();	}
				else
				{	$(this.Buttons.submit.HTML).show();	}
			},
			ErasePic : function (pictures)
			{
				var i;
				for (i=0; i<pictures.length; i++)
				{	$(pictures[i]).hide();	}
			},
			EnterStat : function (pictures, length)//
			{
				if (options.DebugLevel >= 1)
				{
					alert ("function EnterStat");
					alert ("length received : "+length);
					$("#Tree").html ($(pictures[0]).attr("src"));
				}
				if (!length)
				{	$(pictures[0]).show();	}
				else
				{
					if (length < options.YLength)
					{	$(pictures[1]).show();	}
					else
					{	$(pictures[2]).show();	}
				}
			},
			ResetCurrentStepFields : function ()
			{
				var i;
				//RGY fields
				for (i=0; i<objet.RGY.fields.length; i++)
				{
					if (objet.RGY.fields[i].Step == objet.Step)
					{	$(objet.RGY.fields[i].HTML).val("");	}
				}
				//RG fields
				for (i=0; i<objet.RG.fields.length; i++)
				{
					if (objet.RG.fields[i].Step == objet.Step)
					{	$(objet.RG.fields[i].HTML).val("");	}
				}
				//	N/D fields
				for (i=0; i<objet.ND.fields.length; i++)
				{
					if (objet.ND.fields[i].Step == objet.Step)
					{	$(objet.ND.fields[i].HTML).val("");	}
				}
			},
			//	Verify the fields with particular rules
			ValidStep : function ()
			{
				var i;
				var Valid = true;
				objet.RGY.ExecuteRules ();
				objet.RG.ExecuteRules ();
				objet.ND.ExecuteRules ();
				$(objet.RGY.fields).each (function()
				{
					if (this.Step == objet.Step)
					{
						if (!this.IsValid)
						{
							$(this.HTML).css ("background-color", "red");
							Valid = false;
						}
						else
						{	$(this.HTML).css ("background-color", "green");	}
					}
				});
				$(objet.RG.fields).each (function()
				{
					if (this.Step == objet.Step)
					{
						if (!this.IsValid)
						{
							$(this.HTML).css ("background-color", "red");
							Valid = false;
						}
						else
						{	$(this.HTML).css ("background-color", "green");	}
					}
				});
				$(objet.ND.fields).each (function ()
				{
					if (this.Step == objet.Step)
					{
						if (!this.IsValid)
						{
							$(this.HTML).css ("background-color", "red");
							Valid = false;
						}
					}
					else
					{	$(this.HTML).css ("background-color", "green");	}
				});
				return Valid;
			},
			getFormValues : function ()
			{
				var OutputString = "";
				var LastPos = 0;
				$(objet.RGY.fields).each (function()
				{
					if ($(this.HTML).val() != "")
					{
						if (LastPos != OutputString.length)
						{
							OutputString += "&";
							LastPos = OutputString.length;
						}
						OutputString += $(this.HTML).attr("name")+"="+$(this.HTML).val();
					}
				});
				$(objet.RG.fields).each (function()
				{
					if ($(this.HTML).val() != "")
					{
						if (LastPos != OutputString.length)
						{
							OutputString += "&";
							LastPos = OutputString.length;
						}
						OutputString += $(this.HTML).attr("name")+"="+$(this.HTML).val();
					}
				});
				$(objet.ND.fields).each (function()
				{
					if ($(this.HTML).val() != "")
					{
						if (LastPos != OutputString.length)
						{
							OutputString += "&";
							LastPos = OutputString.length;
						}
						OutputString += $(this.HTML).attr("name")+"="+$(this.HTML).val();
					}
				});
				return OutputString;
			}
		};
		$.extend (objet, options);
	/*	this.each(function()
		{
			$("#Tree").html ($(this).html());
			if ($(this).html().search ("input") != -1)
			{
				//	Go in every children and get his type to manage it in the following.
			//	SearchChild (this);
				if (options.DebugLevel >= 2)
				{	alert ("Script en ordre.");	}
			}
			else
			{
				if (options.DebugLevel >= 2)
				{	alert ("Votre script n'est pas conforme !");	}
			}
		});*/
		
		objet.Title = $(this).children("h1").eq(0);
		objet.Legend = $(this).children("legend").eq(0);			//	Légende du formulaire
		
		if (typeof(objet.Title) == "undefined")
		{	alert ("Attention !\nVotre formulaire ne contient pas de balise titre !");	}
		
		//	Search for every input field in the form and store them in objet.
		$(this).find("input").each(function()
		{
			if ($(this).hasClass("RGY_Stat"))
			{	objet.RGY.Temp.push(this);	}
			else
			{
				if ($(this).hasClass("RG_Stat"))
				{	objet.RG.Temp.push (this);	}
				else
				{
					if ($(this).attr ("type") == "text")
					{	objet.ND.Temp.push (this);	}
				}
			}
			if ($(this).attr ("type") == "button")
			{	objet.Buttons.Temp.push (this);	}
			if (!objet.Buttons.reset && $(this).attr ("type") == "reset")
			{	objet.Buttons.reset = this;	}
			if (!objet.Buttons.submit && $(this).attr ("type") == "submit")
			{	objet.Buttons.submit = this;	}
		});
		
		//	Initialize Pictures node by input type.
		objet.Init ();
		objet.SearchPassword ();
		objet.DrawPic();
		objet.PrepareDisp();
		
		//	RGY fields
		$(objet.RGY.fields).each (function()
		{	objet.RGY.EventManager (this);	});
		
		//	RG fields
		$(objet.RG.fields).each (function ()
		{	objet.RG.EventManager (this);	});
		
		//	ND fields
		$(objet.ND.fields).each (function()
		{	objet.ND.EventManager (this);	});
		
		//	Button fields
		$(objet.Buttons.standard).each(function ()
		{	objet.Buttons.EventManager (this);	});
		
		//	Reset Button
		$(objet.Buttons.reset.HTML).click (function(event)
		{
			event.preventDefault();
			objet.ResetCurrentStepFields ();
		});
		
		//	Submit Button
		$(objet.Buttons.submit.HTML).click (function (event)
		{
			if (!objet.ValidStep ())
			{
				event.preventDefault();
				//	code for IE7+, Firefox, Chrome, Opera, Safari
			/*	if (window.XMLHttpRequest)
				{	XHR = new XMLHttpRequest();	}
				//	code for IE6, IE5
				else
				{	XHR = new ActiveXObject("Microsoft.XMLHTTP");	}
				
				XHR.onreadystatechange = function()
				{
					if (XHR.readyState==4 && XHR.status==200)
					{	document.getElementById("txtHint").innerHTML = XHR.responseText;	}
				}
				
				XHR.open(objet.Method, "login.php", true);
				XHR.setRequestHeader ("Content-type", "application/a-www-form-urlencoded");
				XHR.send(objet.getFormValues());*/
			}
		});
		return $(this);
	};
})(jQuery);
