﻿var GeneratedForm=new Class({
	options:{
		/*
		onInitialize:$empty,
		onSending:$empty,
		onSent:$empty,
		onValidating:$empty, // before client validation
		onValidated:$empty, // after client validation
		onValidate:$empty // server validations, after client validation
		*/
	},

	Implements:[Options,Events],

	initialize:function (form,options) {
		this.form=$(form);
		this.setOptions(options);

		this._initValidator();
		this.form.addReplacingEvent("submit",this.onSubmit.bind(this));
		this.form.set("send",{			url:this.form.action,			onComplete:this.onComplete.bind(this),			onFailure:$ajaxFailure,
			evalScripts:true
		});				this._enableSubmit();
		
		this.initUploadFiles();		this.fireEvent("onInitialize");	},
	
	toElement:function () {
		return this.form;
	},
	
	_steps:[],

	_initValidator:function () {
		$waitUntil(function () {
			//console.log('val='+this.form);
			return !!this.form && typeof(FormValidator)!="undefined";
		}.bind(this),function () {
			//console.log('this.validator');
			this.validator=new FormValidator(this.form,{
				errorPrefix:"",
				warningPrefix:"",
				useTitles:true,
				evaluateOnSubmit:false // we'll be checking this on submit ourselves
			});
		}.bind(this));
	},

	onSubmit:function (event) {
		this._disableSubmit();

		// eValidate.isValid could be changed thru the server validators' callbacks
		var eValidate={validatorsChain:new Chain(),isValid:true};

		this.fireEvent("onValidating",[eValidate]); // before client validation

		// client validations
		var isValid=eValidate.isValid && this.validator.validate(event);

		this.fireEvent("onValidated", isValid); // after client validation

		if (!isValid) {
			this._enableSubmit();
			return; // the validator will handle errors
		}

		// server/async validations

		/* in this event, developer can add more server validations
		example:
		onValidate:function (e) {
			e.validatorsChain.chain(function () {
				if (!e.isValid) return e.validatorsChain.callChain();
				var userName=$("Email").value;
				WS.IsUserNameValid(userName,function (valid) {
					if (!valid) {
						alert("Email address already exists.");
						e.isValid=false;
					}
					e.validatorsChain.callChain(); // notice this!
				});
			}.bind(this));
		}
		*/

		this.fireEvent("onValidate",[eValidate]); // server validations, after client validation
		
		if (isValid) this.checkUploadFilesOnSubmit(eValidate);
		
		// adds a final function to run after all async validators
		// that actually sends the form
		eValidate.validatorsChain.chain(function () {
			var e={cancel:false};

			// e could be set with .cancel=true and the operation will be aborted
			this.fireEvent("onSending",[e]);

			// isValid - client side validation
			// eValidate.isValid - custom/async validation
			// e.cancel - custom canceling from onSending
			if (isValid && eValidate.isValid && !e.cancel) {
				this.form.send();			}			else {				this._enableSubmit(); // re-enable the submit buttons cause the validatation didn't pass			}		}.bind(this));		// start		eValidate.validatorsChain.callChain();	},
	onComplete:function (response) {
		response=JSON.decode(response);
	
		if (response.RedirectUrl) {
			location.href=response.RedirectUrl;
			return;
		}

		if (response.Errors && Hash.getLength(response.Errors)>0) {
			this.applyErrorMessages(response.Errors);
			this._enableSubmit();
			return;
		}

		var e={html:response.ResponseHtml};
		this.fireEvent("onSent",[e]);
		if (!e.cancel) {
			this.form.setHTML(e.html);
		}
		
		this._enableSubmit();
	},
	
	_getSubmitButtons:function () {
		return this._submitButtons || (this._submitButtons=this.form.getElements("input[type='submit']"));
	},
	_disableSubmit:function () {
		this._getSubmitButtons().set("disabled",true);
	},
	_enableSubmit:function () {
		this._getSubmitButtons().set("disabled",false);
	},
	
	__files:[],
	
	initUploadFiles:function () {
		var files=this.form.getElements(".swf-upload");
		if (files.length) $waitUntil(function () {
			return typeof(FancyUpload2)!="undefined" && typeof(Swiff.Uploader)!="undefined" && typeof(Fx.ProgressBar)!="undefined";
		},function () {
			var uploaders=[];
			files.each(function	(file) {
				var container=file.getParent(".file-upload");

				var displayName=container.getElement(".file-display-name");
				var fileName=container.getElement(".file-name");

				var uploader=new FancyUpload2(container.getElement('.file-status'),container.getElement('.file-list'),{
					path:PATH_SWF_UPLOAD,
					url:Config.rootUrl+'FormGenerator/UploadHandler.ashx',
					fieldName:file.name,
					limitSize:1000000,
					limitFiles:1,
					multiple:false,
					onLoad:function () { file.hide(); },
					onSelect:function (selectedFile) {
						displayName.set("value",selectedFile.name);
						this.hasFiles=true;
					},
					target:container.getElement(".browse-button"),
					debug:true
				});
				
				uploaders.push(uploader);
				file.store('uploader',uploader).store('fileName',fileName);
				this.__files.push(file);
			},this);

			uploaders.each(function (uploader) {
				(function () { if (uploader.target) uploader.reposition(); }).periodical(250);
			});
		}.bind(this));
	},
	checkUploadFilesOnSubmit:function (e) {
		if (!e.isValid) return;
		if (!this.__files.length) return;
		this.__files.each(function (file) {
			e.validatorsChain.chain(function () {
				var uploader=file.retrieve("uploader");
				var fileName=file.retrieve("fileName");
				if (!uploader || !uploader.hasFiles) e.validatorsChain.callChain();
				else {
					uploader.addEvent("complete",function (fileData,responseData) {
						if ($type(responseData)=="string") responseData=JSON.decode(responseData);
						fileName.set("value",responseData.fileName);
						e.validatorsChain.callChain();
					});
					uploader.upload();
				}
			});
		});
	},
	showError:function (field,errorMsg,className) {
		className=className || "custom";
		var advice=this.validator.makeAdvice(className,field,errorMsg);
		this.validator.insertAdvice(advice,field);
		this.validator.showAdvice(className,field);
	},
	applyErrorMessages:function (errors) {
		Hash.each(errors,function (errorMsgs,fieldName) {
			var field=this.form[fieldName] || this.form;
			errorMsgs.each(function (errorMsg) {
				this.showError(field,errorMsg,"server");
			},this);
		},this);
	}
});
$extend(GeneratedForm,{
	create:function (codeName) {
		// tries to find the form class, such as ContactUsForm, in order to extend options
		var formClass=window[codeName+"Form"] || GeneratedForm;

		new formClass("fg-form-"+codeName);
	}
});