var Http =
{
    cookies: document.cookie.split('; '),

    escapeTable: null,
    unescapeTable: null,

    getCookies: function()
    {
        var result = [];
        for( var i = 0; i < this.cookies.length; i++ )
        {
            var cookie = this.cookies[i].split('=');
            if ( cookie[0] !== '' )
            {
                result[i] = new Http.Cookie( cookie[0], ( cookie[1] ) ? cookie[1] : '' );
            }
        }
        return result;
    },

    getCookieByName: function( /*String*/ name )
    {
        for( var i = 0; i < this.cookies.length; i++ )
        {
            var cookie = this.cookies[i].split('=');
            if( cookie[0].toUpperCase() === name.toUpperCase() )
            {
                return new Http.Cookie( cookie[0], ( cookie[1] ) ? cookie[1] : '' );
            }
        }

        return null;
    },
    updateCookies: function()
    {
        this.cookies = document.cookie.split('; ');
    },
    buildTranslateSymbolTabels: function()
    {
        if( this.unescapeTable instanceof Array && this.escapeTable instanceof Array ) return false;
        this.escapeTable = [];
        this.unescapeTable = [];
        //for (var i = 0x410; i <= 0x44F; i++)  // А-Яа-я
        //{
        //    this.escapeTable[i] = i - 0x350;
        //    this.unescapeTable[i - 0x350] = i;
        //}
        //// Ё
        //this.escapeTable[0x401] = 0xA8;
        //this.escapeTable[0x451] = 0xB8;
        ////ё
        //this.unescapeTable[0xA8] = 0x401;
        //this.unescapeTable[0xB8] = 0x451;        
    },
    escape: function( str )
    {		
        if( typeof( str ) != 'string' ) str += '';

        this.buildTranslateSymbolTabels();

        var ret = '';
		
        for ( var i = 0; i < str.length; i++ )
        {
            var n = str.charCodeAt(i);
            if (typeof( this.escapeTable[n] ) != 'undefined')
                ret += window.escape( String.fromCharCode( this.escapeTable[n] ) );
            else				
				ret += encodeURIComponent( str.charAt(i) );
        }
        return ret;
    },
    unescape: function( str )
    {
        this.buildTranslateSymbolTabels();

        str = window.unescape(str);

        var ret = '';
        for( var i = 0; i < str.length; i++ )
        {
            var n = str.charCodeAt(i);
            if (typeof( this.unescapeTable[n] ) != 'undefined')
                ret += String.fromCharCode( this.unescapeTable[n] );
            else				
				ret += decodeURIComponent( str.charAt(i) );
        }
        return ret;                        
    }
};

