if ( typeof(JKL) == 'undefined' ) JKL = function() {};


JKL.ParseXML = function ( url, query, method ) {
    this.http = new JKL.ParseXML.HTTP( url, query, method, false );
    return this;
};



JKL.ParseXML.prototype.parse = function () {
    if ( ! this.http ) return;


    if ( this.onerror_func ) {
        this.http.onerror( this.onerror_func );
    }

    if ( this.callback_func ) {
        var copy = this;
        var proc = function() {
            if ( ! copy.http ) return;
            var data = copy.parseResponse();
            copy.callback_func( data, copy.callback_arg );
        };
        this.http.async( proc );
    }

    this.http.load();

    if ( ! this.callback_func ) {
        var data = this.parseResponse();
        return data;
    }
};


JKL.ParseXML.prototype.parseResponse = function () {
    var root = this.http.documentElement();
    var data = this.parseDocument( root );
    return data;
}


JKL.ParseXML.prototype.parseDocument = function ( root ) {

    if ( ! root ) return;

    var ret = this.parseElement( root );

    if ( this.usearray == true ) {
        ret = [ ret ];
    } else if ( this.usearray == false ) {
    } else if ( this.usearray == null ) {
    } else if ( this.usearray[root.nodeName] ) {
        ret = [ ret ];
    }

    var json = {};
    json[root.nodeName] = ret;
    return json;
};



JKL.ParseXML.prototype.parseElement = function ( elem ) {


    if ( elem.nodeType == 7 ) {
        return;
    }



    if ( elem.nodeType == 3 || elem.nodeType == 4 ) {
        var bool = elem.nodeValue.match( /[^\x00-\x20]/ );
        if ( bool == null ) return;
        return elem.nodeValue;
    }

    var retval;
    var cnt = {};


    if ( elem.childNodes && elem.childNodes.length ) {
        var textonly = true;
        if ( retval ) textonly = false;        // some attributes exists
        for ( var i=0; i<elem.childNodes.length && textonly; i++ ) {
            var ntype = elem.childNodes[i].nodeType;
            if ( ntype == 3 || ntype == 4 ) continue;
            textonly = false;
        }
        if ( textonly ) {
            if ( ! retval ) retval = "";
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                retval += elem.childNodes[i].nodeValue;
            }
        } else {
            if ( ! retval ) retval = {};
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                var key = elem.childNodes[i].nodeName;
                if ( typeof(key) != "string" ) continue;
                var val = this.parseElement( elem.childNodes[i] );
                if ( ! val ) continue;
                if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
                cnt[key] ++;
                this.addNode( retval, key, cnt[key], val );
            }
        }
    }
    return retval;
};



JKL.ParseXML.prototype.addNode = function ( hash, key, cnts, val ) {
    if ( this.usearray == true ) {
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;
    } else if ( this.usearray == false ) {
        if ( cnts == 1 ) hash[key] = val;
    } else if ( this.usearray == null ) {
        if ( cnts == 1 ) {
            hash[key] = val;
        } else if ( cnts == 2 ) {
            hash[key] = [ hash[key], val ];
        } else {
            hash[key][hash[key].length] = val;
        }
    } else if ( this.usearray[key] ) {
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;
    } else {
        if ( cnts == 1 ) hash[key] = val;
    }
};




JKL.ParseXML.LoadVars = function ( url, query, method ) {
    this.http = new JKL.ParseXML.HTTP( url, query, method, true );
    return this;
};

JKL.ParseXML.LoadVars.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.LoadVars.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.LoadVars.prototype.onerror = JKL.ParseXML.prototype.onerror;

JKL.ParseXML.LoadVars.prototype.parseResponse = function () {
    var text = this.http.responseText();
    text = text.replace( /\r\n?/g, "\n" );
    var hash = {};
    var list = text.split( "&" );
    for( var i=0; i<list.length; i++ ) {
        var eq = list[i].indexOf( "=" );
        if ( eq > -1 ) {
            var key = decodeURIComponent(list[i].substr(0,eq).replace("+","%20"));
            var val = decodeURIComponent(list[i].substr(eq+1).replace("+","%20"));
            hash[key] = val;
        } else {
            hash[list[i]] = "";
        }
    }
    return hash;
};


