var bInTest								= false;

var sTrackerCookie					= "LP-UniqueID";
var sWorkingIcon 						= "Working";
var sPlansTable 						= "plans_table";
var sPlansErrorMessage				= "plans_errormessage";
var sPlansTableContainer			= "PlansContainer";
var sPersonalDetailsSection		= "PersonalDetails";
var sPersonalDetailsAnimation		= "PersonalDetails_Animation";

var sPersonalDetailsForm			= "PersonalDetails_Form";
var sPersonalDetailsErrorMessage	= "PersonalDetails_Errors";
var sPersonalDetailsAjaxIndicator= "ProcessingIndicator";
var sPersonalDetailsSubmitButton	= "SubmitForm";
var sAllDone							= "AllDone";
var sShowReference					= "reference";
var sShowLoanmakersRef				= "loanmakers_reference";
var sLoanAmount_Highlight			= "LoanAmount_Highlight";
var sQueryForm 						= "QueryForm";
var sCloseButton						= "Close";
var sTitle								= "Title";
var sQueryTemplate					= "QueryTemplate";
var sQueryRow							= "QueryRow";
var sPricesUpToDate					= "prices_uptodate";
var sCancelSearchButton				= "CancelSearch";
var sAddSearchSection				= "AddSearchSection"
var sQueryFormPrefix					= "QueryForm_";
var sdbFieldPrefix					= "dbfield_";
var sQueryFieldPrefix				= "query_";

var sWorkingIconQ 					= "WorkingQ";
var sMorphQ 							= "MorphQ";
var sErrorQ								= "ErrorQ";

var sHighlightColour_Hover 		= "#FFFF99";
var sHighlightColour_Add			= "#97FF97";	//"#FA80FD";	

var gbl_sNoDatabase					= "no database";
var gbl_sOK								= "OK";
var gbl_sHiccough						= "NOT OK";

var oScreenAlert						= null;

var serr_General						= "the loans server did not reply to me";
var sLowestAprMessage			 	= "Lowest secured loan APR % rate!"
var iColumnsPerCriteriaSection = 5;
var sVerticalLineImage = "<img src='/img/1x1_black.gif' width='1' height='16' style='padding-left:6px; padding-right:6px;' />";
var ColumnOrder = ["APR","MonthlyPayment","TotalRepayable"];
var arColumnTitles = ["&nbsp;", "APR%", "Monthly Payment", "Total Repayable", "&nbsp;"];
var arColumnTitleClasses = ["VerticalBar_title", "APR_title", "MonthlyPayment_title", "TotalRepayable_title", "Blank_title"];
var arColumnValueClasses = ["VerticalBar", "APR", "MonthlyPayment", "TotalRepayable", ""];

var HelpBubbleWidget = Class.create();
HelpBubbleWidget.prototype = {
	oQueue: {scope:'BubbleHelpQ', position:'end'},
	
	initialize: function(sBubbleID) {
		this.oBubble = $(sBubbleID);
		
		var round_settings = {
		  tl: { radius: 10 },
		  tr: { radius: 10 },
		  bl: { radius: 10 },
		  br: { radius: 10 },
		  antiAlias: true,
		  autoPad: false
		}
		this.oBubble_Bubble = $(this.oBubble.descendants().find(function(elt){return elt.className == "HelpBubble_Bubble"}));
		this.oText = $(this.oBubble.descendants().find(function(elt){return elt.className == "HelpBubble_Text"}));
		this.oTop = $(this.oBubble.descendants().find(function(elt){return elt.id == "HelpBubble_pointer_top"}));
		this.oBottom = $(this.oBubble.descendants().find(function(elt){return elt.id == "HelpBubble_pointer_bottom"}));
		this.oLeft = $(this.oBubble.descendants().find(function(elt){return elt.id == "HelpBubble_pointer_left"}));
		this.oRight = $(this.oBubble.descendants().find(function(elt){return elt.id == "HelpBubble_pointer_right"}));
		
		this.arPointers = $H({below:this.oTop, above:this.oBottom, right:this.oLeft, left:this.oRight});
		
		new curvyCorners(round_settings, this.oBubble_Bubble).applyCornersToAll();
		
		// Fudge
		if (TheBrowser.ie) {
			this.oRight.style.left = "18px";
		}
	},
	
	ShowPointer: function(sWhich) {
		this.arPointers.each(function(el){Element.hide(el.value)});
		if (typeof sWhich != "undefined")
			Element.show(this.arPointers[sWhich]);
	},
	
	refreshposition: function() {
		if (typeof(this.oHelpRefObject) != "undefined" && typeof(this.sHelpPosition) != "undefined") {
			this.position(this.oHelpRefObject, this.sHelpPosition);
		}
	},
	
	position: function(Obj, sRelative, iSpeed) {
		if (! Element.visible(Obj))
			return;

		if (typeof iSpeed == "undefined")
			iSpeed = 1;
			
		this.oHelpRefObject = Obj;
		this.sHelpPosition = sRelative;
		
		this.ShowPointer(sRelative);		
		var pos = Position.cumulativeOffset(Obj);
		var dim = Obj.getDimensions();
		var BubbleDim = this.oBubble.getDimensions();
		
		switch (sRelative) {
			case "above":
				var t = pos[1] - Element.getHeight(this.oBubble) - 4 - ((TheBrowser.ie)?10:0);
				var l = pos[0] - Element.getWidth(this.oBubble) + 24 + 20;
				this._MoveOrMorph(l, t, iSpeed);
				break;
				
			case "below":
				var t = dim.height + pos[1] + 20 ;
				var l = pos[0] - 20 + 10;
				this._MoveOrMorph(l, t, iSpeed);
				break;
				
			case "left":
				var t = pos[1] - (dim.height) - 2;
				var l = pos[0] - BubbleDim.width - 24 - ((TheBrowser.ie)?10:0);
				this._MoveOrMorph(l, t, iSpeed);
				break;
				
			case "right":
				var t = pos[1] - (dim.height) + 4;
				var l = pos[0] + dim.width + 26;
				this._MoveOrMorph(l, t, iSpeed);
				break;
				
		}
		return this;
	},

	_OffScreen:function() {
		this.oBubble.style.top = "-200px";
		this.oBubble.style.left = "-200px";
	},

	_MoveOrMorph: function(x, y, iSpeed) {
		if (typeof iSpeed == "undefined")
			iSpeed = 0.5
		if (Element.visible(this.oBubble)) {
			this.oBubble.morph({top: y+"px", left: x+"px"}, {duration:iSpeed, queue:this.oQueue});
		} else {
			this.oBubble.style.top = y+"px";
			this.oBubble.style.left = x+"px";
		}
	},
	
	update: function(sText) {
		this.oText.update(sText);
		return this;
	},
	
	show: function(bImmediately) {
		if (bImmediately)
			Element.show(this.oBubble);
		else 
			new Effect.Appear(this.oBubble, {duration:0.5, queue:this.oQueue});
		return this;
	},
	
	hide: function() {
		this.ShowPointer();
		new Effect.Fade(this.oBubble, {duration:0.5, queue:this.oQueue});
		return this;
	}
};


