/*!
 * jsX JavaScript Library v0.1.2
 * http://jquery.com/
 *
 * Copyright (c) 2009 IT Media COnnect
 * Dual licensed under the MIT and GPL licenses.
 *
 */

if (!this.jsx) {
    this.jsx = {};
}
if (!this.jajax) {
    this.jajax = {};
}
if (!this.juAx) {
    this.juAx = {};
}

(function(){
	
	this.jsx.version = '0.1.2';
	
    /**
     * Array eXtended
     *
     * Trying to extend the functionalities of the Array object in JavaScript
     *
     * @object Array
     */
    Array.prototype = {
        foreach: function(handler){
            for (var i = 0; i < this.length; i++) {
                handler(this[i]);
            }
        }
    };
     
    /**
     * String eXtended
     *
     * @object String
     */
    /**
     *
     * @param {RegExp} pattern
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.replaceAll = function(pattern, value) {
        s = pattern.toString();
        if (s.indexOf("/") != 0) 
            throw "String.replaceAll(pattern, value): " + s + " is not RegExp";
        if (s.match(/\/[imy]*g[imy]*$/)) {
            return this.replace(pattern, value);
        }
        else {
            s += 'g';
        }
        //def: new RegExp(pattern, flags)
        r = new RegExp(s.substr(1, s.lastIndexOf("/") - 1), s.substr(s.lastIndexOf("/") + 1, s.length));
        return this.replace(r, value);
    }
    
    /**
     *
     * @param {RegExp|String} pattern
     *
     * @return {Boolean}
     * @return {Array}
     */
    String.prototype.matchAll = function(pattern){
        s = pattern.toString();
        if (s.indexOf("/") != 0) 
            throw "String.mathAll(pattern): pattern is not RegExp";
        if (s.match(/\/[imy]*g[imy]*$/)) {
            return this.match(pattern);
        }
        else {
            s += 'g';
        }
        r = new RegExp(s.substr(1, s.lastIndexOf("/") - 1), s.substr(s.lastIndexOf("/") + 1, s.length));
        return this.match(r);
    }
    
    /**
     *
     * @param {String} value
     *
     * @return Boolean
     */
    String.prototype.isInt = function(value){
        n = parseInt(value || this);
        return ((!isNaN(n) && n.toString() == this) ? true : false);
        //	return (this.match(/^-?(\d|[1-9]\d+)([eE]+\d+)?$/) ? true: false);
    }
    
    /**
     *
     * @param {String} value
     *
     * @return Boolean
     */
    String.prototype.isFloat = function(value){
        //	n = parseFloat(value || this);
        //	return ((!isNaN(n) && n.toString() == this) ? true : false);
        return (this.match(/^-?\d+(\.\d*)?([eE][-+]\d+)?$/) ? true : false);
    }
    
    /**
     *
     * @param {String} value
     *
     * @return Boolean
     */
    String.prototype.isNumber = function(value){
        return (this.isInt(value) || this.isFloat(value));
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.htmlEncode = function(value){
        return escape(value || this);
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.htmlDecode = function(value){
        return unescape(value || this);
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.utf8_encode = function(value){
        string = value || this;
        string = (string + '').replace(/\r\n/g, "\n").replace(/\r/g, "\n");
        var utftext = "";
        var start = 0, end = 0;
        var stringl = string.length;
        for (var n = 0; n < stringl; n++) {
            var c1 = string.charCodeAt(n);
            var enc = null;
            
            if (c1 < 128) {
                end++;
            }
            else 
                if ((c1 > 127) && (c1 < 2048)) {
                    enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
                }
                else {
                    enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
                }
            if (enc != null) {
                if (end > start) {
                    utftext += string.substring(start, end);
                }
                utftext += enc;
                start = end = n + 1;
            }
        }
        if (end > start) {
            utftext += string.substring(start, string.length);
        }
        return utftext;
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.utf8_decode = function(value){
        string = value || this;
        var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;
        string += '';
        while (i < string.length) {
            c1 = string.charCodeAt(i);
            if (c1 < 128) {
                tmp_arr[ac++] = String.fromCharCode(c1);
                i++;
            }
            else 
                if ((c1 > 191) && (c1 < 224)) {
                    c2 = string.charCodeAt(i + 1);
                    tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
                    i += 2;
                }
                else {
                    c2 = string.charCodeAt(i + 1);
                    c3 = string.charCodeAt(i + 2);
                    tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }
        }
        return tmp_arr.join('');
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.base64_encode = function(value){
        var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        var o1, o2, o3, h1, h2, h3, h4, bits, i = ac = 0, enc = "", tmp_arr = [];
        
        string = value || this;
        if (!string) {
            return string;
        }
        
        string += '';
        string = string.utf8_encode();
        
        do { // pack three octets into four hexets
            o1 = string.charCodeAt(i++);
            o2 = string.charCodeAt(i++);
            o3 = string.charCodeAt(i++);
            
            bits = o1 << 16 | o2 << 8 | o3;
            
            h1 = bits >> 18 & 0x3f;
            h2 = bits >> 12 & 0x3f;
            h3 = bits >> 6 & 0x3f;
            h4 = bits & 0x3f;
            
            // use hexets to index into b64, and append result to encoded string
            tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
        }
        while (i < string.length);
        
        enc = tmp_arr.join('');
        
        switch (string.length % 3) {
            case 1:
                enc = enc.slice(0, -2) + '==';
                break;
            case 2:
                enc = enc.slice(0, -1) + '=';
                break;
        }
        
        return enc;
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {String}
     */
    String.prototype.base64_decode = function(value){
        var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = "", tmp_arr = [];
        
        string = value || this;
        if (!string) {
            return string;
        }
        
        string += '';
        
        do { // unpack four hexets into three octets using index points in b64
            h1 = b64.indexOf(string.charAt(i++));
            h2 = b64.indexOf(string.charAt(i++));
            h3 = b64.indexOf(string.charAt(i++));
            h4 = b64.indexOf(string.charAt(i++));
            
            bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
            
            o1 = bits >> 16 & 0xff;
            o2 = bits >> 8 & 0xff;
            o3 = bits & 0xff;
            
            if (h3 == 64) {
                tmp_arr[ac++] = String.fromCharCode(o1);
            }
            else 
                if (h4 == 64) {
                    tmp_arr[ac++] = String.fromCharCode(o1, o2);
                }
                else {
                    tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
                }
        }
        while (i < string.length);
        
        dec = tmp_arr.join('');
        dec = dec.utf8_decode();
        
        return dec;
    }
    
    
    /**
     *
     * @param {Number} value
     *
     * @return {String}
     */
    Number.prototype.toHexa = function(value){
        value = value || this;
        return (new Number(value)).toString(16).toUpperCase();
    }
    
    /**
     *
     * @param {String} value
     *
     * @return {Number}
     */
    Number.prototype.fromHexa = function(value){
        return new Number(parseInt(value, 16));
    }
    
    /**
     *
     * @param {Number} value
     *
     * @return {String}
     */
    Number.prototype.toOctal = function(value){
        value = value || this;
        return (new Number(value)).toString(8).toUpperCase();
    }
    
    /**
     *
     * @param {Object} value
     *
     * @return {Number}
     */
    Number.prototype.fromOctal = function(value){
        return new Number(parseInt(value, 8));
    }
    
    /**
     *
     * @param {Number} value
     *
     * @return {String}
     */
    Number.prototype.toBinary = function(value){
        value = value || this;
        return (new Number(value)).toString(2).toUpperCase();
    }
    
    /**
     *
     * @param {Object} value
     *
     * @return {Number}
     */
    Number.prototype.fromBinary = function(value){
        return new Number(parseInt(value, 2));
    }
    
    /**
     *
     * @param {Number} base
     * @param {Object} value
     *
     * @return {String}
     */
    Number.prototype.toBase = function(base, value){
        value = value || this;
        return (new Number(value)).toString(base).toUpperCase();
    }
    
    /**
     *
     * @param {String} value
     * @param {Number} base
     *
     * @return {Number}
     */
    Number.prototype.fromBase = function(value, base){
        return new Number(parseInt(value, base));
    }
    
    /** 
     * @class Date
     */
    Date.prototype = {};
    
    /**
     * @class Function
     */
    Function.prototype = {};
    
    /**
     * @class RegExp
     */
    RegExp.prototype = {};
    
    /**
     * @object Boolean
     */
    Boolean.prototype = {}
	
	/**
	 * @object Object
	 */
	
})();

(function(){

    /**
     * juAx / jsX user Agent
     * 
     */
    this.juAx.uA = navigator.userAgent.toLowerCase();
    this.juAx.is_msie = /msie /.test(this.juAx.uA);
	for (i = 5; i < 8; i++) {
		this.juAx['is_msie' + i] = (new RegExp('msie ' + i)).test(this.juAx.uA);
		this.juAx['is_msie' + i + 'gt'] = (new RegExp('msie [' + (i+1) + '-9]')).test(this.juAx.uA);
		this.juAx['is_msie' + i + 'lt'] = (new RegExp('msie [1-' + (i-1) + ']')).test(this.juAx.uA);
	}
	this.juAx.is_msie8 = /mise 8/.test(this.juAx.uA);
    this.juAx.is_gecko = /gecko/.test(this.juAx.uA);
    this.juAx.is_safari = /safari/.test(this.juAx.uA);
    this.juAx.is_opera = /opera/.test(this.juAx.uA);
    this.juAx.is_khtml = /khtml/.test(this.juAx.uA);
	/**
	 * function is_agentbrowser, matchKey = null, userAgent = null)
	 * @example
	 * juAx.is_agent('firefox');
	 * juAx.is_agent('firefox gt 3');
	 * juAx.is_agent('epiphany gt 2', /(epiphany)\/([0-2]\.[0-2]*)/)
	 * 
	 * @param {String} matchKey
	 * @param {RegExp} pattern
	 * @param {String} userAgent
	 */
    this.juAx.is_agent = function(browser, matchKey, userAgent){
		/**
		 * main used browsers
		 */
		browsers = new Object();
		browsers = { 
			'chrome' : /chrome\/([0-9]+\.?[0-9]*)/,
			'epiphany' : /epiphany\/([0-9]+\.?[0-9]*)/,
			'firebird' : /firebird\/([0-9]+\.?[0-9]*)/i,
			'firefox' : /firefox\/([0-9]+\.?[0-9]*)/i,
			'gecko' : /gecko\/([0-9]+)/i,
			'iceape' : /iceape\/([0-9]+\.?[0-9]*)/i,
			'iceweasel' : /iceweasel\/([0-9]+\.?[0-9]*)/i,
			'khtml' : /khtml\/([0-9]+\.?[0-9]*)/i,
			'konqueror' : /konqueror\/([0-9]+\.?[0-9]*)/i,
			'msie' : /msie ([0-9]+\.?[0-9]*)/i,
			'opera' : /opera[\/ ]([0-9]+\.?[0-9]*)/i,
			'phoenix' : /phoenix\/([0-9]+\.?[0-9]*)/i,
			'safari' : /version\/([0-9]+\.?[0-9]*)|safari\/([0-9]+\.?[0-9]*)/i
		};
		/**
		 * the usual operators from string to javascript operators
		 */
		operators = { eq : '==', gte : '>=', gt : '>', lte : '<=', 'lt' : '<', neq : '!=' };
		/* select the user agent version we will use */
		userAgent = (userAgent)? userAgent.toLowerCase() : juAx.uA;
		
		browser = browser.toLocaleLowerCase();
		/* apply test filter to obtain browser, operator and version */
		b = browser.match(/([a-z]+) ?([glte]+)? ?([0-9]+\.?[0-9]*)?/);
		/* if no match, throw exception */
		if (!b) {
			throw new Error("Browser parameter syntax is incorect. Please use 'browser_name [gt(e)|lt(e)|(n)eq version.subversion]' (i.e. 'msie gt 6.5'). ");
			return false;
		}
		/* if we have operator the test gets more complicated */
		if (b[2]) {
			/* if we don't have a version to compare, throw an exception */
			if (!b[3]) {
				throw new Error("No browser version specified. No version to compare with. Please use 'browser_name [gt(e)|lt(e)|(n)eq version.subversion]' (i.e. 'msie gt 6.5'). ");
				return false;
			}
			/* if the operator does not exist throw an exception */
			if (!operators[b[2]]) {
				throw new Error("Browser compare operator is incorrect. Please use 'browser_name [gt(e)|lt(e)|(n)eq version.subversion]' (i.e. 'msie gt 6.5'). ");
				return false;
			}
			if (matchKey) {
				c = userAgent.match(matchKey);
				if (c) {
					return eval(c[1] + ' ' + operators[b[2]] + ' ' + b[3]);
				}
			}
			/* check for browser version grabber and do test */
			for (key in browsers) {
				if (key == b[1]) {
					c = userAgent.match(browsers[key]);
//					document.write(c);
					if (c) {
						return eval(c[1] + ' ' + operators[b[2]] + ' ' + b[3]);
					} 
					return false;
				}
			}
		}
		/* if we only test browser */
		if (b[1]) {
			for (key in browsers) {
				if (key == b[1] && (new RegExp(key)).test(juAx.uA) ) {
					return true;
				}
			}
		}
		return false;
    }, // operating system
 	this.juAx.is_win = /windows|winnt/.test(this.juAx.uA);
    this.juAx.is_nix = /windows|winnt/.test(this.juAx.uA);
    this.juAx.is_nil = /linux/.test(this.juAx.uA);
    
   /**
    * juAx.js 
    * Trying to discover javascript version by major browsers types and version.
    * 
    * @memberOf juAx
    * @version 0.0.1
    * 
    * There is still much to test here... please do not use this element yet.
    */
    this.juAx.js = new Object();
	// Netscape 2.x, MSIE 3
    this.juAx.js.is_10 = /(mozilla\/2|msie 3)/.test(this.juAx.uA); 
	// Netscape 3
    this.juAx.js.is_11 = /(mozilla\/3)/.test(this.juAx.uA); 
	// Netscape 4 -> 4.0.5 | By convention I'll reduce all ns4.0 to js12
    this.juAx.js.is_12 = /(mozilla\/4(\.0[0-5])?)/.test(this.juAx.uA); 
	// Netscape 4.06-4.7x, MSIE 4-8	| Not sure of IE agents lower than v-5
    this.juAx.js.is_13 = /(mozilla\/4\.[6-9]|msie [4-8])/.test(this.juAx.uA);
	// Opera 6 | Untill further assurance, opera stays here 
    this.juAx.js.is_14 = /(opera[\/ ][6-9])/.test(this.juAx.uA); 
	// Netscape 6, Firefox 1 (MSIE 5.5, MSIE6-8)? (Opera 6-9)?
    this.juAx.js.is_15 = /(netscape6|firefox\/?1\.0)/.test(this.juAx.uA);
	// Firefox 1.5, Netscape 7,8, Opera 7+
    this.juAx.js.is_16 = /(netscape\/[7-8]|firefox\/1\.5)/.test(this.juAx.uA); 
	// Firefox 2, Safari 3
    this.juAx.js.is_17 = /(firefox\/2|version\/3.|safari)/.test(this.juAx.uA);
	// Firefox 3 
    this.juAx.js.is_18 = /(firefox\/3)/.test(this.juAx.uA); 
	// Firefox 3.1
    this.juAx.js.is_19 = /(firefox\/3\.1)/.test(this.juAx.uA); 
   
   
 	this.juAx.version = '0.0.2';  
    juAx = this.juAx;
	if (window.jQuery) {
		jQuery.juAx = juAx;
	}
    
})();

(function() {
	jajax = this.jajax = {
		
		/*
		 * constants for XMLHttpRequest.readyState
		 */
        status_unsent: 0, 		// 0 UNSENT
        status_open: 1, 		// 1 OPEN
        status_sent: 2, 		// 2 SENT
        status_loading: 3, 		// 3 LOADING 
        status_done: 4, 		// 4 DONE
		
		/**
		 * jajax::call(c)
		 * 
		 * @param {Object} c
		 */
		call : function (c) {
			var cc = {
				url : '',				// string
				method : 'post',		// can be 'post' or 'get'
				response : 'xml',		// can be 'text' or 'xml'
				request : '',			// any type of object
				async : true,			// boolean
				username : null,		// string
				password : null,		// string
				serialize : null,		// can be null, 'json', 'xml', 'php' (php serialize function)
				handle : null,			// function
				handled : false			// boolean 
				
			};
			for (key in c) {
				cc[key] = c[key];
			}
			var htreq = 'call' + jajax.calls;
            if (window.XMLHttpRequest) { 
                jajax[htreq] = new XMLHttpRequest();
                if (jajax[htreq].overrideMimeType) {
                    jajax[htreq].overrideMimeType('text/xml');
                }
            }
            else 
                if (window.ActiveXObject) { 
                    try {
                        jajax[htreq] = new ActiveXObject("Msxml2.XMLHTTP");
                    } 
                    catch (e) {
                        try {
                            jajax[htreq] = new ActiveXObject("Microsoft.XMLHTTP");
                        } 
                        catch (e) {
							throw new Error("Browser does not support XMLHttpRequest object.");
                        }
                    }
                }
            if (!jajax[htreq]) {
                alert('Browser does not support XMLHttpRequest object.');
                return false;
            }
			try {
				if (cc.serialize) {
					if (cc.serialize == 'json') {
						if (!JSON) {
							throw new Error('JSON script was not added');
						}
						cc.request = JSON.stringify(cc.request);
					}
					if (cc.serialize == 'xml') {
						if (!JXML) {
							throw new Error('JXML script was not added.');
						}
						cc.request = JXML.stringify(cc.request);
					}
					if (cc.serialize == 'php') {
						if (!JPHP) {
							throw new Error('JPHP script was nod added.')
						}
						cc.request = JPHP.serialize(cc.request);
					}
					cc.request = 'req=' + cc.request + '&reqm=' + cc.serialize;
				}
				if (!cc.serialize) {
					r = '';
					for (key in cc.request) {
						if (typeof cc.request[key] !== 'function') {
							r += key + '=' + cc.request[key] + '&';
						}
					}
					cc.request = r;
				}
				
				if (cc.handled) {
					jajax[htreq].onreadystatechange = function() {
						//alert(jajax[htreq].readyState + ':' + htreq);
						cc.handle(jajax[htreq]);
					}
				} else {
					jajax[htreq].onreadystatechange = function(){
						if (jajax[htreq].readyState == jajax.status_done) {
							cc.handle((cc.response == 'xml') ? jajax[htreq].responseXML : jajax[htreq].responseText);
						}
					}
				}
				if (cc.method != 'post') {
					cc.url += ((cc.url.indexOf('?') < 0) ? '?' : '&') + cc.request; 
				}
//				alert(cc.url);
                jajax[htreq].open(cc.method, cc.url, cc.async, cc.username, cc.password);
				if (cc.method == 'post') {
					jajax[htreq].setRequestHeader("Content-type", "application/x-www-form-urlencoded");
					jajax[htreq].setRequestHeader("Content-length", cc.request.length);
					jajax[htreq].setRequestHeader("Connection", "close");
				}
                jajax[htreq].send( (cc.method == 'post') ? cc.request : null );
            } 
            catch (e) {
                throw "XMLHttpRequest.send: " + e;
            }
			jajax.calls ++;
		},
		
		calls : 0,
		
		version : '0.0.1'
	}
	
	if (window.jQuery) {
		jQuery.jajax = jajax;
	}
})();
