//| validator.js
//| 
//| @AUTH      Nully
//| @COPYRIGHT magical-remix&Co.
//| @URL       http://magical-remix.co.jp
//| @SINCE     2008-2009
//| @LICENSE   MIT
//| 
//| 
//| 
////////////////////////////////////////////////////////////////////////////////
var validate = {
	check : function(targ){
		var error = false ; // check error flags.
		var val = targ.value ? targ.value : null ;
		var rel = targ.getAttribute("rel") ? targ.getAttribute("rel") : null ;
		var rels = null ;
		if(rel === null)
			return ;
		
		
		rels = rel.split(" ") ;
		var j = 0;
		for(var i = 0; i < rels.length; i++) {
			if( val === null || this.rule[rels[i]](val) == false ) {
				error = true ;
				this.addClass( targ, "validError" ) ;
				break ;
			} else {
				this.removeClass( targ, "validError" );
			}
		}
		
		
		// エラーがあればポップアップ（吹き出し）を表示
		if( error == true ){
			this.popup.open(targ, this.errorMsg[rels[i]]) ;
		}
	},
	
	// 送信時にチェック
	submit : function(form) {
		// すべてのポップアップを閉じます
		this.allClose(form);
		
		// onbulrがあるならフォーカスを外した事にします
		for( var i = 0, f; f = form[i]; i ++ ) {
			if( f.onblur ) {
				f.onblur() ;
			}
		}
		
		// フォーム要素のポップアップのstyle属性がdisplay:noneじゃなければエラ表示
		for ( var i = 0,f; f = form[i]; i++ ) {
			if(f._popup && !f._popup.isVisible()){
				return false ;
			}
		}
		
		return true ;
	},
	allClose : function(form){
		for( var i = 0,f; f = form[i]; i++ ) {
			if(f._popup == undefined) {
				this.check(f);
			}
		}
		return ;
	},
	getClasses : function(o) {
		return o.getAttribute("class") ;
	},
	getClass : function(o, name){
		return o.getAttribute(name);
	},
	addClass : function(o, name ){
		// if hasClass, join to class name.
		tmp = this.getClasses( o ) ;
		if( tmp )
			name = name + " " + tmp ;
		
		return o.setAttribute("class", name);
	},
	removeClass : function(o, name){
		attr   = this.getClass(o, "class") ;
		if(attr == null)
			return ;
		atache = attr.replace(name,"") ;
		
		return o.setAttribute("class", atache) ;
	}
};


// get user agent.
var ua = navigator.userAgent.toLowerCase();
validate.browser = {
	version: (ua.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
	safari: /webkit/.test( ua ),
	opera: /opera/.test( ua ),
	msie: /msie/.test( ua ) && !/opera/.test( ua ),
	mozilla: /mozilla/.test( ua ) && !/(compatible|webkit)/.test( ua )
};


// validationルール
validate.rule = {
	"required" : function(a){
		return a.match(/.+/) ? true : false ;
	},
	"numeric"  : function(a){
		return a.match(/^[\d]+$/) ? true : false ;
	},
	"alpha"    : function(a){
		return a.match(/^[a-z]+$/) ? true : false ;
	},
	"alphanum" : function(a){
		return a.match(/^[a-z0-9]+$/) ? true : false ;
	},
	"mail" : function(a){
		return a.match(/^[\x01-\x7F]+@((([-a-z0-9]+\.)*[a-z]+)|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))$/) ? true : false ;
	},
	"numHyphen" : function(a){
		return a.match(/^[0-9¥-]+$/) ? true : false ;
	}
};


// エラーメッセージ
validate.errorMsg = {
	"required"  : "必須項目です",
	"numeric"   : "数字のみで構成してください",
	"alpha"     : "英字のみで構成してください",
	"alphanum"  : "英数字で構成してください",
	"mail"      : "メールアドレスを正しく入力してください",
	"numHyphen" : "数字とハイフンのみで構成してください"
};


// ポップアップ関数群
validate.popup = {
	open : function(field, msg){
		if( !field._popup ) {
			var o = new this.elem(field);
			o.create() ;
			field._popup = o ;
			addEvent(field, "focus", function(){ o.close(); });
		}
		field._popup.show(msg) ;
	},
	elem : function(field){
		this.initialize.apply(this, arguments)
	}
};


// ポップアップ関数のprototype拡張
validate.popup.elem.prototype = {
	// コンストラクタ
	initialize : function(field){
		this._parent = validate.popup ;
		this.field = field ;
	},
	create : function(){
		var field = this.field ;
		var s     = this ;
		
		var div = document.createElement("div");
		div.className = "validateErrorMessage" ;
		
		// div要素を作成
		var offset = position.getPosition(field) ;
		var top  = offset.y ;
		var left = offset.x ;
		div.style.top  = top +"px" ;
		div.style.left = left+"px" ;
		div.style.position = "absolute" ;
		div.style.width = "130px" ;
		
		// 閉じるボタンの挙動
		var close = function(){s.close();} ;
		
		var link  = document.createElement("a") ;
		link.appendChild(document.createTextNode("×"));
		link.setAttribute("href", "javascript:void(0);");
		addEvent(link, "click", close) ;
		
		// テキストを流し込むspan要素の作成
		var span = document.createElement("span") ;
		addEvent(span, "click", close);
		
		// 作成した要素をすべてdiv要素に入れ込む
		div.appendChild(link) ;
		div.appendChild(span) ;
		document.body.appendChild(div);
		
		// 参照できるように変数をglobalへ
		this.divElem  = div ;
		this.spanElem = span ;
		
	},
	show   : function( msg ){
		this.spanElem.innerHTML = " "+msg ;
		this.divElem.style.display = "block" ;
	},
	hide   : function(){
	},
	isVisible : function() {
		return ( this.divElem.style.display == 'none' ) ;
	},
	close  : function(){
		this.divElem.style.display =  "none" ;
	}
};


// 位置関係の変数
var position = {
	// オフセットの取得
	getOffset : function(el){
		var p = {} ; // return value of offset.
		var tagName = el.tagName.toLowerCase(),
				name    = el.name.toLowerCase() ;
		var target = tagName+"[name='"+name+"']" ;
		var o = jQuery( target ).offset() ;
		p.x = Math.round( o.left );
		p.y = Math.round( o.top ) ;
		return p ;
	},
	// 位置を取得
	getPosition : function(el) {
		var offset = this.getOffset(el);
		var pos = {} ;
		var w = el.offsetWidth ;
		var h = el.offsetHeight ;
		pos.x = offset.x + w - 10 ;
		pos.y = offset.y - h + 5  ;
		return pos ;
	}
};


// イベントの作成
function addEvent(elm, evType, fn) {
	if (elm.addEventListener) {
		elm.addEventListener(evType, fn, false);
		return true;
	}
	else if (elm.attachEvent) {
		var r = elm.attachEvent('on' + evType, fn);
		return r;
	}
	else {
		elm['on' + evType] = fn;
	}
}