var SourcingTableWidget = Class.create();
SourcingTableWidget.prototype = {
	initialize: function(oPlansTable, oSubmitDetails) {
		this.oSubmitDetailsWidget	= oSubmitDetails;
		this.oPlansTable 				= $(oPlansTable);
		this.oWorkingIcon				= $(this.oPlansTable.descendants().find(function(elt){return elt.id == sWorkingIcon}));
		this.oCancelSearchButton	= $(this.oPlansTable.descendants().find(function(elt){return elt.id == sCancelSearchButton}));
		
		this.oQueryControl			= $(this.oPlansTable.descendants().find(function(elt){return elt.id == sQueryTemplate}));
		this.oErrorMessage			= $($(this.oPlansTable.parentNode).descendants().find(function(elt){return elt.id == sPlansErrorMessage}));
		
		this.iCriteriaSections 		= 1;
		this.SearchesCount			= 0;
		this.arPlans 					= $H();

		this.HighlightedObject		= [];
		this.bSearchingInProgress 	= false;
		this.iShowMore					= false;		
		this.b_FlashAddSearchSection = true;

		this.oHelpTimer				= 0;

		// Star rating
		this.oStarRating = new StarRatingWidget();

		// Clicks
		this.handler = this.handleThisEvent.bindAsEventListener(this);		
		this.oPlansTable.observe('click', this.handler);
		this.oPlansTable.observe('mouseover', this.handler);
		this.oPlansTable.observe('mouseout', this.handler);

		this.fieldHandler = this.handleFieldEvents.bindAsEventListener(this);		
		
		// Put a "blur" event on each of the input/select buttons
		this.oQueryControl.descendants().each(
			function(elt){
				if (elt.id && Element.visible(elt))
					if (elt.id.substr(0,sQueryFieldPrefix.length) == sQueryFieldPrefix) {
						elt.observe('blur', this.fieldHandler);
						elt.observe('focus', this.fieldHandler);
					} else if (elt.id=="submit") {
						elt.observe('click', this.fieldHandler);
						elt.observe('focus', this.fieldHandler);
					}
			}.bind(this)
		);
				
		this.bFirstSearchByUser	= false;
		this.bFirstPlanSelect 	= true;		
		this.bCanCompare 			= false;
		this.bFirstTime	 		= true;
	},
	
	Startup: function() {
		this.AdviseVisitorInitialise();
		this.findPlans();
		this.bFirstSearchByUser = true;
		setTimeout("ConsiderFieldFocus('query_Amount')", 4000);
	},
	
	ShowMore: function(caller, sOpposite) {
		RecordEvent("Plans_ShowMore");
		this.iShowMore = true;
		return this.ChangeNumberOfPlansShown(caller, sOpposite);
	},
	ShowFewer: function(caller, sOpposite) {
		RecordEvent("Plans_ShowLess");
		this.iShowMore = false;
		return this.ChangeNumberOfPlansShown(caller, sOpposite);
	},
	ChangeNumberOfPlansShown: function(caller, sOpposite) {
		Element.hide(caller);
		Element.show(sOpposite);
		//this.findPlans();
		
		this.prepareForFindPlans();
		this.bFirstTime	= true;
		this.FillTable();
		return false;
	},
	
	findPlans: function(oCriteria) {
		this.oStarRating.ResetScope();
		this.prepareForFindPlans();
		this._actuallyFindPlans(oCriteria);		
	},
	
	_actuallyFindPlans:function(oCriteria) {
		if (typeof(oCriteria) == "undefined")
			oCriteria = this.oQueryControl;

		var params = oCriteria.serialize();
		var myregexp = /_(\d+)/;
		var match = myregexp.exec(oCriteria.id);
		if (match != null) {
			this.ArrayIndex = match[1] - 1;
		} else {
			this.ArrayIndex = 0;
		}

		RecordEvent("SearchPlans", params);
		this.oAjaxCall = new Ajax.Request('/ajax/Sourcing/SourcingDataToJSON_V2.php', {
							  parameters: params,
							  onSuccess:this.SourcingSuccess.bind(this),
							  onFailure:this.SourcingFailure.bind(this),
							  onComplete:this.SourcingComplete.bind(this)
							  });			
	},

	prepareForFindPlans:function() {
		this.ClearErrorMessage();
		this.AdviseSearching();
		this.disableSearchButtons();
		this.EmptyTable();		
	},

	CancelSearchInProgress: function() {
		// Return early from waiting for the AJAX call.
		if (typeof this.oAjaxCall != "undefined")
			try {
				this.oAjaxCall.transport.abort(); 
				this.enableSearchButtons();
			} catch(e) {}
	},

	SourcingComplete: function() {
		this.FillTable();
		delete this.oAjaxCall;
	},
	
	SourcingFailure: function(oAjax, oJSON) {
		var sWhy = "";
		if (oAjax.responseText) 
			sWhy = " [" + oAjax.responseText + "]"
		this.ShowErrorMessage(serr_General + sWhy);
	},

	ScanPlansForError: function(sResponseText) {
		var sError = null;
		var myregexp = /unable to find/i;
		var match = myregexp.exec(sResponseText);
		if (match != null) {
			sError = "no new plans were found to match your enquiry";
		}
		return sError;		
	},

	SourcingSuccess: function(oAjax, oJSON) {
		var isError = false;
		if (oAjax.status == 200) {
			this.HideCancelSearchButton();
			this.RemoveColumnFromPlans(this.ArrayIndex);
					
			var sError = this.ScanPlansForError(oAjax.responseText);
			if (sError) {
				this.ShowErrorMessage(sError);
				isError = true;
			} else {
				var myPlans;
				var x = "myPlans = " + oAjax.responseText;
				try {
					eval (x);
				} catch(e) {}
				
				if (typeof myPlans == "undefined") {
					this.ShowErrorMessage("no new plans were found to match your enquiry [" + oAjax.responseText + "]");
					isError = true;
				} else 	if (myPlans.length > 0) {
					// Remove previous list of plans for this "column"
					this.RemoveColumnFromPlans(this.ArrayIndex);
					this.LoadColumnIntoPlans(myPlans);
					this.TidyupPlansArray();
					this.SortPlans("APR");
				} else {
					var sWhy = "";
					if (oAjax.responseText) 
						sWhy = " [" + oAjax.responseText + "]";
					this.ShowErrorMessage(serr_General + sWhy);
					isError = true;
				}
			}
		} else {
			var sWhy = "";
			if (oAjax.responseText) 
				sWhy = " [" + oAjax.responseText + "]";
			this.ShowErrorMessage(serr_General + sWhy + " (" + oAjax.status + ")");
			isError = true;		
		}	
	},
	
	SortPlans: function(sColumn) {
		// Sort this.arPlans by the sColumn (eg "APR") field in the this.ArrayIndex'th column
		//
		// this.arPlans = [ Lender:[plan1, plan2, ...], Lender2:[plan1, plan2, ...], ... ]
		var oLender;
		var temp = this.arPlans.sortBy(function(oLender) {
			var oarPlans = oLender.value;
			var oPlan = oarPlans[this.ArrayIndex];
			var iAPR = oPlan.APR;		// or oPlan[sColumn]
			return (typeof iAPR == "undefined")?100:(iAPR*1);
		}.bind(this));
		
		this.arPlans = this.arrayToSourcingHash(temp);
		var A = 1;
	},
	
	arrayToSourcingHash: function(ar) {
		var H = $H();
		ar.each(function(el){
			H[el[0]] = el[1];					  
		});
		return H;
	},
	
	TidyupPlansArray: function() {
		// Remove all lenders from the array if they have no data for any of the criteria-searches.
		// This will allow more lenders to appear beyond the "5" visual limit we've imposed.
		
		// For each lender....
		this.arPlans.each( function(oLender, index) {
			var bLenderRowIsBlank = true;
			// For each plan that this lender record holds
			oLender.value.each(function(oLenderPlan) {
				if (typeof oLenderPlan != "undefined") {
					if (typeof oLenderPlan.APR != "undefined") {
						bLenderRowIsBlank = false;
					}
				}
			});
			// If this lender has no plans, remove the lender from the array...
			if (bLenderRowIsBlank) {
				delete this.arPlans[oLender.key];
			}
		}.bind(this) );
		var A = 1;
	},

	LoadColumnIntoPlans: function(myPlans) {
		myPlans.each(
			function(o, index) { 
				var obj = {MonthlyPayment:o.MonthlyPayment, APR:o.APR, TotalRepayable:o.TotalRepayable};
				if ( typeof(this.arPlans[o.Lender]) == "undefined" ) {
					this.arPlans[o.Lender] = [];	//{};
				}
				this.arPlans[o.Lender][this.ArrayIndex] = obj;
				this.oStarRating.AddToScope(obj.APR);
			}.bind(this)
		);
	},

	RemoveColumnFromPlans: function(ArrayIndex) {
		this.arPlans.each(
			function(el) {
				this.arPlans[el.key][ArrayIndex] = {}
			}.bind(this)
		);

	},

	FillTable: function() {
		setTimeout(this.FillTable_PostErase.bind(this), (this.bFirstTime)?10:Math.random()*4000+1000);
	},
	
	FillTable_PostErase: function() {
		if (! this.bTableIsEmpty ) {
			setTimeout(this.FillTable_PostErase.bind(this), 10);
			return;
		}

		var sBottomBorderStyle = '1px solid #C1FFC1';
		var iTotalDelay = 0;
		var iDelay = 0;
		var iSpeed = 0.5;
		var iRandom = 0;
		var arNACols = ColumnOrder.clone();
		arNACols.push("Apply");

		if (this.iShowMore)
		//var MaxRows = this.arPlans.size();
		//if (document.URL.indexOf("showlogos") > -1)
			this.MaxRows = this.arPlans.size();
		else 
			this.MaxRows = 5;

		var iBrokerLogo = 0;
		this.arPlans.each(
			function(row, index) {
				if ( /*document.URL.indexOf("showlogos") > -1 && */ index >= this.MaxRows) 
						throw $break;
				if (index >=(this.MaxRows-1))
					sBottomBorderStyle="";

				var sBrokerLogo = null;
				
				var fAPR = 1;
				var fLowestAPR = 1000;
				var sClass = "tr_rowB";	//(index % 2)?"tr_rowA":"tr_rowB";
				var oRow = Builder.node("TR", {className:sClass});

				var sLenderContent = row.key
				var oTD = Builder.node("TD", {className:"Lender"} );
				oTD.style.padding="4px";
				oTD.style.borderBottom = sBottomBorderStyle;
				
				//if (document.URL.indexOf("showlogos") > -1) {
					sBrokerLogo = "LenderIMG_" + iBrokerLogo++;
					var oLenderImage = Builder.node("IMG", {style:'display:none; margin-right:50px', src:"/php/lib/Lib_LenderImage.php?" + row.key} );
					oLenderImage.id = sBrokerLogo;
					//if (TheBrowser.saf)
					//	oLenderImage.style.display="";	// patch
					oTD.appendChild(oLenderImage);
					oTD.appendChild(Builder.node("BR"));
					oTD.appendChild(document.createTextNode(sLenderContent));
					oTD.style.padding="4px";
				//} else {
				//	oTD.appendChild(Builder.node("P", {style:"margin:0px"}, sLenderContent));
				//}
				
				oRow.appendChild(oTD);
				
				var ColCount = 0;
				
				// DO a FOR loop checking that if there is an array for the FOR index print the values, else print n/a's
				var arColumnData = row.value;				
				for (iColumnSetToPrint = 0; iColumnSetToPrint < this.iCriteriaSections; iColumnSetToPrint++) {
					var oColumnSet = arColumnData[iColumnSetToPrint];
					var oQueryControl = (iColumnSetToPrint==0)?this.oQueryControl:$("QueryForm_"+(iColumnSetToPrint+1));								
					if (typeof(oColumnSet) == "undefined" || typeof(oColumnSet.APR) == "undefined" ) {
						// do a blank set of columns
						var iBlankCols = iColumnsPerCriteriaSection-1;
						arNACols.each(
							function(colName) {
								var sText;
								switch (colName) {
									case "TotalRepayable":	sText = "Not available";	break;
									case "Apply":				sText = " ";				break;
									default:						sText = " ";				break;
								}
								var oTD = Builder.node("TD", {className:"NotApplicable"}, sText);
								oTD.style.borderBottom = sBottomBorderStyle;
								oRow.appendChild(oTD);
							}
						);
						ColCount+=iBlankCols;
					} else {
						ColumnOrder.each(
							function(colName) {
								if (typeof oColumnSet[colName] == "undefined") 
									oColumnSet[colName] = "n/a";
								var oTD = Builder.node("TD");
								oTD.style.borderBottom = sBottomBorderStyle;
								switch (colName) {
									case "APR":
										var sAlt = "";
										if (this.oStarRating.StarRating_IsLowestValue(oColumnSet[colName])) {
											sAlt = sLowestAprMessage;
										}
										oTD.innerHTML = oColumnSet[colName] + "%";
										oTD.innerHTML += "<br><img height='13' class='"+this.oStarRating.StarRating_AsClassname(oColumnSet[colName])+"' alt='"+sAlt+"' title='"+sAlt+"'>";
										//+ (this.oStarRating.StarRating_IsLowestValue(oColumnSet[colName])?"alt='"+sLowestAprMessage+"' title='"+sLowestAprMessage+"'":"") + "'>";
										oTD.className = "APR";
										fAPR = oColumnSet[colName];
										break;
									case "MonthlyPayment":									
										oTD.innerHTML = "&pound;" + addCommas(oColumnSet[colName]) + "<div style='height:13px;'></div>";// + ".00";
										oTD.className = "MonthlyPayment";
										break;
									case "TotalRepayable":
										oTD.innerHTML = "&pound;" + addCommas(oColumnSet[colName]) + "<div style='height:13px;'></div>";// + ".00";
										oTD.className = "TotalRepayable";
										break;
								}
								oTD.id = oTD.className + ":" + oQueryControl.LoanAmount.value + "/" + oQueryControl.LoanTerm.value + "/" + row.key + "/" + oColumnSet["APR"] + "/" + oColumnSet["MonthlyPayment"].replace(",","") + "/" + oColumnSet["TotalRepayable"].replace(",","");
								oRow.appendChild(oTD);
								ColCount++;
							}.bind(this)
						)
					}					
					
					if ( ColCount % iColumnsPerCriteriaSection == (iColumnsPerCriteriaSection-2) ) {
						oTD = Builder.node("TD");
						oTD.style.borderBottom = sBottomBorderStyle;
						var sChoice = "Button:" + oQueryControl.LoanAmount.value + "/" + oQueryControl.LoanTerm.value + "/" + row.key + "/" + oColumnSet["APR"] + "/" + oColumnSet["MonthlyPayment"].replace(",","") + "/" + oColumnSet["TotalRepayable"].replace(",","") ;
						oTD.appendChild( Builder.node("INPUT", {type:"button", className:"Apply", value:"more info >", id:sChoice, disabled:true}) );
						oTD.appendChild( Builder.node("DIV", {style:"height:13px;"}));
						oRow.appendChild(oTD);
						ColCount++;
					}
					if (ColCount < (this.iCriteriaSections * iColumnsPerCriteriaSection)-1){
						if ( ColCount % iColumnsPerCriteriaSection == (iColumnsPerCriteriaSection-1) ) {						
							oTD = Builder.node("TD", {className:"VerticalBar"});
							oTD.style.borderBottom = sBottomBorderStyle;
							oRow.appendChild(oTD);
							ColCount++;;
						}
					}

				}
				var bDoFlash = true;
				if (this.bFirstTime) {
					iDelay = 1;
					bDoFlash = false;
					iTotalDelay++;
				} else {
					var mn = fAPR * Math.log(fAPR);
					var mx = (fAPR*1) + mn;
					var fRand = Random(mn*0.75, mx*1.3);
					iDelay = (1/fRand)*150; // 140;
					if (iDelay > 10)
						iDelay = 10;
					iTotalDelay += (bInTest)?0.5:iDelay;
	
					bDoFlash = false;
					if (fAPR < fLowestAPR) {
							fLowestAPR = fAPR;
							bDoFlash = true;
					}
				}
				new AddRowWithEffect("Appear", iDelay, this.oPlansTable, oRow, bDoFlash, sBrokerLogo);
			}.bind(this)
		);
		
		if (iTotalDelay > 30 || iTotalDelay <=0)
			iTotalDelay = 30;
		setTimeout(this.enableSearchButtons.bind(this), iTotalDelay*350);
		
		//setTimeout(this.RefreshStarRating.bind(this), 1000);
		this.RefreshStarRating();
	},
	
	RefreshStarRating:function() {
		this.oStarRating.SetImageSrcByClass({iMin:0.5});
	},
	
	EmptyTable: function() {
		this.bTableIsEmpty = false;
		if (this.oPlansTable) {
			var trowsA = $$("tr.tr_rowA");
			var trowsB = $$("tr.tr_rowB");
			var trows = trowsA.concat(trowsB);
			trows = trows.sortBy(function(){return Math.random() >=0.5});
			var Rows = trows.length;
			var iTotalDelay = 0;
			var iDelay = 0;
			for (var ir=Rows-1; ir>=0; ir--) {
				iDelay += Math.random() * 0.25;
				iTotalDelay += iDelay;
				new DeleteRowWithEffect("Fade", iDelay, trows[ir]);			
			}
		}
		setTimeout(this.FlagTableAsEmpty.bind(this), iTotalDelay*100);
	},
	
	FlagTableAsEmpty: function() {
		setTimeout(function(){this.bTableIsEmpty = true}.bind(this), 2000);
		//this.bTableIsEmpty = true;
	},

	
	disableSearchButtons: function() {
		this.bSearchingInProgress = true;
		this.ShowWorkingIcon();
		document.getElementsByClassName("SearchButton").each(function(el){el.disabled = true});
		document.getElementsByClassName(sAddSearchSection).each(function(el){el.hide()});
		document.getElementsByClassName("Apply").each(function(el){el.disabled = true});
		Element.hide("rowcountchange");		
	},
	
	enableSearchButtons: function() {
		this.bSearchingInProgress = false;		
		document.getElementsByClassName("SearchButton").each(function(el){el.disabled = false});
		if (this.bCanCompare) {
			document.getElementsByClassName(sAddSearchSection).each(function(el){el.show();});
			
			if (typeof(this.id_FlashAddSearchSection) != "undefined" )
				clearInterval(this.id_FlashAddSearchSection);
			if (this.b_FlashAddSearchSection)
				this.id_FlashAddSearchSection = setInterval(this.FlashAddSearchSection.bind(this), 2000);
		}
		document.getElementsByClassName("Apply").each(function(el){el.disabled = false});
		
		Element.show("rowcountchange");
		this.HideWorkingIcon();
		this.AdviseVisitorHowToBegin();
		
		if (!this.bFirstSearchByUser && this.bFirstPlanSelect) {
			setTimeout(this.AdviseVisitor_selectPlan.bind(this), 3000);
		}
		
		//if (this.bFirstTime)
		//	setTimeout("ConsiderFieldFocus('query_Amount')", 1000);
		
		//this.bFirstSearchByUser = false;
		//setTimeout(this.notFirstTime.bind(this), 5000);
	},
	
	FlashAddSearchSection: function() {
		document.getElementsByClassName(sAddSearchSection).each(function(el){ new Effect.Fade(el, {duration:0.7, to:0.3, afterFinish:function(effect){new Effect.Appear(effect.element.id, {duration:0.7})}}); });
	},
	
	notFirstTime:function() {
		this.bFirstTime = false;
	},

	// Advice for the visitor...
	AdviseVisitorInitialise: function() {
		//oHelp.update("Initialising page ... one moment please.");
		oHelp._OffScreen();
		//oHelp.show();
		//oHelp.position(this.oWorkingIcon, "below", 2);
	},
	AdviseVisitorHowToBegin: function(iSpeed) {
		if (typeof iSpeed == "undefined")
			iSpeed = 2;
		if (this.bFirstSearchByUser) {
			oHelp.update("Start here - tell us how much you might like to borrow ( <a style='' href='/h/loanspage_com-ourservice.php'><span style='font-weight:normal; color:white; text-decoration:underline'>more</span></a>... )");
			oHelp.show(1);
			oHelp.position(this.oQueryControl.query_Amount, "below", iSpeed);
			//setTimeout(this.RepositionHelp.bind(this), 5000);
			setTimeout("oHelp.refreshposition()", 5000);
		}
	},
	AdviseVisitorClickSearch: function(iSpeed) {
		if (this.bFirstSearchByUser) {
			oHelp.update("Click here to find your loan plans.");
			oHelp.position(this.oQueryControl.submit, "above", iSpeed);
			oHelp.show();
		}
	},
	AdviseVisitor_selectPlan: function() {
		if (this.bFirstPlanSelect) {
			oHelp.update("Click on a plan that seems right for you...");
			oHelp.position($("selectplan_pos"), "above", 1);
			oHelp.show();			
			this.bFirstPlanSelect = false;
			this.bFirstSearchByUser = false;
			this.oHelpTimer = setTimeout(this.AdviseVisitor_compare.bind(this), 4000);
		}
	},
	AdviseVisitor_compare: function() {
		//if (this.bFirstSearchByUser) {
			oHelp.update("<b>Brand New:</b> ...or compare plans using different loan amounts/terms.");
			
			var oCompareAnchor = $(this.oPlansTable.descendants().find(function(elt){return elt.id == "add"}));
			if (typeof oCompareAnchor != "undefined") {
				oHelp.position(oCompareAnchor, "above");
				oHelp.show();
			}
			this.oHelpTimer = setTimeout("oHelp.hide()", 7000);
		//}
	},

	ShowWorkingIcon:function() {
		this.ShowCancelSearchButton();
		new Effect.Appear(this.oWorkingIcon, {queue:{scope:sWorkingIconQ, position:'end'}});
	},


	HideWorkingIcon:function() {
		new Effect.Fade(this.oWorkingIcon, {queue:{scope:sWorkingIconQ, position:'end'}});
	},

	HideCancelSearchButton: function() {
		this.oCancelSearchButton.disabled=true;
		new Effect.Fade(this.oCancelSearchButton);
	},
	ShowCancelSearchButton: function() {
		this.oCancelSearchButton.disabled=false;
		Element.show(this.oCancelSearchButton);
	},


	AddNewQuerySection: function() {
		var bIgnoreRows = true;
		if (typeof(this.id_FlashAddSearchSection) != "undefined" )
			clearInterval(this.id_FlashAddSearchSection);
		this.b_FlashAddSearchSection = false;
	
		RecordEvent("Compare");
	
		// Increment the number of CriteriaSections in the table
		this.iCriteriaSections++;
		
		// Add columns to all our existing rows
		var oRows = $A(this.oPlansTable.getElementsByTagName('tr'));
		var iDimensionsToAdd = 0;
		oRows.each(function(oRow, index)
			{
				if (oRow.id == sQueryRow) {
					var oTD = Builder.node("TD");
					oRow.appendChild(oTD);
					
					oTD = Builder.node("TD");
					oTD.colSpan = iColumnsPerCriteriaSection-1;
					oTD.style.padding = "0";
					var oQueryClone = this.oQueryControl.cloneNode(true);
					
					oQueryClone.id = "QueryForm_" + this.iCriteriaSections;
					oTD.appendChild(oQueryClone);
					oRow.appendChild(oTD);
					
					if (this.bFirstSearchByUser)
						oHelp.position(oQueryClone.query_Amount, "below");
					else
						oHelp.hide();
				}
				
				if (oRow.className == "header") {
					bIgnoreRows = false;
				}

				if (!bIgnoreRows) {
					for(var a=0; a<iColumnsPerCriteriaSection; a++) {						
						var oTD = Builder.node("TD");
						
						if (iDimensionsToAdd==0) {
							oTD.className = arColumnTitleClasses[a];
							oTD.innerHTML = arColumnTitles[a];
						} else {
							oTD.className = arColumnValueClasses[a];
							switch(a) {
								case 0:	oTD.innerHTML = "&nbsp;";			break;
								case 1:	oTD.innerHTML = "-.-%";				break;
								case (iColumnsPerCriteriaSection-1):	
									var oApplyButton = Builder.node("INPUT", {type:"button", className:"Apply", value:"apply", id:""});
									Form.Element.disable(oApplyButton);
									oTD.appendChild(oApplyButton);
									break;
								
								default:	oTD.innerHTML = "&pound;--";	break;
							}
						}
												
						oRow.appendChild(oTD);
					}
					iDimensionsToAdd++;
				}

			}.bind(this)
		);				
	},
	
	Close: function(oSectionToClose) {
		// Remove a CriteriaSection from the table
		var a = 1;
		
		var oRows = $A(this.oPlansTable.getElementsByTagName('tr'));
		oRows.each(function(oRow)
			{
				var oSection = oSectionToClose.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
			}.bind(this)
		);
	},
	
	
	handleFieldEvents: function(e) {
		var elt = Event.element(e);
		if (e.type=="blur") {
			if (elt.id == "query_Amount") {
				elt.value = ToNumber(elt.value);
			} else if (elt.id == "query_Term") {
				//oHelp.hide();
			}
		}
		if (e.type=="focus") {
			if (elt.id == "query_Term") {
				oHelp.update("... now select how long to pay back the loan. Click <b style='color:yellow'>[Search...]</b> when ready.");
				oHelp.position(this.oQueryControl.query_Term, "above");	
			} else if(elt.id == "query_Amount")  {
				this.AdviseVisitorHowToBegin(0.5);
			} else if (elt.id == "submit") {
				this.AdviseVisitorClickSearch(0.5);
			}
		}
				
		if (e.type=="click") {
			if (elt.id == "submit") {
				this.notFirstTime();
				this.AdviseSearching();
			}
		}
	},

	AdviseSearching:function() {
		setTimeout(this._AdviseSearching.bind(this), 500);
	},
	
	_AdviseSearching: function() {
		this.SearchesCount++;
		if (this.bFirstSearchByUser) {
			oHelp.update("We're now searching loan plans for you...");
			oHelp.position(this.oWorkingIcon, "below");				
			//setTimeout(this.RepositionHelp.bind(this), 3500);			
			setTimeout("oHelp.refreshposition()", 2000);
			if (this.SearchesCount > 1){
				this.bFirstSearchByUser = false;
				this.bCanCompare = true;
				setTimeout("oHelp.hide()", 7000);
			}
		}
	},

/*
	RepositionHelp: function() {
		if (typeof(this.oHelpRefObject) != "undefined") {
			oHelp.position(this.oHelpRefObject, "below");
			delete this.oHelpRefObject;
		}
	},
*/
	handleThisEvent: function(e) {
		var elt = Event.element(e);
		if (elt) {
			// If the class is APR, MonthlyPayment or TotalPayable then highlight the box
			
			if ( (e.type == "click" || e.type == "button"))
				if (this.IsADealField(elt.className) && !this.bSearchingInProgress )
					this.Apply(elt.id);
				else if(elt.id == this.oCancelSearchButton.id) 
					this.CancelSearchInProgress();
	
			if (!this.bSearchingInProgress && e.type == "mouseover" && this.IsADealField(elt.className)) {
				this.HighlightDeal(elt);
			}
			if (!this.bSearchingInProgress && e.type == "mouseout" && this.IsADealField(elt.className)) {
				this.UnhighlightDeal(elt);
			}
		}
	},
	
	HighlightDeal:function(elt) {
		var oDeal = {};
		var sDealID;
		var myregexp = /\w+:(.*)/;
		var match = myregexp.exec(elt.id);
		if (match != null) {
			sDealID = match[1];
		} else {
			sDealID = "";
		}

		if (sDealID != "") {
			oDeal.APR = ["APR:" + sDealID, $("APR:" + sDealID).style.backgroundColor];
			oDeal.MonthlyPayment = ["MonthlyPayment:" + sDealID, $("MonthlyPayment:" + sDealID).style.backgroundColor];
			oDeal.TotalRepayable = ["TotalRepayable:" + sDealID,$("TotalRepayable:" + sDealID).style.backgroundColor];
			this.HighlightObjects(oDeal);	
		}
	},
	
	HighlightObjects:function(oDeal) {
		oDeal = $H(oDeal);
		this.HighlightedObject.push(oDeal);
		oDeal.each(
			function(el) {
				$(el.value[0]).style.backgroundColor = sHighlightColour_Hover;			
			}
		);		
	},

	UnhighlightDeal:function(elt) {
		if (this.HighlightedObject.length) {
			var oDeal = this.HighlightedObject.pop();	
			oDeal.each(
				function(el) {
					$(el.value[0]).style.backgroundColor = el.value[1];
				}
			);
		}
	},
	
	Show: function() {
		$(sPricesUpToDate).show();
		if (this.bFirstSearchByUser)
			oHelp.show();
			
		//if (TheBrowser.ie)
			new Effect.SlideDown(sPlansTableContainer, {duration:2}); 
		//else
		//	new Effect.BlindDown(sPlansTableContainer, {duration:2}); 
	},
	
	Hide: function() {
		oHelp.hide();
		//if (TheBrowser.ie)
			new Effect.SlideUp(sPlansTableContainer, {duration:2, afterFinish:function(){$(sPricesUpToDate).hide()} });
		//else 
		//	new Effect.BlindUp(sPlansTableContainer, {duration:2, afterFinish:function(){$(sPricesUpToDate).hide()} }); 	
	},
	
	Apply: function(sChoice) {
		// Change the page...
		//	MonthlyPayment:25000/60/Paragon Personal/10.0/263
		var myregexp = /(\w+):(\d+)\/(\d+)\/([\w\s]+)\/([\d.]+)\/(\d+)/;
		var match = myregexp.exec(sChoice);
		if (match != null) {
			if (match[1] != "Button") {
				new Effect.Pulsate(sChoice, {pulses:2, duration:0.5,
					afterFinish:function(){
						this.ChangePageToApplyMode(sChoice);
					}.bind(this) }
				);
			} else {
				this.ChangePageToApplyMode(sChoice);
			}
		}		
	},
	
	ChangePageToApplyMode: function(sChoice) {
		RecordEvent("SelectPlan", sChoice);
		
		if (this.oHelpTimer) {
			clearTimeout(this.oHelpTimer);
			this.oHelpTimer = 0;
		}
		
		// Setup the Personal Details section with the data just chosen...
		this.oSubmitDetailsWidget.Apply(sChoice);
		this.Hide();
		
		this.bFirstSearchByUser = false;
		this.bFirstPlanSelect = false;
	},
	
	IsADealField: function(s) {
		return (s == "Lender" || s == "APR" || s == "MonthlyPayment" || s == "TotalRepayable" || s == "Apply" || s == "HighlightHelper");
	},
	
	ShowErrorMessage: function(sError) {
		this.oErrorMessage.update("<strong style='color:red'>Information:</strong><br>We apologise for any inconvenience but " + sError + ". Please try again.");
		this.oErrorMessage.visualEffect('BlindDown', {queue:{scope:sErrorQ, position:'end'}});
	},
	
	ClearErrorMessage: function() {
		this.oErrorMessage.visualEffect('BlindUp', {queue:{scope:sErrorQ, position:'end'}});
	}
};



