/**
 * @author Barrington Henry
 */

/**
 * script taken from mozilla development
 * @param {Object} fun
 * @param {Object}  thisp
 * 
 */
if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
      {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }

    return res;
  };
}

var GM_Validation = Class.create();
GM_Validation.prototype = {
	tipHTMLOLD:'<div class="{TIP_TYPE} tip-container">'+
				'<div style="vertical-align:middle;margin:0;padding:0">'+
					'<div style="max-width:250px;">{CONTENT}'+
					'</div>'+
				'</div>'+
			'</div>',
	tipHTML:'<div class="tip-container {TIP_TYPE}">' +
				'<table>' + 
					'<tr>'+
						'<td style="vertical-align:middle">{CONTENT}</td>'+
					'</tr>'+
				'</table>'+
			'</div>',
	validationdefinitions:{
		'checked':['This must be checked to continue.','client', function(v,elem) {
                return elem.checked;
			}],
		'required':['This is a required field.','client', function(v) {
				return !v.blank();
			}],
		'validate-isexist':['sdasd','server', function(v, elem) {
				inputObj = {
					typeexist:elem.identify(), 
					value:v
				};
				this.ajaxInProgress = true;
				this.doAlert('progress', elem, 'checking availability...');
				var processInfo = new AJAXgetinfo('checkexistence',{source:'/gmasync/utils'},{pars:inputObj});
				AJAXgetinfo.addMethods({
					afterProcess:function(transport){
						var response = transport.responseText;
						var jsoneval = response.evalJSON();	
						var keywordHint = jsoneval.fullhtml;
					
						this.error = keywordHint;
						this.validationdefinitions['validate-isexist'][0] = keywordHint;

						if(jsoneval.resp == 'exists'){
							this.ajaxInProgress = false;							
							this.ajaxresults.set(elem.identify(), false);
							
						}else{
							this.ajaxInProgress = false;
							this.ajaxresults.set(elem.identify(), true);				
						}
					}.bind(this)
				});
				processInfo.getinfoGen2();
				return false;
		}],
		'validate-email': ['Please enter a valid email address.','', function (v) {
				return  /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/.test(v)
			}],
		'no-space':['Spaces are not permitted here.', '', function(v){
			return !/\s/.test(v);	
		}],
		'number-chars-6-15':['Must have 6 - 15 characters.', '',function(v){
			if(v.length < 6 || v.length > 15){
				return false
			}else{
				return true
			}
		}],
		'pass-confirm': ['Please verify password.', 'client', function(v, elem) {
			return Form.getInputs(this.form, 'password').all(function(n){
				var str = n.value
				
				if(!str.blank()){
					return (str == v);
				}
			});		
		}]
	},
	tipdefinition:{
		'email_address':['We will never, ever share your email address. Your email will be used for signing into your account or in case you forget your password. '],
		'username':['Create your unique Mojo user name (no spaces please).'],
		'password':['6 to 15 characters (no spaced please). If you forget, don\'t worry, we\'ll email it to you'],
		'confirm_password':['Re-enter the same password'],
        'tos':['You must agree to the Terms of Service to continue.']
	},
	elem_validator_key:'elem_validators',
	activevalidatedef:'present',
	element_value_cache_id:'cacheid',
	tooltip_status_id:'barstatusid',
	tipclass:'tip',
	intervalmappings:$H(),
	ajaxresults:$H(),
	validatedElements:[],
    approvedElements:$H(),
    whoToValidate:[],
    initialize : function(form, options){
		this.options = Object.extend({
			onSubmit : true,
			stopOnFirst : false,
			ajaxInProgress:false,
			clearErrors : true,
			immediate : false,
			focusOnError : true,
			useTitles : false,
			messageOverlibInset:'immediateancestor',
			onFormValidate : function(result, form) {},
			onElementValidate : function(result, elm) {},
			onSubmitLogic:null,
			preloadErrors:'',
			tipAlgo:function(){},
			changeDefaultAnchorPosition:false,
			defaultAnchorPosition:{},
            additionalFieldsToValidateOnSubmit:[]
		}, options || {});
		this.form = $(form);
		
		if(this.form == null){
			return;
		}
		
		if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false);	
		this.overlib = new GM_overlib({insertinto:this.options.messageOverlibInset});
		
		if(this.options.immediate) {
			
			if(this.options.preloadErrors !== undefined){
				this.preloadOperation.call(this);
			}	
			
			Form.getElements(this.form).each(function(input) {
				var cn = input.classNames();
				
				var valid_validators = $A(cn).filter(this.isAValidator.bind(this));	
				
				
				if(valid_validators.size() > 0){
					input.store(this.elem_validator_key, valid_validators);
					Event.observe(input, 'blur', function(ev) { 
												this.validate(input); 												
											}.bind(this));
                    if(input.hasClassName('checked'))
                        Event.observe(input, 'click', function(ev) {
                            this.validate(input);
                        }.bind(this));
                    this.whoToValidate.push(input.id);
				}
				
				if(input.hasClassName(this.tipclass)){
					Event.observe(input, 'focus', function(ev) { 
							this.showTip(input); 												
						}.bind(this));
				}
			}.bind(this));
		}
	},
    onSubmit:function(ev){
        this.options.additionalFieldsToValidateOnSubmit.each(function(f){
            this.validate($(f));
        }.bind(this));
        
        if(this.whoToValidate.length!=this.approvedElements.values().length)
            ev.stop();
        if(this.options.onSubmitLogic !== null && typeof this.options.onSubmitLogic == 'function')
        	this.options.onSubmitLogic.call(this);
        else return true;
    },
	validate:function(input){		
		var definitions = $A(input.retrieve(this.elem_validator_key));
		var v = input.value;
		var valuecache = input.retrieve(this.element_value_cache_id);
		
		this.validatedElements.push(input);
	
		if(valuecache != undefined && !input.hasClassName("checked")){
			if(valuecache == v){
				return;
			}
		}
		
		var result = definitions.all(function(defs){
			input.store(this.activevalidatedef, defs);
			return this.validationdefinitions[defs][2].apply(this, [v, input]);
		}.bind(this));
				
		if(!this.ajaxInProgress){
			this.processAlert.apply(this, [result, input]);
		}else{
			var interval = window.setInterval(function(){
						if(!this.ajaxInProgress){
							var result = this.ajaxresults.get(input.identify());
							this.processAlert.apply(this, [result, input]);
							window.clearInterval(this.intervalmappings.get(input.identify()));
						}
				}.bind(this), 100);
				this.intervalmappings.set(input.identify(), interval);			
		}
		
		input.store(this.element_value_cache_id, v);
        return result;
	},
	showTip:function(element){
		
		if(this.options.tipAlgo != undefined && typeof this.options.tipAlgo == 'function'){
			this.options.tipAlgo.apply(this, [element]);	
		}else{
			throw new TypeError();
		}
	},
	
	isAValidator:function(element, index, array){
		return !Object.isUndefined(this.validationdefinitions[element]);
	},
	requestTip:function(element){
		
	},
	doAlert:function(type,input, message){
		var anchorelem = null;
		
		if (this.options.changeDefaultAnchorPosition) {
			input.siblings().each(function(elem){
				if ((this.options.defaultAnchorPosition.posclass != undefined) && 
					elem.hasClassName(this.options.defaultAnchorPosition.posclass)) {
					anchorelem = elem;
				}
			}.bind(this));
		}else{
			anchorelem = input;
		}
		
		this.overlib.generateoverlib({},
			{	bubbleselect:type, 
				innercontent:message, 
				elem:anchorelem, 
				bubbleidpostfix:anchorelem.identify(),
				regex:anchorelem.identify(),
				margincumul:24,
				anchorY:2
			}
		);	
	},
    doTextAlert:function(type, input, message){
        $(input.id+"_message").update(message);
    },
	processAlert:function(result, input){
		if(!result){
			presentdefinition = input.retrieve(this.activevalidatedef);
			input.store(this.tooltip_status_id, true);
			
			message = this.validationdefinitions[presentdefinition][0];
			var finalValue = this.getTipMarkup(message, 'validation-err');

            if(input.hasClassName('checked'))
                this.doTextAlert('', input, message);
			else
                this.doAlert('anchor', input, finalValue);
            this.approvedElements.unset(input.id);
		}else{
			var finalValue = this.getTipMarkup('ok', 'validation-ok');
            if(input.hasClassName('checked'))
                this.doTextAlert('', input, '');
			else this.doAlert('anchor', input, finalValue);
            this.approvedElements.set(input.id, true);
		}
		
		this.removeRadiusRight(input);
	},
	getTipMarkup:function(message, type, tipHTMLString){
		var tipHTML = this.tipHTML || tipHTMLString;
		var markup = tipHTML.replace(/{CONTENT}/g, message);
		var finalvalue = markup.replace(/{TIP_TYPE}/g, type);
		
		return finalvalue;
	},
	refresh:function(){
		this.validatedElements.each(function(elements){
			elements.store(this.element_value_cache_id, '__this_has_been_deactivated__');
		}.bind(this));
		
		this.overlib.refresh();
		this.validatedElements = [];
	},
	preloadOperation:function(){
		if(typeof this.options.preloadErrors == 'string'){
			if(this.options.preloadErrors.isJSON()){
				var errors = this.options.preloadErrors.evalJSON();
			}
		}else if(typeof this.options.preloadErrors == 'object'){
			var errors = this.options.preloadErrors;
		}					
					
		$A(errors).each(function(elem){
			var final = this.getTipMarkup(elem.errtext.first(), 'validation-err');
			this.removeRadiusRight( $(elem.field) );

            if($(elem.field).hasClassName('checked'))
                this.doTextAlert('', $(elem.field), elem.errtext.first());
            else
                this.doAlert('anchor', $(elem.field), final);
		}.bind(this));	
	},
	removeRadiusRight:function(input){
		Element.setStyle(input, {
			'webkitBorderTopRightRadius':'0px',
			'webkitBorderBottomRightRadius':'0px',
			'MozBorderRadiusTopright':'0px',
			'MozBorderRadiusBottomright':'0px',
			'borderTopRightRadius':'0px',
			'borderBottomRightRadius':'0px'
		});
	},
	setRadiusRight:function(input){
		Element.setStyle(input, {
			'webkitBorderTopRightRadius':'5px',
			'webkitBorderBottomRightRadius':'5px',
			'MozBorderRadiusTopright':'5px',
			'MozBorderRadiusBottomright':'5px',
			'borderTopRightRadius':'5px',
			'borderBottomRightRadius':'5px'
		});
	}
}
