/**
 * Validates known tag contents
 * 
 * @author Angelo Selvini <angelo@exmachina.ch>
 * @requires ch.exmachina.bravofly.ui.Pager
 * @requires ch.exmachina.bravofly.utils
 */


if(!ch){
	var ch = {};
}
if(!ch.exmachina){
	ch.exmachina = {};
}
if(!ch.exmachina.bravofly){
	ch.exmachina.bravofly = {};
}
if(!ch.exmachina.bravofly.ui){
	ch.exmachina.bravofly.ui = {};
}

ch.exmachina.bravofly.ui.Validator = function(/* object */ ctorArgs){
	var t;

	this.target = t = ctorArgs["target"];
	if (!t || !t.nodeType || t.nodeType != 1)
		throw new Error("Validator requires target");

	// defaults
	this.name      = t.getAttribute("bf:name") || ctorArgs["name"]   || "validatorWidget"+parseInt(Math.random()*1000);
	this.listening = false;

	this.options   =
	{ message    : t.getAttribute("bf:message")     || "Error."
	, must       : t.getAttribute("bf:must")        == "true" ? true : false
	, listen     : t.getAttribute("bf:listen")      == "false" ? false : true
	, showMessage: t.getAttribute("bf:showMessage") == "false" ? false : true
	};

	this.rule   = t.getAttribute("bf:rule")  || null;
	this.group  = t.getAttribute("bf:group") || null;
	this.regexp = /.+/;
};

ch.exmachina.bravofly.ui.Validator.prototype = {

	type: "ch.exmachina.bravofly.ui.Validator",

	_listening: false,

	group  : null,
	regexp : null,

	params : null,
	target : null,
	options: null,

	setOptions: function(/* object */ o){
		if (!o) return;

		var i = 0,
			c = this.options,
			l = [ { type:"s", name:"message"}
				, { type:"s", name:"rule"   }
				, { type:"s", name:"group"   }
				]
		;

		c = ch.exmachina.bravofly.utils.validateOptions(
				{ optsNew: o
				, optsOld: c
				, rules: l
				}
			);
	},

	setParams: function(/* object */ p){
		if (p.rule){
			this.rule = p.rule;
			this._setRule();
		}
	},

	// DOM
	create: function(){
		// summary: setup input
		var e,
			C = this.getConstants(), 
			t = this.target
		;
		if (!this._isTag()) return;
		this._setRule();
	},

	_setRule: function(){
		var re = this.regexp,
			r = this.rule,
			C = this.getConstants()
		;

		switch(r){
			case null:
				re = /.*/;
				break;
			case C.EMAIL:
				re = /^([A-Za-z0-9\._]\.?)+@(\w\.?)+(\.\w{2,4})$/i;
				break;
			case C.PHONE:
				re = /^\+?(\d+(\.|\s|-)?)+$/;
				break;
			case C.NUMBERS:
				re = /^\d+$/;
				break;
			case C.WORDS:
				re = /^\D+$/;
				break;
			default:
				re = new RegExp(r);
				break;
		}
		this.regexp = re;
	},

	draw: function(){
		// summary: evaluate template with parameters
	},

	update: function(){
	},

	validate: function(e){
		// summary: evaluates conditions
		var r, v,
			o  = this.options,
			t  = this.target,
			nn = t.nodeName
		;
		v = this._getValByNodeName(nn)

		// Check if compulsory
		if (o.must && (v==null || v=="" || v==undefined)){
			r = false

		// Check if matches
		} else if (v) {
			r = this.regexp.test(v);

		// Don't mind value
		} else {
			r = true

		}
		
		this._manageClass(r);
		this._manageMessage(!r && o.showMessage);

		return r;
	},

	hasGroup: function(){
		return this.group; 
	},

	setListening: function(/* boolean */ b){
		if (b && !this._listening)
			this._addListeners();
		else if (!b)
			this._removeListeners();
	},

	_addListeners: function(){
		var o  = this.options,
			t  = $(this.target),
			nn = t.nodeName
		;
		this._listening = true;

		if (o.listen && /INPUT/.test(nn))
			t.observe("blur", this.delegate(this, this.validate));
	},

	_removeListeners: function(){
		var t = $(this.target);
		this._listening = false;

		t.stopObserving("blur");
	},

	_manageMessage: function(/* boolean */ b){
		b ?  this._addError() : this._hideError();
	},

	_addError: function(){
		var e = this.error
		;
		if (e){
			e.setStyle({display:""});
		} else {
			var d,
				t = this.target,
				C = this.getConstants()
			;
			d = document.createElement("div");
			$(d).addClassName(C.CLASS_ERROR_MESSAGE);
			d.innerHTML = this.options.message;

			e = this.error = $(d);

			if (this.hasParentNode(t))
				t.parentNode.insertBefore(e,t);
		}
	},

	_hideError: function(){
		var e = this.error
		;
		if (e)
			e.setStyle({display:"none"});
	},

	_removeError: function(){
		var e = this.error
		;
		if (e && this.hasParentNode(e))
			e.parentNode.removeChild(e);
	},

	_getValByNodeName: function(/* string */ n){
		var v;
		switch(n){
			case "INPUT": v=this.target.value; break;
		}
		return v;
	},
	setValue: function(/* object */ v){
		var t = this.target,
			n = t.nodeName
		;
		switch(n){
			case "INPUT": 
				t.value=v; 
				break;
		}
		return v;
	
	},

	_manageClass: function(/* boolean */b){
		// summary: add/remove error class name
		var t = $(this.target),
			c = this.getConstants()["CLASS_ERROR"]
		;

		if (b && t.hasClassName(c))
			t.removeClassName(c);
		else if (!b)
			t.addClassName(c);
	},

	_isTag: function(){
		return /INPUT/.test(this.target.nodeName)
	},

	_getValue: function(){
		var v,
			t = this.target
		;
		switch (t.nodeName){
			case "INPUT":
				v = t.value;
				break;
		}
		return v;
	},

	isEmpty: function(){
		var t = this.target,
			v = this._getValue()
		;
		return (v!=undefined && v!=null && v!="") ? false : true;
	},

	getNode: function(){
		return this.target;
	},

	getType: function(){
		return this.type;
	},

	destroy: function(){
		var p = this.pagers
		;

		this.setListening(false);
		this._manageClass(false);
		this._manageMessage(false);
	},

	getConstants: function(){
		return window.ch.exmachina.bravofly.ui.Validator.getConstants();
	},

	hasParentNode: ch.exmachina.bravofly.utils.hasParentNode,
	delegate: ch.exmachina.bravofly.utils.delegate
};

ch.exmachina.bravofly.ui.Validator.getConstants = function() {
	var cnst =
	{ EMAIL: "email"
	, PHONE: "phone"
	, WORDS: "words"
	, NUMBERS: "numbers"
	, CLASS_ERROR: "vg_vldError"
	, CLASS_ERROR_MESSAGE: "vg_vldErrorMsg"
	};
	return cnst;
};