var DeleteRowWithEffect = Class.create();
DeleteRowWithEffect.prototype = {
	initialize: function(sEffect, iDelay, oRow) {
		this.oRow = $(oRow);
		this.sEffect = sEffect;
		setTimeout(this.DoAnimation.bind(this), iDelay * 1000);
	},
	
	DoAnimation:function() {
		if (this.sEffect == "Fade" && TheBrowser.ie) {			
			this.oRow.descendants().each(function(el){
				try {
					Element.show(el); 
					new Effect.Fade(el, {
						duration:0.5
					}); 
				} catch(e) {}
			});
			setTimeout(this.DeleteObject.bind(this), 3000);
		} else {
			this.oRow.visualEffect(this.sEffect, {
				duration:0.5,
				afterFinish:function() {
					//this.oRow.parentNode.removeChild(this.oRow);
					this.DeleteObject.bind(this)
				}.bind(this)
			});
		}
	},
	
	DeleteObject:function() {
		this.oRow.parentNode.removeChild(this.oRow);
	}
};

var iElementCount = 0;
var AddRowWithEffect = Class.create();
AddRowWithEffect.prototype = {
	initialize: function(sEffect, iDelay, oTable, oRow, bDoFlash, sBrokerLogo) {
		if (iDelay == 0)
			iDelay = 1;
		else if (iDelay > 10)
			iDelay = 9 + Math.random(5);
		this.sEffect = sEffect;
		this.oRow = oRow;
		this.bDoFlash = bDoFlash;
		this.sBrokerLogo = sBrokerLogo;

		Element.hide(this.oRow);
		
		var tbody = $(oTable).immediateDescendants();
		tbody = tbody.find(function(elt){return elt.tagName == "TBODY"});
		tbody.appendChild(this.oRow);

		setTimeout(this.DoAnimation.bind(this), iDelay * 1000);		
	},
	
	AppearBrokerLogo: function() {
		new Effect.Appear($(this.sBrokerLogo), {duration:3});
	},
	
	DoAnimation:function() {
		if (this.sEffect == "Appear" && (TheBrowser.ie || TheBrowser.saf)) {
			var oInstance = this;
			var bFirstColumn = true;
			this.oRow.descendants().each(function(el){
				if (bFirstColumn) {
					bFirstColumn = !bFirstColumn;
				} else {
					Element.hide(el); 
					new Effect.Appear(el, {
						duration:2,
						afterFinish:function(effect){ 
							if (this.bDoFlash){
								iElementCount++;
								var id = "td_" + iElementCount;
								try {
									effect.element.update("<div class='HighlightHelper' id='" + id + "'>" + effect.element.innerHTML + "</div>");
									$(id).id_parent = effect.element.id;
									new Effect.Highlight($(id), {startcolor:sHighlightColour_Add, duration:2, afterFinish:function(effect){effect.element.id = effect.element.id_parent}})
								} catch(e){}
							}
						}.bind(oInstance)
					}); 
				}
			}.bind(oInstance));
			this.oRow.show();
		} else {
			if (this.sBrokerLogo)
				setTimeout(this.AppearBrokerLogo.bind(this), 3000);

			this.oRow.visualEffect(this.sEffect, {
				duration:2,
				afterFinish:function(effect){ if(this.bDoFlash){new Effect.Highlight(effect.element, {startcolor:sHighlightColour_Add, duration:2})} }.bind(this)
			});
		}
	}
};