JKL.ParseXML.HTTP = function( url, query, method, textmode ) {
    this.url = url;
    if ( typeof(query) == "string" ) {
        this.query = query;
    } else {
        this.query = "";
    }
    if ( method ) {
        this.method = method;
    } else if ( typeof(query) == "string" ) {
        this.method = "POST";
    } else {
        this.method = "GET";
    }
    this.textmode = textmode ? true : false;
    this.req = null;
    this.xmldom_flag = false;
    this.onerror_func  = null;
    this.callback_func = null;
    this.already_done = null;
    return this;
};

JKL.ParseXML.HTTP.REQUEST_TYPE  = "application/x-www-form-urlencoded";
JKL.ParseXML.HTTP.ACTIVEX_XMLDOM  = "Microsoft.XMLDOM";
JKL.ParseXML.HTTP.ACTIVEX_XMLHTTP = "Microsoft.XMLHTTP";
JKL.ParseXML.HTTP.EPOCH_TIMESTAMP = "Thu, 01 Jun 1970 00:00:00 GMT"

// ================================================================

JKL.ParseXML.HTTP.prototype.onerror = JKL.ParseXML.prototype.onerror;
JKL.ParseXML.HTTP.prototype.async = function( func ) {
    this.async_func = func;
}



JKL.ParseXML.HTTP.prototype.load = function() {

    if ( window.ActiveXObject ) {
        var activex = JKL.ParseXML.HTTP.ACTIVEX_XMLHTTP;
        if ( this.method == "GET" && ! this.textmode ) {
            activex = JKL.ParseXML.HTTP.ACTIVEX_XMLDOM;
        }

        this.req = new ActiveXObject( activex );
    } else if ( window.XMLHttpRequest ) {

        this.req = new XMLHttpRequest();
    }


    var async_flag = this.async_func ? true : false;

    if ( typeof(this.req.send) != "undefined" ) {

        this.req.open( this.method, this.url, async_flag );
    }


    if ( typeof(this.req.setRequestHeader) != "undefined" ) {

        this.req.setRequestHeader( "Content-Type", JKL.ParseXML.HTTP.REQUEST_TYPE );
    }


    if ( typeof(this.req.overrideMimeType) != "undefined" && ! this.textmode ) {

        this.req.overrideMimeType( JKL.ParseXML.MIME_TYPE_XML );
    }


    if ( async_flag ) {
        var copy = this;
        copy.already_done = false;
        var check_func = function () {
            if ( copy.req.readyState != 4 ) return;

            var succeed = copy.checkResponse();

            if ( ! succeed ) return;
            if ( copy.already_done ) return;
            copy.already_done = true;
            copy.async_func();
        };
        this.req.onreadystatechange = check_func;

    }


    if ( typeof(this.req.send) != "undefined" ) {

        this.req.send( this.query );
    } else if ( typeof(this.req.load) != "undefined" ) {

        this.req.async = async_flag;
        this.req.load( this.url );
    }


    if ( async_flag ) return;

    var succeed = this.checkResponse();

}


JKL.ParseXML.HTTP.prototype.checkResponse = function() {

    if ( this.req.parseError && this.req.parseError.errorCode != 0 ) {

        if ( this.onerror_func ) this.onerror_func( this.req.parseError.reason );
        return false;
    }


    if ( this.req.status-0 > 0 &&
         this.req.status != 200 &&
         this.req.status != 206 &&
         this.req.status != 304 ) {

        if ( this.onerror_func ) this.onerror_func( this.req.status );
        return false;
    }

    return true;
}


JKL.ParseXML.HTTP.prototype.documentElement = function() {

    if ( ! this.req ) return;
    if ( this.req.responseXML ) {
        return this.req.responseXML.documentElement;
    } else {
        return this.req.documentElement;
    }
}