Http.Request = function ( /*String*/ url, /*Object[]*/ params, /*String*/ method )
{
    this.url = url;
    if( method ) { this.method = method.toUpperCase(); }
    if( params ) { this.params = params; }
    try { this.request = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
    if ( !this.request ) { try { this.request = new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} }
    if ( !this.request ) { try { this.request = new XMLHttpRequest(); } catch(e) {} }
    if ( !this.request ) { throw new Error( "Your browser dont support Ajax. Wee recomend to update browser." ); }
};
Http.Request.prototype =
{
    request: null,
    async: false,
    url: '',
    method: 'GET',
    params: {},
    options: { sendParamsAsXML: false, sendParamsAsJSON: false },
    onComplete: function ( response ) {},
    onInteractive: function ( request ) {},
    onLoaded: function ( response ) {},
    onLoading: function ( response ) {},
    onUninitialized: function ( response ){},
    send: function ( /*Boolean*/ async )
    {
        this.async = ( typeof( async ) != 'undefined' ) ? async : this.async;
        var query = 'timestamp=' + new Date().getTime();		
        for( var i in this.params )
        {
            if ( typeof( this.params[i]) != 'function' )
            {
                query += '&' + i + '=' + Http.escape( this.params[i] );
            }
        }		
        if( this.method == 'GET' )
        {
            this.url += '?' + query;
        }
        var self = this;
        this.request.onreadystatechange = function ()
        {
            if ( self.request.readyState == 4 ) // Complete
            {
                self.onComplete( new Http.Response( self.request ) );
            }
            else if ( self.request.readyState == 3 ) // Interactive
            {
                self.onInteractive( self.request );
            }
        };
        this.request.open( this.method, this.url, this.async );

        var headers = ['X-Requested-With', 'XMLHttpRequest'];        
        if ( this.method == 'POST' )
        {
            headers.push('Content-type', 'application/x-www-form-urlencoded');			
            if ( this.request.overrideMimeType )
            {
                headers.push('Connection', 'close');
            }
        }
		else
		{
			headers.push('Content-type', 'text/html; charset=UTF-8');
		}
        for ( i = 0; i < headers.length; i+=2 )
        {
			 this.request.setRequestHeader( headers[i], headers[ i + 1 ] );
        }

        if( this.method == 'POST' )
        {
            if( this.options.sendParamsAsXML )
            {
                this.request.send( this.params );
            }
            else if( this.options.sendParamsAsJSON && typeof( JSON ) != 'undefined' )
            {
                this.request.send( JSON.stringify( this.params ) );
            }
            else
            {
                this.request.send( query );
            }
        }
        else
        {
            this.request.send( null );
        }

        /*
        if ( ( this.request.status ) && ( ( 200 > this.request.status ) || ( 300 <= this.request.status ) ) )
        {
			throw "Unable to load " + this.url +" status: " + this.request.status;
        }
        */

        return ( ( this.async ) ? null : new Http.Response( this.request ) );
    }
};

Http.Response = function( /*Object*/ data )
{
    this.data = data;
};
Http.Response.prototype =
{
    data: null,
    serializedHTML: null,
    serializedJSON: {},
    isSuccess: function()
    {
        return ( this.data.status >= 200 && this.data.status < 300 );
    },
    getXML: function ()
    {
        if( this.isSuccess() )
        {
            return this.data.responseXML;
        }
        return null;
    },
    getText: function()
    {
        if( this.isSuccess() )
        {
            return this.data.responseText;
        }
        return null;
    },
    getHTML: function()
    {
        this.convertXMLtoHTML();
        return this.serializedHTML;
    },
    getJSON: function( /*String|Node*/ startNode )
    {
        this.converXMLtoJSON( startNode );
        return this.serializedJSON;
    },
    xpath: function( /*String*/ expression )
    {
        if ( this.isSuccess() && typeof( xpathParse ) != 'undefined' )
        {
            var ctx = new ExprContext( this.data.responseXML );
            var pathExpr = xpathParse( expression );
            var e = pathExpr.evaluate( ctx );
            return e.nodeSetValue();
        }
        return null;
    },
    converXMLtoJSON: function( /*String|Node*/ startNode )
    {
        var root = this.data.responseXML.childNodes[1];
        if ( !root ) root = this.data.responseXML.firstChild;
        if ( typeof( startNode ) == 'string' )
        {
            root = this.data.responseXML.getElementsByTagName( startNode )[0];
        }
        else if ( startNode )
        {
            root = startNode;
        }
        if ( !root ) throw "Empty file. Error in Http.Response.converXMLtoJSON()";
        this.serializedJSON = this.serializeJSON( {}, root );
    },
    serializeJSON: function( /*Object*/ obj, /*XMLNode*/ root )
    {
        var rootName = this.fixXMLNodeName( root );
        if ( root.nodeType == 1 )
        {
            obj[ rootName ] = {};
            for ( var i = 0; i < root.childNodes.length; i++ )
            {
                var node = root.childNodes[ i ];
                var nodeName = this.fixXMLNodeName( node );
                if( typeof( obj[ rootName ][ nodeName ] ) != 'undefined' && !( obj[ rootName ][ nodeName ] instanceof Array ) )
                {
                    obj[ rootName ][ nodeName ] = [ obj[ rootName ][ nodeName ] ];
                }
                if ( obj[ rootName ][ nodeName ] instanceof Array )
                {
                    obj[ rootName ][ nodeName ].push( this.serializeJSON( {}, node )[ nodeName ] );
                }
                else if ( node.nodeType != 3 )
                {
                    obj[ rootName ] = this.serializeJSON( obj[ rootName ], node );
                }
            }
        }
        if( root.attributes )
        {
            for ( var j = 0; j < root.attributes.length; j++ )
            {
                var attr = root.attributes[ j ];
                var attrName = this.fixXMLNodeName( attr );
                if ( attr.nodeValue )
                {
                    obj[ rootName ][ '@' + attrName ] = attr.nodeValue;
                }
            }
        }
        if ( root.nodeType == 1 && !root.firstChild )
        {
            obj[ rootName ]['#text'] = root.nodeValue;
        }
        if ( root.nodeType == 3 )
        {
            obj['#text'] = root.nodeValue;
        }
        return obj;
    },
    fixXMLNodeName: function( name )
    {
        name = name.nodeName;
        if ( typeof( name ) != 'string' ) throw 'Error in Http.Response.fixXMLNodeName()';
        while ( name.indexOf( '-' ) != -1 )
        {
            name = name.replace( '-', '' );
        }
        return name;
    },
    convertXMLtoHTML: function()
    {
        var root = this.data.responseXML.childNodes[1];
        if ( !root ) root = this.data.responseXML.firstChild;
        if ( !root ) throw "Empty file. Error in Http.Response.convertXMLtoHTML()";
        this.serializedHTML = document.createElement( 'root' );
        if ( root )
        {
            this.serializedHTML.appendChild( this.serializeNode( root ) );
            this.serializeNodes( this.serializedHTML.firstChild, root );
        }
    },
    serializeNodes: function( /*Node*/ to, /*XMLNode*/ from )
    {
        for ( var i = 0; i < from.childNodes.length; i++ )
        {
            var elem = from.childNodes[ i ];
            var newElem = this.serializeNode( elem );
            if ( newElem !== null )
            {
                to.appendChild( newElem );
                this.serializeNodes( newElem, elem );
            }
        }
    },
    serializeNode: function( /*XMLNode*/ node )
    {
        var newElem = null;
        switch ( node.nodeType )
        {
            case 1:
                newElem = document.createElement( node.nodeName );
                if ( node.attributes.length > 0 )
                {
                    for ( var j = 0; j < node.attributes.length; j++ )
                    {
                        var attr = node.attributes[ j ];
                        if ( attr.nodeValue )
                        {
                            /*var newAttr = document.createAttribute( attr.nodeName );
                            newAttr.nodeValue = attr.nodeValue;
                            newElem.setAttributeNode( newAttr );*/
                            if ( newElem.setAttribute )
                            {
                                newElem.setAttribute( attr.nodeName, attr.nodeValue, false );
                            }
                            else if ( newElem[ attr.nodeName ] )
                            {
                                newElem[ attr.nodeName ] = attr.nodeValue;
                            }
                            else if ( document.createAttribute )
                            {
                                var newAttr = document.createAttribute();
                                newAttr.nodeName = attr.nodeName; 
                                newAttr.nodeValue = attr.nodeValue;
                                newElem.setAttributeNode( newAttr );
                            }
                        }
                    }
                }
                break;
            case 3:
                newElem = document.createTextNode( node.nodeValue );
                break;
			default: break;
        }
        return newElem;
    }
};

/*---------------HTTP.COOKIE Class---------------*/
Http.Cookie = function( /*String*/ name, /*String*/ value, /*Date*/ expires, /*String*/ path, /*String*/ domain, /*Boolean*/ secure )
{
    if( name )
    {
        this.setName( name );
    }
    if( value )
    {
        this.setValue( value );
    }
    if( expires instanceof Date )
    {
        this.expires = expires;
    }
    if( path )
    {
        this.setPath( path );
    }
    if( domain )
    {
        this.setDomain( domain );
    }

    if( secure instanceof Boolean )
    {
        this.setSecure( secure );
    }
};

Http.Cookie.prototype =
{
    name: '',
    value: '',
    maxAge: null,
    path: null,
    domain: null,
    secure: false,

    getDomain: function()
    {
        return this.domain;
    },

    getMaxAge: function()
    {
        return this.maxAge;
    },

    getName: function()
    {
        return this.name;
    },

    getPath: function()
    {
        return this.path;
    },

    getSecure: function()
    {
        return this.secure;
    },

    getValue: function()
    {
        return unescape( this.value );
    },

    setMaxAge: function( /*Date*/ maxAge )
    {
        this.maxAge = new Date( maxAge );
    },

    setDomain: function( /*String*/ domain )
    {
        this.domain = domain;
    },

    setName: function( /*String*/ name )
    {
        this.name = name;
    },

    setPath: function( /*String*/ path )
    {
        this.path = path;
    },

    setSecure: function( /*Boolean*/ secure )
    {
        this.secure = secure;
    },

    setValue: function( /*String*/ value )
    {
        this.value = escape( value );
    },

    destroy: function()
    {
        document.cookie = this.name + "=" +
                          ( ( this.path ) ? '; path=' + this.path : '' ) +
                          ( ( this.domain ) ? '; domain=' + this.domain : '' ) +
                          '; expires=' + ( new Date(1970, 00, 01) ).toGMTString();
        Http.updateCookies();
    },
    save: function()
    {
        document.cookie = this.name + "=" +
                          ( ( this.value ) ? escape( this.value ) : '' ) +
                          ( ( this.expires ) ? '; expires=' + this.expires.toGMTString() : '' ) +
                          ( ( this.path ) ? '; path=' + this.path : '' ) +
                          ( ( this.domain ) ? '; domain=' + this.domain : '' ) +
                          ( ( this.secure ) ? '; secure' : '' );
        Http.updateCookies();
        return true;
    }
};
/*---------------HTTP.COOKIE Class---------------*/