// http://www.mredkj.com/javascript/nfbasic.html
function addCommas(nStr) {
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}


function HighlightPlan(obj, which) {
}


// ------------------------------------------------
// Submit your Details form class
var SubmitDetailsWidget = Class.create();
SubmitDetailsWidget.prototype = {
	initialize: function(oDetailsContainer) {
		this.oDetailsContainer = oDetailsContainer;
		this.oDetailsForm = $(this.oDetailsContainer.descendants().find(function(elt){return elt.id == sPersonalDetailsForm}));
		this.oErrorMessage = $(this.oDetailsContainer.descendants().find(function(elt){return elt.id == sPersonalDetailsErrorMessage}));
		this.oAjaxIndicator = $(sPersonalDetailsAjaxIndicator);
		this.oSubmitButton = $(this.oDetailsContainer.descendants().find(function(elt){return elt.id == sPersonalDetailsSubmitButton}));

		this.handler = this.handleThisEvent.bindAsEventListener(this);
		
		// For every field in this form, bind an event listener.
		this.oDetailsForm.descendants().each(
			function(elt){
				if (elt.id)
					if (elt.id.substr(0,sdbFieldPrefix.length) == sdbFieldPrefix && Element.visible(elt) ) {
						elt.observe('blur', this.handler);
					}
			}.bind(this)
		);
		
		this.bFirstAppForm = true;
	},
	
	handleThisEvent: function(e) {
		var elt = Event.element(e);
		
		//elt is the element that has just blurred.

		sFunction = elt.id + "_OnBlur";		
		var command_str = "if(typeof " + sFunction + " == 'function') " + sFunction + "();";
		eval(command_str);		
				
		return;
	},

	setAssociatedPlansWidget:function(oPlansWidget) {
		this.oPlansWidget = oPlansWidget;
	},
	
	
	ChangePageToPlansMode: function() {
		RecordEvent("ReturnToPlans");
		this.Hide();
		if ($(sAllDone).visible()) $(sAllDone).visualEffect("BlindUp");
		this.oPlansWidget.Show();
	},
	
	
	Show: function() {
		new Effect.BlindDown(sPersonalDetailsAnimation /*sPersonalDetailsSection*/, {duration:3, 
							afterFinish:function(){
								Form.Element.focus("dbfield_firstname");
								this.AdviseWhatToDo();
							}.bind(this) });
	},
	
	Hide: function() {
		oHelp.hide();
		new Effect.BlindUp(sPersonalDetailsAnimation /*sPersonalDetailsSection */, {duration:1});
	},
	
	
	AdviseWhatToDo: function() {
		if (this.bFirstAppForm) {
			this.bFirstAppForm = false;
			oHelp.update("Complete this easy form...");
			oHelp.position($("dbfield_firstname"), "right", 1);
			oHelp.show();
			setTimeout(this.AdviseWhatToDo2.bind(this), 4000);
		}
	},
	
	AdviseWhatToDo2: function() {
		oHelp.update("... when finished click here.");
		oHelp.position($("SubmitForm"), "above", 2);
		setTimeout("oHelp.hide()", 7000);
	},
	
	
	Apply: function(sChoice) {
		this.ClearErrorMessage();
		
		//	MonthlyPayment:25000/60/Paragon Personal/10.0/263/33456
		var myregexp = /(\w+):(\d+)\/(\d+)\/([\w\s]+)\/([\d.]+)\/(\d+)\/(\d+)/;
		var match = myregexp.exec(sChoice);
		if (match != null) {
			$("personaldetails_amount_ro").innerHTML = addCommas(match[2]);
			$("personaldetails_term_ro").innerHTML = match[3];
			$("personaldetails_lender_ro").innerHTML = match[4];
			$("personaldetails_apr_ro").innerHTML = match[5];
			$("personaldetails_monthlypayment_ro").innerHTML = addCommas(match[6]);
			$("personaldetails_totalrepayable_ro").innerHTML = addCommas(match[7]);
	
			$("personaldetails_amount").value = match[2];
			$("personaldetails_term").value = match[3];
			$("personaldetails_lender").value = match[4];
			$("personaldetails_apr").value = match[5];
			$("personaldetails_monthlypayment").value = match[6];
			$("personaldetails_totalrepayable").value = match[7];

			this.Show();
						
		} else {
			alert("Problem - could not determine your chosen deal (debug: [" + sChoice + "]");
		}	
	},
	
	ValidateForm: function() {
		this.oDetailsForm.descendants().each(
			function(elt){
				if (elt.id)
					if (elt.id.substr(0,sdbFieldPrefix.length) == sdbFieldPrefix) {
						sFunction = elt.id + "_OnBlur";
						var command_str = "if(typeof " + sFunction + " == 'function') " + sFunction + "();";
						eval(command_str);
					}
			}.bind(this)
		);
	},
	
	SubmitDetails: function() {
		this.ValidateForm();	
		if (InvalidFields.count != 0) {
			RecordEvent("SubmitPlanFailed_DataIncompete", this.oDetailsForm.serialize());
			alert("Please fix the fields with problems, then try submitting again.");
		} else {
			this.ProcessingIndicator(true);
			setTimeout(this._SubmitDetails.bind(this), 5000);
		}
	},
				
	_SubmitDetails: function() {		
		var params = this.oDetailsForm.serialize();
		RecordEvent("SubmitPlan", params);
		new Ajax.Request('/ajax/Sourcing/SubmitSourcingData.php', {
							  parameters: params,
							  onSuccess:this.SourcingSuccess.bind(this),
							  onComplete:this.SourcingComplete.bind(this)
							  });
	},

	SourcingComplete: function() {
		this.ProcessingIndicator(false);
	},

	SourcingSuccess: function(oAjax, oJSON) {
		if (oAjax.status == 200) {
			var sStatus 			= this.extractStatus(oAjax.responseText);
			var sAccount 			= this.extractAccount(oAjax.responseText);
			var sLoanmakersRef 	= this.extractLoanmakersRef(oAjax.responseText);
			var sXMLStatus 		= this.extractXMLStatus(oAjax.responseText);
			var sXMLError 			= this.extractXMLError(oAjax.responseText);
			
			if (sStatus == gbl_sNoDatabase) {
				RecordEvent("SubmitPlanFailed_Other", gbl_sNoDatabase);
				this.ShowErrorMessage(gbl_sNoDatabase);
				return;
			} else if(sStatus == gbl_sHiccough) {
				RecordEvent("SubmitPlanFailed_Other", gbl_sHiccough);
				this.ShowErrorMessage(gbl_sHiccough);
			} else if(sXMLStatus != "Success") {
				RecordEvent("SubmitPlanFailed_Other", sXMLError);
				debug(oAjax.responseText);
				this.ShowErrorMessage(gbl_sHiccough, sXMLError);
			} else {
				RecordEvent("SubmitPlan_Success", oAjax.responseText);
				$(sShowReference).update(sAccount);
				if (sLoanmakersRef) {
					var sQuote = "... quoting reference number: " + sLoanmakersRef;
					$(sShowLoanmakersRef).update(sQuote);
				}
				this.Hide();
				$(sAllDone).visualEffect("BlindDown");
				// Try sending Analysis signals to the browser (held in /h/new-account/loanspage-new-account-signals.js)
				try { DoSignals(); } catch(e) {}
			}
		}	
		
		/*
				
		SOURCING SUCCESS:-
		Array ( [STATUS] => Success [STATUSCODE] => DNC [CUSTOMERID] => 523422 ) XML data posted to application
		
		*/
		
		
	},
	
	extractLoanmakersRef: function(sText) {
		var myregexp = /\[CUSTOMERID\] => (\w+)/;
		var match = myregexp.exec(sText);
		if (match != null) {
			return match[1];
		} else {
			return "";
		}
	},
	
	extractXMLError: function(sText) {
		var myregexp = /(\[ERROR\] => [\w\s\W]*)/m;
		var match = myregexp.exec(sText);
		if (match != null) {
			return match[1];
		} else {
			return "";
		}		
	},
	
	extractXMLStatus:function(sText) {
		var myregexp = /\[STATUS\] => (\w+)/;
		var match = myregexp.exec(sText);
		if (match != null) {
			return match[1];
		} else {
			return "";
		}
	},


	extractStatus:function(sText) {
		var myregexp = /status: ([\w ]+)/;
		var match = myregexp.exec(sText);
		if (match != null) {
			return match[1];
		} else {
			return "";
		}
	},


	extractAccount:function(sText) {
		var myregexp = /account_code: \[(\w+)\]/;
		var match = myregexp.exec(sText);
		if (match != null) {
			return match[1];
		} else {
			return "";
		}
	},

	ProcessingIndicator: function(bShow) {
		if (bShow) {
			Position.Center(this.oAjaxIndicator /*, this.oDetailsContainer*/);
			this.oSubmitButton.disabled = true;
			this.sFormBackgroundColor = this.oDetailsContainer.style.backgroundColor;
			this.oDetailsContainer.morph({backgroundColor: '#CCCCCC', opacity: '0.5'});
		} else {
			this.oDetailsContainer.morph({backgroundColor: this.sFormBackgroundColor, opacity: '1'});
			delete this.sFormBackgroundColor;
			this.oSubmitButton.disabled = false;
		}

		this.oAjaxIndicator.visualEffect((bShow)?"Appear":"Fade", {queue:{scope:sWorkingIconQ, position:'end'}});
	},
	
	ShowErrorMessage: function(sError, sAdditionalText) {
		var sDisplayError;
		var sDisplaySolution = "We suggest that you wait a couple of minutes and try again.";
		switch(sError) {
			case gbl_sNoDatabase:
				sDisplayError = "we could not connect to the database to process your details.";
				break;
				
			case gbl_sHiccough:
				sDisplayError = "a technical problem occured that we cannot determine at this time. An administrator has been notified of the problem.  We apologise for any inconvenience and advise you to try submitting your application again in about an hour.";
				sDisplaySolution = "";
				if (typeof(sAdditionalText) != "undefined") {
					sDisplayError += "  The error is as follows:-<br><br>" + sAdditionalText;
				}
				break;			
				
			default:
				sDisplayError = sError;
		}
		this.oErrorMessage.update("<strong style='color:red'>There was a problem submitting your enquiry!</strong><br>We apologise for the inconvenience but " + sDisplayError + ". " + sDisplaySolution);
		this.oErrorMessage.visualEffect('BlindDown', {queue:{scope:sErrorQ, position:'end'}});
	},
	
	ClearErrorMessage: function() {
		this.oErrorMessage.visualEffect('BlindUp', {queue:{scope:sErrorQ, position:'end'}});
	}
};


