Main = {	
	_GET: null,	
	
	init: function(){
		this.parseUrl();
	},
	
	get:function(sKey, bFlag){		
		if(bFlag){
			return (this._GET && this.isset(this._GET[sKey]))?this._GET[sKey]:null;	
		}else{
			return (this._GET && this.isset(this._GET['query'][sKey]))?this._GET['query'][sKey]:null;	
		}		
	},	
	
	getParam: function(sKey){
		return ($_CONF && this.isset($_CONF[sKey]))?$_CONF[sKey]:null;
	},
	
	getMessage: function(sCode, args){		
		if(this.isset($_MSG[sCode])){
			return this.vsprintf($_MSG[sCode], args);	
		}
		return null;
	},	
	
	forward: function(sUrl){
		window.location = sUrl;
	},
	
	makeUrl: function(sFile, aParam, bAppend){
		if(!aParam){aParam = new Array();}				
		var aVal = this._GET['query'];		
		if(!(aParam instanceof Array)){ 
			for(var key in aParam) {
				aVal[key] = aParam[key];
			}   
    	}
		var sUrl = this._GET['root_url'];		
		if('current' == sFile){
			sUrl += this._GET['file'];			
			sUrl = this.sprintf('%s?%s', sUrl, this.buildQuery(aVal));
		}else if(sFile){			
			sUrl += this.trim(this.dirname(this._GET['file']), ' \\/');
			sUrl = this.sprintf('%s?%s', sFile, this.buildQuery(bAppend?aVal:aParam));
		}		
		return sUrl;
	},	
	
	fetch: function(sTemplate, aParam){		
		sTemplate = sTemplate.replace(/\s/g, ' ');
		var req = /{([^}]+)\}/g,
			aMatches = sTemplate.match(req),key;
		if(aMatches){
			for(var i = 0; i < aMatches.length; i++) {
				key = aMatches[i].replace(req, "$1");
				if(typeof aParam[key] != 'undefined'){
					sTemplate = sTemplate.replace(aMatches[i], aParam[key]);
				}
			}
		}
		return sTemplate;
	},
	
	clone: function(obj){
		var c = {};  
		for (var i in obj) {
			var prop = obj[i];  
			if (typeof prop == 'object') {
				c[i] = Main.clone(prop);
			}else{
				c[i] = prop;
			}
		}  
		return c;	
	},
	
	htmlspecialchars: function(string){ 
		if(string)
			return $('<span>').text(string).html();
		return '';	
	},
	
	validate: function(sCode, sReq, aRule){
		var me = this;
		if(!sReq){
			sReq = /val\[([a-zA-z0-9\_]+)\]/; 
		}
		
		var checkable = function(element) {
			return /radio|checkbox/i.test(element.type);
		};
						
		var findByName = function(name){	
			return $(document.getElementsByName(name)).map(function(index, element) {
				return element.form == form && element.name == name && element  || null;
			});
		};
		
		var getLength = function(value, element) {
			switch(element.nodeName.toLowerCase()){
			case 'select':
				return $("option:selected", element).length;
			case 'input':
				if(checkable(element))
					return findByName(element.name).filter(':checked').length;
			}
			return value.length;
		};
		
		var email = function(value, element) {			
			return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
		};
		
		var required = function(value, element){				
			switch(element.nodeName.toLowerCase()){
			case 'select':
				var options = $("option:selected", element);
				return options.length > 0 && ( element.type == "select-multiple" || ($.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
			case 'input':
				if(checkable(element))
					return getLength(value, element) > 0;
			default:
				return $.trim(value).length > 0;
			}
		};
		
		var bFlag = true;
		
		$(sCode).each(function(){
			var sName = $(this).attr("name");
			var aMatch = sName.match(sReq);			
			
			if(me.isset(aRule[aMatch[1]])){				
				var rules = aRule[aMatch[1]];
				for(var i=0;i<rules.length;i++){
					var rule = rules[i];
					var type = rule[0]; 					
					if(typeof type == 'function'){
						if(!(bFlag = type(this))){
							alert(Main.getMessage(rule[1],rule[2]));
							$(this).focus();
							return bFlag;			  
						}
					}else if(typeof type == "string"){
						switch(type.toLowerCase()){
							case 'required': 
								if(!(bFlag = required($(this).val(), this))){
									alert(Main.getMessage(rule[1],rule[2]));
									$(this).focus();
									return bFlag;								  
								}
								break;
							case 'email': 
								if(!(bFlag = email($(this).val(), this))){
									alert(Main.getMessage(rule[1],rule[2]));
									$(this).focus();
									return bFlag;	
								}
								break;
						}
					}
				}				
			}
		});	
		return bFlag;
	},
	
	parseUrl: function(sUrl){	
		if(this._GET){return;}
		var sUrl = window.location.href;		
		this._GET = {'root_url':null, 'file':null, 'name':null, 'query':null, 'mark':null};		
		
		var oParse = {
			strictMode: false,
			key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],        
			q:{
				name:   "queryKey",
				parser: /(?:^|&)([^&=]*)=?([^&]*)/g
			},
			parser: {            
				strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
				loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/\/?)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
			}
		};
		var aMatch  = oParse.parser[oParse.strictMode?"strict":"loose"].exec(sUrl),
		oUri = {},
		i = 14;
		while (i--) {oUri[oParse.key[i]] = aMatch[i] || "";}
		
		this._GET['root_url'] = this.sprintf("%s://%s%s", oUri.protocol, oUri.authority, oUri.directory);		
		this._GET['query'] = this.parseQuery(oUri.query);
		this._GET['mark'] = oUri.anchor;			
		this._GET['file'] = oUri.file;				
	},
	
	parseQuery: function(sQuery){
		var aResult = {};	  	
		if(sQuery){
			sQuery = sQuery.replace(/\+/g, ' ');	 
			var aQuery = sQuery.split(/[&;]/g);	  	 
			for (var i = 0; i < aQuery.length; i++){
				var aData = aQuery[i].split('=');
				var key = decodeURIComponent(aData[0]);
				var value = decodeURIComponent(aData[1]);					
				aResult[key] = (aData.length == 1) ? '' : value;	
			}					
		}
		return aResult;
	},	
	
	buildQuery: function(aData, arg_separator){
		var value, key, tmp = [];	 
		var _build_query_helper = function (key, val, arg_separator){
			var k, tmp = [];        
			if(val === true){
				val = "1";
			} else if (val === false) {
				val = "0";
			}        
			if (val !== null && typeof(val) !== "object" && typeof(val) !== "function"){
				return encodeURIComponent(key) + "=" + encodeURIComponent(val);
			}else{
				return encodeURIComponent(key) + "="; 	
			}
		};
	 
		if(!arg_separator){
			arg_separator = "&";
		}
		for(key in aData){
			value = aData[key];			
			tmp.push(_build_query_helper(key, value, arg_separator));
		}
		return tmp.join(arg_separator);
	},
		
	//FOR PHP http://phpjs.org	
	file_get_contents: function(url) {        
		var req = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
        if (!req) {
            throw new Error('XMLHttpRequest not supported');
        }
        if (!(/^http/).test(url)) { 
			url = this.dirname(window.location.href) + '/' +url;
        }
        req.open("GET", url, false);
        req.send(null);
        return req.responseText;    
	},
	
	trim: function(str, charlist){   
		str += '';		
		if (!charlist) {
			whitespace = " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";
		} else {			
			charlist += '';
			whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1');    
		}		
		l = str.length;
		for (i = 0; i < l; i++) {
			if (whitespace.indexOf(str.charAt(i)) === -1) {            
				str = str.substring(i);
				break;
			}
		}
		l = str.length;
		for (i = l - 1; i >= 0; i--) {
			if (whitespace.indexOf(str.charAt(i)) === -1) {
				str = str.substring(0, i + 1);
				break;        
			}
		}		
		return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
	},
	
	dirname: function(path) {        
	    return path.replace(/\\/g,'/').replace(/\/[^\/]*\/?$/, '');
	},
	
	isset: function(){
		var a=arguments, l=a.length, i=0;		
		if (l===0) {
			throw new Error('Empty isset'); 
		}		
		while (i!==l) {
			if (typeof(a[i])=='undefined' || a[i]===null) { 
				return false; 
			} else { 
				i++; 
			}
		}
		return true;
	},

	sprintf: function(){		
		var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
		var a = arguments, i = 0, format = a[i++];
	
		// pad()
		var pad = function (str, len, chr, leftJustify) {
			if (!chr) {chr = ' ';}
			var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
			return leftJustify ? str + padding : padding + str;
		};
	
		// justify()
		var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
			var diff = minWidth - value.length;
			if (diff > 0) {
				if (leftJustify || !zeroPad) {
					value = pad(value, minWidth, customPadChar, leftJustify);
				} else {
					value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
				}
			}
			return value;
		};
	
		// formatBaseX()
		var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
			// Note: casts negative numbers to positive ones
			var number = value >>> 0;
			prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
			value = prefix + pad(number.toString(base), precision || 0, '0', false);
			return justify(value, prefix, leftJustify, minWidth, zeroPad);
		};
	
		// formatString()
		var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
			if (precision != null) {
				value = value.slice(0, precision);
			}
			return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
		};
	
		// doFormat()
		var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
			var number;
			var prefix;
			var method;
			var textTransform;
			var value;
	
			if (substring == '%%') {return '%';}
	
			// parse flags
			var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, customPadChar = ' ';
			var flagsl = flags.length;
			for (var j = 0; flags && j < flagsl; j++) {
				switch (flags.charAt(j)) {
					case ' ': positivePrefix = ' '; break;
					case '+': positivePrefix = '+'; break;
					case '-': leftJustify = true; break;
					case "'": customPadChar = flags.charAt(j+1); break;
					case '0': zeroPad = true; break;
					case '#': prefixBaseX = true; break;
				}
			}
	
			// parameters may be null, undefined, empty-string or real valued
			// we want to ignore null, undefined and empty-string values
			if (!minWidth) {
				minWidth = 0;
			} else if (minWidth == '*') {
				minWidth = +a[i++];
			} else if (minWidth.charAt(0) == '*') {
				minWidth = +a[minWidth.slice(1, -1)];
			} else {
				minWidth = +minWidth;
			}
	
			// Note: undocumented perl feature:
			if (minWidth < 0) {
				minWidth = -minWidth;
				leftJustify = true;
			}
	
	
			if (!isFinite(minWidth)) {
				throw new Error('sprintf: (minimum-)width must be finite');
			}
	
			if (!precision) {
				precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
			} else if (precision == '*') {
				precision = +a[i++];
			} else if (precision.charAt(0) == '*') {
				precision = +a[precision.slice(1, -1)];
			} else {
				precision = +precision;
			}
	
			// grab value using valueIndex if required?
			value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
	
			switch (type) {
				case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
				case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
				case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
				case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
				case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
				case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
				case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
				case 'i':
				case 'd':
					number = parseInt(+value, 10);
					prefix = number < 0 ? '-' : positivePrefix;
					value = prefix + pad(String(Math.abs(number)), precision, '0', false);
					return justify(value, prefix, leftJustify, minWidth, zeroPad);
				case 'e':
				case 'E':
				case 'f':
				case 'F':
				case 'g':
				case 'G':
					number = +value;
					prefix = number < 0 ? '-' : positivePrefix;
					method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
					textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
					value = prefix + Math.abs(number)[method](precision);
					return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
				default: return substring;
			}
		};
	
		return format.replace(regex, doFormat);
	},
	
	vsprintf: function(format, args){		
        return this.sprintf.apply(this, [format].concat(args));
	},
	
	print_r: function(array, return_val) {     
		var output = "", pad_char = " ", pad_val = 4, d = window.document;    var getFuncName = function (fn) {
			var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
			if (!name) {
				return '(Anonymous)';
			}        return name[1];
		};	 
		var repeat_char = function (len, pad_char){
			var str = "";        
			for (var i=0; i < len; i++){
				str += pad_char;
			}
			return str;
		}; 
		var formatArray = function (obj, cur_depth, pad_val, pad_char){
			if (cur_depth > 0){
				cur_depth++;
			} 
			var base_pad = repeat_char(pad_val*cur_depth, pad_char);
			var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
			var str = "";
			 if (typeof obj === 'object' && obj !== null) {
				str += "Array\n" + base_pad + "(\n";
				for (var key in obj) {
					if (obj[key] instanceof Array || typeof obj === 'object'){
						str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char) + "\n";                
					} else {
						str += thick_pad + "["+key+"] => " + obj[key] + "\n";
					}
				}
				str += base_pad + ")\n";        
			}else if (obj === null || obj === undefined) {
				str = '';
			}else{
				str = obj.toString();
			} 
			return str;
		};	 
		return formatArray(array, 0, pad_val, pad_char); 
	}
};
Main.init();