//------------------------------------------------------------
// Error handling

var InvalidFieldsClass = Class.create();
var GoToLoanspage_co_uk = "Please go to <a target=_blank href='http://www.loanspage.co.uk' onclick='return GotoLoanspage_couk()'><span class=Loanspage style='font-style:normal'>Loanspage.co.uk</span></a> for our loan service for";
var hErrorMessages = {	blank: "This field must not be blank",
								nothomeowner: "You must own your own home. " + GoToLoanspage_co_uk + " non-homeowners.",
								passwordsnotequal: "These passwords do not match",
								passwordtooshort: "Minimum password length is 4 characters",
								unemployed: "Only employed may apply for these loan plans. " + GoToLoanspage_co_uk + " unemployed."
							};

InvalidFieldsClass.prototype = {
	initialize: function() {
		// each element of the array means that a field has a problem.
		// {sFieldID:'dbfield_surname', arProblems:[]}
		this.arFields = [];
		this.arFieldBGColor = [];
		this.count = 0;
	},
	
	DisplayErrorMessage:function(sField, sErrorDescription) {
		// If there's already an error section then don't create another one.
		var sError = sField + "_errormessage";
		if (! $(sError)) {
			var oMessage = $(Builder.node('div', {className:'FieldErrorMessage'}));	//, {style:'color:red;fontStyle:italic'}); // document.createTextNode(sErrorDescription); 
			oMessage.id = sError;
			oMessage.update(sErrorDescription);
			$(sField).parentNode.appendChild(oMessage)
		}
	},

	RemoveErrorMessage:function(sFieldID) {
		var sError = sFieldID + "_errormessage";
		if ($(sError))
			$(sError).parentNode.removeChild($(sError));
	},

	Push: function(sFieldID, sErrorDescription) {
		if (typeof this.arFields[sFieldID] == "undefined") {
			this.count++;
			this.arFields[sFieldID] = sErrorDescription;
			if (typeof this.arFieldBGColor[sFieldID] == "undefined")
				this.arFieldBGColor[sFieldID] = $(sFieldID).getStyle('background-color');
			$(sFieldID).style.backgroundColor = "#FFA8A8" ;
			this.DisplayErrorMessage(sFieldID, sErrorDescription);
						
			RecordEvent("DataCheck_Failed", "Field: [" + sFieldID + "], Error: ["+sErrorDescription+"]");
		}
	},

	Remove: function(sFieldID) {
		if (typeof this.arFields[sFieldID] != "undefined") {
			try {
				if (typeof this.arFieldBGColor[sFieldID] != "undefined") {
					$(sFieldID).style.backgroundColor = this.arFieldBGColor[sFieldID];
					delete this.arFieldBGColor[sFieldID]
				}
				this.RemoveErrorMessage(sFieldID);
				delete this.arFields[sFieldID];
			} catch(e) { alert("Exception during Remove.  Error name: '" + e.name + "', Error message: '"+e.message +"'"); }
			this.count--;
		}
	}
};
var InvalidFields = new InvalidFieldsClass;


function IsBlank(sField) {
	if ($(sField).value == "") {
		InvalidFields.Push(sField, hErrorMessages.blank);
		return true;
	} else {
		InvalidFields.Remove(sField);
	}
	return false;
}

function dbfield_firstname_OnBlur() {
	IsBlank("dbfield_firstname");
}
function dbfield_surname_OnBlur() {
	IsBlank("dbfield_surname");
}
function dbfield_telephoneday_OnBlur() {
	IsBlank("dbfield_telephoneday");
}
function dbfield_email_OnBlur() {
	IsBlank("dbfield_email");
}
function dbfield_address_OnBlur() {
	IsBlank("dbfield_address");
}
function dbfield_city_OnBlur() {
	IsBlank("dbfield_city");
}
function dbfield_postcode_OnBlur() {
	IsBlank("dbfield_postcode");
}

function ToNumber(v) {
	var nv = "";
	for (i = 0;  i < v.length;  i++) {
		var ch = v.charAt(i);
		if ( (ch >= "0" && ch <= "9") ||  ch == ".")
			nv = nv + "" + ch;
	}
	return nv;
}

function GotoLoanspage_couk() {
	var sRedirectURL = "https://secure.loanspage.co.uk/h/loanspage-newaccount.php?lpredir=1&" + $(sPersonalDetailsForm).serialize();
	var C = getCookie(sTrackerCookie);
	if (C) 
		location.href = "https://secure.loanspage.co.uk/cgi-bin/lp-redirect.pl?t=" + C + "&p=" + encodeURIComponent(sRedirectURL);
	else 
		location.href = sRedirectURL;

	return false;
}
function CloseAlert() {
	oScreenAlert.ClearAlert();
	oScreenAlert = null;
	return false;
}
function DoScreenAlert(param_Criteria, param_sExplanation) {
	if (!oScreenAlert) {
		oScreenAlert = new ScreenAlertWidget({sAlertText:"Would you like to use our loan finding service<br>for " + param_Criteria + "?", sAlertExplanation:param_sExplanation, funcYes:GotoLoanspage_couk, funcNo:CloseAlert});		
	}
}
function dbfield_totalincome_OnBlur() {
	var sField = "dbfield_totalincome";
	if (!IsBlank(sField)) {
		$(sField).value = ToNumber($(sField).value);
	}
}
function dbfield_homeowner_OnBlur() {
	var sField = "dbfield_homeowner";
	var value = $F($(sField));
	if (value != "Yes") {
		DoScreenAlert("non-homeowners", "You have told us that you do not own your home.  We suggest we transfer your details over to our free loan service for non-homeowners.");
		InvalidFields.Push(sField, hErrorMessages.nothomeowner);
	} else
		InvalidFields.Remove(sField);
}

function dbfield_maritalstatus_OnBlur() {
	var sField = "dbfield_maritalstatus";
	var obj = $(sField);
	if ($F(obj) == "") {
		InvalidFields.Push(sField, hErrorMessages.blank);
	} else {
		InvalidFields.Remove(sField);
	}
}

// Misc
function dbfield_Title_genderChange() {
	var Chosen = false;
	if ( ["Mr"].find(function(el){return el == $("dbfield_title").value}) ) {
		$("dbfield_gender").selectedIndex = 0;
		Chosen = true;
	} else if ( ["Mrs", "Miss", "Ms"].find(function(el){return el == $("dbfield_title").value}) ) {
		$("dbfield_gender").selectedIndex = 1;
		Chosen = true;
	}	
	["dbfield_gender", "fieldtitle_gender"].each(function(el){
		if (Chosen) {
			if ($(el).visible()) $(el).hide()
		} else {			
			if (!$(el).visible()) {
				$(el).show();
				$(el).visualEffect("Highlight");
			}
		}
	});

	return true;
}


function PasswordsCheck() {
	var sFields = new Array("dbfield_password", "dbfield_password2");
	var sCompareField = {dbfield_password: "dbfield_password2", dbfield_password2: "dbfield_password"};
	sFields.each(
		function (sField) {
			if (!IsBlank(sField)) {
				if ($(sField).value.length < 4) {
					InvalidFields.Push(sField, hErrorMessages.passwordtooshort);
				} else {
					if ($(sField).value != $(sCompareField[sField]).value) {
						InvalidFields.Push(sField, hErrorMessages.passwordsnotequal);
					} else {
						InvalidFields.Remove(sField);
					}
				}
			}
		}
	);
}

function dbfield_password_OnBlur() {
	PasswordsCheck();
}
function dbfield_password2_OnBlur() {
	PasswordsCheck();
}


function dbfield_employment_OnBlur() {
	var sField = "dbfield_employment";
	if ($(sField).value == "Unemployed" || $(sField).value == 0) {
		InvalidFields.Push(sField, hErrorMessages.unemployed);
		DoScreenAlert("unemployed","You have told us that you are unemployed.  We suggest we transfer your details over to our free loan service for <u>unemployed</u>.");
	} else {
		InvalidFields.Remove(sField);
	}
}



function debug(x) {
	var el = "debug";
	$(el).update(x);
	Element.show(el);
}
function debugIfMe(x) {
	var C = getCookie(sTrackerCookie);
	if (C == "200371516175971") 
		debug(x);
}
function Random(mn, mx) {
	//return Math.round(100*Math.random())	
	return Math.random() * (mx - mn) + mn;
	//return Math.floor(Math.random() * (mx - mn + 1)) + mn;
}

/**
	http://aaron.xavisys.com/using-prototype-javascript-to-get-the-value-of-a-radio-group/
 * Returns the value of the selected radio button in the radio group, null if
 * none are selected, and false if the button group doesn't exist
 *
 * @param {radio Object} or {radio id} el
 * OR
 * @param {form Object} or {form id} el
 * @param {radio group name} radioGroup
 */
function $RF(el, radioGroup) {
    if($(el).type && $(el).type.toLowerCase() == 'radio') {
        var radioGroup = $(el).name;
        var el = $(el).form;
    } else if ($(el).tagName.toLowerCase() != 'form') {
        return false;
    }
 
    var checked = $(el).getInputs('radio', radioGroup).find(
        function(re) {return re.checked;}
    );
    return (checked) ? $F(checked) : null;
}

// **  Login
function Login_OpenLoginBox() {
	RecordEvent("LoginOpen");
	$("LoginLink").hide();
	$("LoginWho").hide();
	new Effect.BlindDown($("LoginBox"), {afterFinish:function(){Form.Element.focus("Login_name")}});
}
function Login_Cancel() {
	RecordEvent("LoginCancel");
	_Login_Close();
}
function Login_Close() {
	RecordEvent("LoginClose");
	_Login_Close();
}
function _Login_Close() {
	$("LoginError").update("");
	new Effect.BlindUp($("LoginBox"), {afterFinish:function(){$("LoginLink").show(); $("LoginWho").show();} });
}
var jsonLoginData;
var jsonLoginError;
function Login_Submit() {
	// Login_password
	// Login_name
	
	jsonLoginData = null;
	jsonLoginError = null;
	$("LoginWho").update("");
	new Ajax.Request('/ajax/Sourcing/SourcingLogin.php', {
					  parameters: $("loginform").serialize(),
					  onSuccess:Login_AJAXSuccess,
					  onComplete:Login_AJAXComplete
					  });			

}

function Login_AJAXComplete() {
	if (jsonLoginError) {
		$("LoginError").update(jsonLoginError);
		RecordEvent("LoginFailed",$("loginform").serialize());
	} else if (jsonLoginData) {
		// Put all the data into the form;
		$H(jsonLoginData).each(
			 function(el) {
 				 if (el.key == "tracker") {
					 SetOurCookie(el.value);	// dof.tracker.js
				 } else {
					 try {
						switch ($(el.key).type) {
							case "select-one":
							case "radio":
								var A = $A($(el.key).options);
								var O = A.find( function(option){
													 var OptionText;
													 if (TheBrowser.ie) {
														 OptionText = option.text;
													 } else {
														OptionText = option.value;
													 }
													 return (OptionText == el.value);
								});
								try {
									$(el.key).selectedIndex = O.index;
								} catch (e) {}
								break;
							default: $(el.key).value = el.value;	break;
						}
						var sFunction = el.key + "_OnBlur";		
						var command_str = "if(typeof " + sFunction + " == 'function') " + sFunction + "();";
						eval(command_str);		
					 } catch(e) {}
				 }
			 } 
		);
		$("LoginWho").update("Welcome back " + jsonLoginData.dbfield_title + " " + jsonLoginData.dbfield_surname + ".");
		$("LoginError").update("Your details are now loaded into the application form.");
		RecordEvent("LoginSuccess",$("loginform").serialize());
		setTimeout(Login_Close, 5000);
	}
}
function Login_AJAXSuccess(oAjax, oJSON) {
	var isError = false;
	if (oAjax.status == 200) {
		var myregexp = /ERROR: (.*)/;
		var match = myregexp.exec(oAjax.responseText);
		if (match != null) {
			jsonLoginError = match[1];
		} else {
			try {
				eval("jsonLoginData = " + oAjax.responseText);
			} catch(e) {}
		}
	}
}

// Event tracking...
function RecordEvent(sEvType, sAdditional) {
	var sURL = '/ajax/Sourcing/SourcingEvent.php?e='+ sEvType;
	if (sAdditional) {
		sURL += "&A=" + encodeURIComponent(sAdditional);
		//alert(encodeURIComponent(sAdditional));
	}
	new Ajax.Request(sURL);
}

// Helper Functions
function CloseHelp() {
	if (oSourcingPlans.bFirstSearch)
		oSourcingPlans.bFirstSearch = false;
	else if(oSourcingPlans.bFirstPlanSelect)
		oSourcingPlans.bFirstPlanSelect = false;
	oHelp.hide();
}

// Prototype.js extensions...

Position.Center = function(element, parent) {
	var w, h, pw, ph;
	var d = Element.getDimensions(element);
	w = d.width;
	h = d.height;
	Position.prepare();
	if (!parent) {
		var ws = Position.GetWindowSize();
		pw = ws[0];
		ph = ws[1];
	} else {
		pw = parent.offsetWidth;
		ph = parent.offsetHeight;
	}
	element.style.top = (ph/2) - (h/2) /*-  Position.deltaY */ + "px";
	element.style.left = (pw/2) - (w/2) /* -  Position.deltaX */ + "px";
	}

Position.GetWindowSize = function(w) {
	w = w ? w : window;
	var width = w.innerWidth || (w.document.documentElement.clientWidth || w.document.body.clientWidth);
	var height = w.innerHeight || (w.document.documentElement.clientHeight || w.document.body.clientHeight);
	return [width, height]
}


function DoCurves() {
	var leaf_settings = {
		 tl: { radius: 16 },
		 tr: false,
		 bl: false,
		 br: { radius: 16 },
		 antiAlias: true,
		 autoPad: true
	}

	var leaf_smaller_settings = {
		 tl: { radius: 8 },
		 tr: false,
		 bl: false,
		 br: { radius: 8 },
		 antiAlias: true,
		 autoPad: true
	}

	$A(["navigation_warning", "PlansBorder", "LoginBox"]).each(function(el){new curvyCorners(leaf_smaller_settings, $(el)).applyCornersToAll()});
	$A(["AllDone", "ProcessingIndicator", "PersonalDetails"]).each(function(el){new curvyCorners(leaf_settings, $(el)).applyCornersToAll()});

}

/**
 * Start
 *
 */
 
 	// Keep these values global...
	var oSourcingPlans;
	var oSubmitDetails;
	var oHelp;


	function Begin() {	
	
		//setTimeout(DoCurves, 500);
		DoCurves();
		
		oHelp = new HelpBubbleWidget("HelpBubble");	
		oSubmitDetails = new SubmitDetailsWidget($("PersonalDetails"));
		oSourcingPlans = new SourcingTableWidget($("plans_table"), oSubmitDetails);
		oSubmitDetails.setAssociatedPlansWidget(oSourcingPlans);
		
		//oSourcingPlans.Startup();

		setTimeout(oSourcingPlans.Startup.bind(oSourcingPlans), 2000);
	}

