
// ================================================================
//  jkl-parsexml.js ---- JavaScript Kantan Library for Parsing XML
//  Copyright 2005-2007 Kawasaki Yusuke <u-suke@kawa.net>
//  http://www.kawa.net/works/js/jkl/parsexml.html
// ================================================================
//  v0.01  2005/05/18  first release
//  v0.02  2005/05/20  Opera 8.0beta may be abailable but somtimes crashed
//  v0.03  2005/05/20  overrideMimeType( "text/xml" );
//  v0.04  2005/05/21  class variables: REQUEST_TYPE, RESPONSE_TYPE
//  v0.05  2005/05/22  use Msxml2.DOMDocument.5.0 for GET method on IE6
//  v0.06  2005/05/22  CDATA_SECTION_NODE
//  v0.07  2005/05/23  use Microsoft.XMLDOM for GET method on IE6
//  v0.10  2005/10/11  new function: JKL.ParseXML.HTTP.responseText()
//  v0.11  2005/10/13  new sub class: JKL.ParseXML.Text, JSON and DOM.
//  v0.12  2005/10/14  new sub class: JKL.ParseXML.CSV and CSVmap.
//  v0.13  2005/10/28  bug fixed: TEXT_NODE regexp for white spaces
//  v0.14  2005/11/06  bug fixed: TEXT_NODE regexp at Safari
//  v0.15  2005/11/08  bug fixed: JKL.ParseXML.CSV.async() method
//  v0.16  2005/11/15  new sub class: LoadVars, and UTF-8 text on Safari
//  v0.18  2005/11/16  improve: UTF-8 text file on Safari
//  v0.19  2006/02/03  use XMLHTTPRequest instead of ActiveX on IE7,iCab
//  v0.20  2006/03/22  (skipped)
//  v0.21  2006/11/30  use ActiveX again on IE7
//  v0.22  2007/01/04  JKL.ParseXML.JSON.parseResponse() updated
// ================================================================

if ( typeof(JKL) == 'undefined' ) JKL = function() {};

// ================================================================
//  class: JKL.ParseXML 

JKL.ParseXML = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, false );
    return this;
};

// ================================================================
//  class variables

JKL.ParseXML.VERSION = "0.22";
JKL.ParseXML.MIME_TYPE_XML  = "text/xml";
JKL.ParseXML.MAP_NODETYPE = [
    "",
    "ELEMENT_NODE",                 // 1
    "ATTRIBUTE_NODE",               // 2
    "TEXT_NODE",                    // 3
    "CDATA_SECTION_NODE",           // 4
    "ENTITY_REFERENCE_NODE",        // 5
    "ENTITY_NODE",                  // 6
    "PROCESSING_INSTRUCTION_NODE",  // 7
    "COMMENT_NODE",                 // 8
    "DOCUMENT_NODE",                // 9
    "DOCUMENT_TYPE_NODE",           // 10
    "DOCUMENT_FRAGMENT_NODE",       // 11
    "NOTATION_NODE"                 // 12
];

// ================================================================
//  define callback function (ajax)

JKL.ParseXML.prototype.async = function ( func, args ) {
    this.callback_func = func;      // callback function
    this.callback_arg  = args;      // first argument
};

JKL.ParseXML.prototype.onerror = function ( func, args ) {
    this.onerror_func = func;       // callback function
};

// ================================================================
//  method: parse()
//  return: parsed object
//  Download a file from remote server and parse it.

JKL.ParseXML.prototype.parse = function () {
    if ( ! this.http ) return;

    // set onerror call back 
    if ( this.onerror_func ) {
        this.http.onerror( this.onerror_func );
    }

    if ( this.callback_func ) {                             // async mode
        var copy = this;
        var proc = function() {
            if ( ! copy.http ) return;
            var data = copy.parseResponse();
            copy.callback_func( data, copy.callback_arg );  // call back
        };
        this.http.async( proc );
    }

    this.http.load();

    if ( ! this.callback_func ) {                           // sync mode
        var data = this.parseResponse();
        return data;
    }
};

// ================================================================
//  every child/children into array
JKL.ParseXML.prototype.setOutputArrayAll = function () {
    this.setOutputArray( true );
}
//  a child into scalar, children into array
JKL.ParseXML.prototype.setOutputArrayAuto = function () {
    this.setOutputArray( null );
}
//  every child/children into scalar (first sibiling only)
JKL.ParseXML.prototype.setOutputArrayNever = function () {
    this.setOutputArray( false );
}
//  specified child/children into array, other child/children into scalar
JKL.ParseXML.prototype.setOutputArrayElements = function ( list ) {
    this.setOutputArray( list );
}
//  specify how to treate child/children into scalar/array
JKL.ParseXML.prototype.setOutputArray = function ( mode ) {
    if ( typeof(mode) == "string" ) {
        mode = [ mode ];                // string into array
    }
    if ( mode && typeof(mode) == "object" ) {
        if ( mode.length < 0 ) {
            mode = false;               // false when array == [] 
        } else {
            var hash = {};
            for( var i=0; i<mode.length; i++ ) {
                hash[mode[i]] = true;
            }
            mode = hash;                // array into hashed array
            if ( mode["*"] ) {
                mode = true;            // true when includes "*"
            }
        } 
    } 
    this.usearray = mode;
}

// ================================================================
//  method: parseResponse()

JKL.ParseXML.prototype.parseResponse = function () {
    var root = this.http.documentElement();
    var data = this.parseDocument( root );
    return data;
}

// ================================================================
//  convert from DOM root node to JavaScript Object 
//  method: parseElement( rootElement )

JKL.ParseXML.prototype.parseDocument = function ( root ) {
    // debug.print( "parseDocument: "+root );
    if ( ! root ) return;

    var ret = this.parseElement( root );            // parse root node
    // debug.print( "parsed: "+ret );

    if ( this.usearray == true ) {                  // always into array
        ret = [ ret ];
    } else if ( this.usearray == false ) {          // always into scalar
        //
    } else if ( this.usearray == null ) {           // automatic
        //
    } else if ( this.usearray[root.nodeName] ) {    // specified tag
        ret = [ ret ];
    }

    var json = {};
    json[root.nodeName] = ret;                      // root nodeName
    return json;
};

// ================================================================
//  convert from DOM Element to JavaScript Object 
//  method: parseElement( element )

JKL.ParseXML.prototype.parseElement = function ( elem ) {
    // debug.print( "nodeType: "+JKL.ParseXML.MAP_NODETYPE[elem.nodeType]+" <"+elem.nodeName+">" );

    //  COMMENT_NODE

    if ( elem.nodeType == 7 ) {
        return;
    }

    //  TEXT_NODE CDATA_SECTION_NODE

    if ( elem.nodeType == 3 || elem.nodeType == 4 ) {
        // var bool = elem.nodeValue.match( /[^\u0000-\u0020]/ );
        var bool = elem.nodeValue.match( /[^\x00-\x20]/ ); // for Safari
        if ( bool == null ) return;     // ignore white spaces
        // debug.print( "TEXT_NODE: "+elem.nodeValue.length+ " "+bool );
        return elem.nodeValue;
    }

    var retval;
    var cnt = {};

    //  parse attributes

    if ( elem.attributes && elem.attributes.length ) {
        retval = {};
        for ( var i=0; i<elem.attributes.length; i++ ) {
            var key = elem.attributes[i].nodeName;
            if ( typeof(key) != "string" ) continue;
            var val = elem.attributes[i].nodeValue;
            if ( ! val ) continue;
            if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
            cnt[key] ++;
            this.addNode( retval, key, cnt[key], val );
        }
    }

    //  parse child nodes (recursive)

    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;
};

// ================================================================
//  method: addNode( hash, key, count, value )

JKL.ParseXML.prototype.addNode = function ( hash, key, cnts, val ) {
    if ( this.usearray == true ) {              // into array
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;      // push
    } else if ( this.usearray == false ) {      // into scalar
        if ( cnts == 1 ) hash[key] = val;       // only 1st sibling
    } else if ( this.usearray == null ) {
        if ( cnts == 1 ) {                      // 1st sibling
            hash[key] = val;
        } else if ( cnts == 2 ) {               // 2nd sibling
            hash[key] = [ hash[key], val ];
        } else {                                // 3rd sibling and more
            hash[key][hash[key].length] = val;
        }
    } else if ( this.usearray[key] ) {
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;      // push
    } else {
        if ( cnts == 1 ) hash[key] = val;       // only 1st sibling
    }
};

// ================================================================
//  class: JKL.ParseXML.Text 

JKL.ParseXML.Text = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.Text( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, true );
    return this;
};

JKL.ParseXML.Text.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.Text.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.Text.prototype.onerror = JKL.ParseXML.prototype.onerror;

JKL.ParseXML.Text.prototype.parseResponse = function () {
    var data = this.http.responseText();
    return data;
}

// ================================================================
//  class: JKL.ParseXML.JSON

JKL.ParseXML.JSON = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.JSON( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, true );
    return this;
};

JKL.ParseXML.JSON.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.JSON.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.JSON.prototype.onerror = JKL.ParseXML.prototype.onerror;

JKL.ParseXML.JSON.prototype.parseResponse = function () {
    var text = this.http.responseText();
    // http://www.antimon2.atnifty.com/2007/01/jklparsexmljson.html
    if ( typeof(text) == 'undefined' ) return;
    if ( ! text.length ) return;
    var data = eval( "("+text+")" );
    return data;
}

// ================================================================
//  class: JKL.ParseXML.DOM

JKL.ParseXML.DOM = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.DOM( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, false );
    return this;
};

JKL.ParseXML.DOM.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.DOM.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.DOM.prototype.onerror = JKL.ParseXML.prototype.onerror;

JKL.ParseXML.DOM.prototype.parseResponse = function () {
    var data = this.http.documentElement();
    return data;
}

// ================================================================
//  class: JKL.ParseXML.CSV

JKL.ParseXML.CSV = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.CSV( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, true );
    return this;
};

JKL.ParseXML.CSV.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.CSV.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.CSV.prototype.onerror = JKL.ParseXML.prototype.onerror;

JKL.ParseXML.CSV.prototype.parseResponse = function () {
    var text = this.http.responseText();
    var data = this.parseCSV( text );
    return data;
}

JKL.ParseXML.CSV.prototype.parseCSV = function ( text ) {
    text = text.replace( /\r\n?/g, "\n" );              // new line character
    var pos = 0;
    var len = text.length;
    var table = [];
    while( pos<len ) {
        var line = [];
        while( pos<len ) {
            if ( text.charAt(pos) == '"' ) {            // "..." quoted column
                var nextquote = text.indexOf( '"', pos+1 );
                while ( nextquote<len && nextquote > -1 ) {
                    if ( text.charAt(nextquote+1) != '"' ) {
                        break;                          // end of column
                    }
                    nextquote = text.indexOf( '"', nextquote+2 );
                }
                if ( nextquote < 0 ) {
                    // unclosed quote
                } else if ( text.charAt(nextquote+1) == "," ) { // end of column
                    var quoted = text.substr( pos+1, nextquote-pos-1 );
                    quoted = quoted.replace(/""/g,'"');
                    line[line.length] = quoted;
                    pos = nextquote+2;
                    continue;
                } else if ( text.charAt(nextquote+1) == "\n" || // end of line
                            len==nextquote+1 ) {                // end of file
                    var quoted = text.substr( pos+1, nextquote-pos-1 );
                    quoted = quoted.replace(/""/g,'"');
                    line[line.length] = quoted;
                    pos = nextquote+2;
                    break;
                } else {
                    // invalid column
                }
            }
            var nextcomma = text.indexOf( ",", pos );
            var nextnline = text.indexOf( "\n", pos );
            if ( nextnline < 0 ) nextnline = len;
            if ( nextcomma > -1 && nextcomma < nextnline ) {
                line[line.length] = text.substr( pos, nextcomma-pos );
                pos = nextcomma+1;
            } else {                                    // end of line
                line[line.length] = text.substr( pos, nextnline-pos );
                pos = nextnline+1;
                break;
            }
        }
        if ( line.length >= 0 ) {
            table[table.length] = line;                 // push line
        }
    }
    if ( table.length < 0 ) return;                     // null data
    return table;
};

// ================================================================
//  class: JKL.ParseXML.CSVmap

JKL.ParseXML.CSVmap = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.CSVmap( '"+url+"', '"+query+"', '"+method+"' );" );
    this.http = new JKL.ParseXML.HTTP( url, query, method, true );
    return this;
};

JKL.ParseXML.CSVmap.prototype.parse = JKL.ParseXML.prototype.parse;
JKL.ParseXML.CSVmap.prototype.async = JKL.ParseXML.prototype.async;
JKL.ParseXML.CSVmap.prototype.onerror = JKL.ParseXML.prototype.onerror;
JKL.ParseXML.CSVmap.prototype.parseCSV = JKL.ParseXML.CSV.prototype.parseCSV;

JKL.ParseXML.CSVmap.prototype.parseResponse = function () {
    var text = this.http.responseText();
    var source = this.parseCSV( text );
    if ( ! source ) return;
    if ( source.length < 0 ) return;

    var title = source.shift();                 // first line as title
    var data = [];
    for( var i=0; i<source.length; i++ ) {
        var hash = {};
        for( var j=0; j<title.length && j<source[i].length; j++ ) {
            hash[title[j]] = source[i][j];      // array to map
        }
        data[data.length] = hash;               // push line
    }
    return data;
}

// ================================================================
//  class: JKL.ParseXML.LoadVars

JKL.ParseXML.LoadVars = function ( url, query, method ) {
    // debug.print( "new JKL.ParseXML.LoadVars( '"+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" );              // new line character
    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;
};

// ================================================================
//  class: JKL.ParseXML.HTTP
//  constructer: new JKL.ParseXML.HTTP()

JKL.ParseXML.HTTP = function( url, query, method, textmode ) {
    // debug.print( "new JKL.ParseXML.HTTP( '"+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;
};

// ================================================================
//  class variables

JKL.ParseXML.HTTP.REQUEST_TYPE  = "application/x-www-form-urlencoded";
JKL.ParseXML.HTTP.ACTIVEX_XMLDOM  = "Microsoft.XMLDOM";  // Msxml2.DOMDocument.5.0
JKL.ParseXML.HTTP.ACTIVEX_XMLHTTP = "Microsoft.XMLHTTP"; // Msxml2.XMLHTTP.3.0
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;
}

// ================================================================
//  [IE+IXMLDOMElement]
//      XML     text/xml            OK
//      XML     application/rdf+xml OK
//      TEXT    text/plain          NG
//      TEXT    others              NG
//  [IE+IXMLHttpRequest]
//      XML     text/xml            OK
//      XML     application/rdf+xml NG
//      TEXT    text/plain          OK
//      TEXT    others              OK
//  [Firefox+XMLHttpRequest]
//      XML     text/xml            OK
//      XML     application/rdf+xml OK (overrideMimeType)
//      TEXT    text/plain          OK
//      TEXT    others              OK (overrideMimeType)
//  [Opera+XMLHttpRequest]
//      XML     text/xml            OK
//      XML     application/rdf+xml OK
//      TEXT    text/plain          OK
//      TEXT    others              OK
// ================================================================

JKL.ParseXML.HTTP.prototype.load = function() {
    // create XMLHttpRequest object
    if ( window.ActiveXObject ) {                           // IE5.5,6,7
        var activex = JKL.ParseXML.HTTP.ACTIVEX_XMLHTTP;    // IXMLHttpRequest
        if ( this.method == "GET" && ! this.textmode ) {
            // use IXMLDOMElement to accept any mime types
            // because overrideMimeType() is not available on IE6
            activex = JKL.ParseXML.HTTP.ACTIVEX_XMLDOM;     // IXMLDOMElement
        }
        // debug.print( "new ActiveXObject( '"+activex+"' )" );
        this.req = new ActiveXObject( activex );
    } else if ( window.XMLHttpRequest ) {                   // Firefox, Opera, iCab
        // debug.print( "new XMLHttpRequest()" );
        this.req = new XMLHttpRequest();
    }

    // async mode when call back function is specified
    var async_flag = this.async_func ? true : false;
    // debug.print( "async: "+ async_flag );

    // open for XMLHTTPRequest (not for IXMLDOMElement)
    if ( typeof(this.req.send) != "undefined" ) {
        // debug.print( "open( '"+this.method+"', '"+this.url+"', "+async_flag+" );" );
        this.req.open( this.method, this.url, async_flag );
    }

//  // If-Modified-Since: Thu, 01 Jun 1970 00:00:00 GMT
//  if ( typeof(this.req.setRequestHeader) != "undefined" ) {
//      // debug.print( "If-Modified-Since"+JKL.ParseXML.HTTP.EPOCH_TIMESTAMP );
//      this.req.setRequestHeader( "If-Modified-Since", JKL.ParseXML.HTTP.EPOCH_TIMESTAMP );
//  }

    // Content-Type: application/x-www-form-urlencoded (request header)
    // Some server does not accept without request content-type.
    if ( typeof(this.req.setRequestHeader) != "undefined" ) {
        // debug.print( "Content-Type: "+JKL.ParseXML.HTTP.REQUEST_TYPE+" (request)" );
        this.req.setRequestHeader( "Content-Type", JKL.ParseXML.HTTP.REQUEST_TYPE );
    }

    // Content-Type: text/xml (response header)
    // FireFox does not accept other mime types like application/rdf+xml etc.
    if ( typeof(this.req.overrideMimeType) != "undefined" && ! this.textmode ) {
        // debug.print( "Content-Type: "+JKL.ParseXML.MIME_TYPE_XML+" (response)" );
        this.req.overrideMimeType( JKL.ParseXML.MIME_TYPE_XML );
    }

    // set call back handler when async mode
    if ( async_flag ) {
        var copy = this;
        copy.already_done = false;                  // not parsed yet
        var check_func = function () {
            if ( copy.req.readyState != 4 ) return;
            // debug.print( "readyState(async): "+copy.req.readyState );
            var succeed = copy.checkResponse();
            // debug.print( "checkResponse(async): "+succeed );
            if ( ! succeed ) return;                // failed
            if ( copy.already_done ) return;        // parse only once
            copy.already_done = true;               // already parsed
            copy.async_func();                      // call back async
        };
        this.req.onreadystatechange = check_func;
        // for document.implementation.createDocument
        // this.req.onload = check_func;
    }

    // send the request and query string
    if ( typeof(this.req.send) != "undefined" ) {
        // debug.print( "XMLHTTPRequest: send( '"+this.query+"' );" );
        this.req.send( this.query );                        // XMLHTTPRequest
    } else if ( typeof(this.req.load) != "undefined" ) {
        // debug.print( "IXMLDOMElement: load( '"+this.url+"' );" );
        this.req.async = async_flag;
        this.req.load( this.url );                          // IXMLDOMElement
    }

    // just return when async mode
    if ( async_flag ) return;

    var succeed = this.checkResponse();
    // debug.print( "checkResponse(sync): "+succeed );
}

// ================================================================
//  method: checkResponse()

JKL.ParseXML.HTTP.prototype.checkResponse = function() {
    // parseError on IXMLDOMElement
    if ( this.req.parseError && this.req.parseError.errorCode != 0 ) {
        // debug.print( "parseError: "+this.req.parseError.reason );
        if ( this.onerror_func ) this.onerror_func( this.req.parseError.reason );
        return false;                       // failed
    }

    // HTTP response code
    if ( this.req.status-0 > 0 &&
         this.req.status != 200 &&          // OK
         this.req.status != 206 &&          // Partial Content
         this.req.status != 304 ) {         // Not Modified
        // debug.print( "status: "+this.req.status );
        if ( this.onerror_func ) this.onerror_func( this.req.status );
        return false;                       // failed
    }

    return true;                            // succeed
}

// ================================================================
//  method: documentElement()
//  return: XML DOM in response body

JKL.ParseXML.HTTP.prototype.documentElement = function() {
    // debug.print( "documentElement: "+this.req );
    if ( ! this.req ) return;
    if ( this.req.responseXML ) {
        return this.req.responseXML.documentElement;    // XMLHTTPRequest
    } else {
        return this.req.documentElement;                // IXMLDOMDocument
    }
}

// ================================================================
//  method: responseText()
//  return: text string in response body

JKL.ParseXML.HTTP.prototype.responseText = function() {
    // debug.print( "responseText: "+this.req );
    if ( ! this.req ) return;

    //  Safari and Konqueror cannot understand the encoding of text files.
    if ( navigator.appVersion.match( "KHTML" ) ) {
        var esc = escape( this.req.responseText );
//        debug.print( "escape: "+esc );
        if ( ! esc.match("%u") && esc.match("%") ) {
            return decodeURIComponent(esc);
        }
    }

    return this.req.responseText;
}

// ================================================================
//  http://msdn.microsoft.com/library/en-us/xmlsdk/html/d051f7c5-e882-42e8-a5b6-d1ce67af275c.asp
// ================================================================


/**
* Function : dump()
* Arguments: The data - array,hash(associative array),object
*    The level - OPTIONAL
* Returns  : The textual representation of the array.
* This function was inspired by the print_r function of PHP.
* This will accept some data as the argument and return a
* text that will be a more readable version of the
* array/hash/object that is given.
*/
function dump(arr,level) {
var dumped_text = "";
if(!level) level = 0;

//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += "    ";

if(typeof(arr) == 'object') { //Array/Hashes/Objects
 for(var item in arr) {
  var value = arr[item];
 
  if(typeof(value) == 'object') { //If it is an array,
   dumped_text += level_padding + "'" + item + "' ...\n";
   dumped_text += dump(value,level+1);
  } else {
   dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
  }
 }
} else { //Stings/Chars/Numbers etc.
 dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
} 


function htmlEscape(plainText)
{	var SAFECHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";	
	var HEX = "0123456789ABCDEF";
  var charMap = Array();
  charMap["34"] = '&quot;';
  charMap["38"] = '&amp;';
  charMap["60"] = '&lt;';
  charMap["62"] = '&gt;';
  charMap["160"] = '&nbsp;';
  charMap["161"] = '&iexcl;';
  charMap["162"] = '&cent;';
  charMap["163"] = '&pound;';
  charMap["164"] = '&curren;';
  charMap["165"] = '&yen;';
  charMap["166"] = '&brvbar;';
  charMap["167"] = '&sect;';
  charMap["168"] = '&uml;';
  charMap["169"] = '&copy;';
  charMap["170"] = '&ordf;';
  charMap["171"] = '&laquo;';
  charMap["172"] = '&not;';
  charMap["173"] = '&shy;';
  charMap["174"] = '&reg;';
  charMap["175"] = '&macr;';
  charMap["176"] = '&deg;';
  charMap["177"] = '&plusmn;';
  charMap["178"] = '&sup2;';
  charMap["179"] = '&sup3;';
  charMap["180"] = '&acute;';
  charMap["181"] = '&micro;';
  charMap["182"] = '&para;';
  charMap["183"] = '&middot;';
  charMap["184"] = '&cedil;';
  charMap["185"] = '&sup1;';
  charMap["186"] = '&ordm;';
  charMap["187"] = '&raquo;';
  charMap["188"] = '&frac14;';
  charMap["189"] = '&frac12;';
  charMap["190"] = '&frac34;';
  charMap["191"] = '&iquest;';
  charMap["192"] = '&Agrave;';
  charMap["193"] = '&Aacute;';
  charMap["194"] = '&Acirc;';
  charMap["195"] = '&Atilde;';
  charMap["196"] = '&Auml;';
  charMap["197"] = '&Aring;';
  charMap["198"] = '&AElig;';
  charMap["199"] = '&Ccedil;';
  charMap["200"] = '&Egrave;';
  charMap["201"] = '&Eacute;';
  charMap["202"] = '&Ecirc;';
  charMap["203"] = '&Euml;';
  charMap["204"] = '&Igrave;';
  charMap["205"] = '&Iacute;';
  charMap["206"] = '&Icirc;';
  charMap["207"] = '&Iuml;';
  charMap["208"] = '&ETH;';
  charMap["209"] = '&Ntilde;';
  charMap["210"] = '&Ograve;';
  charMap["211"] = '&Oacute;';
  charMap["212"] = '&Ocirc;';
  charMap["213"] = '&Otilde;';
  charMap["214"] = '&Ouml;';
  charMap["215"] = '&times;';
  charMap["216"] = '&Oslash;';
  charMap["217"] = '&Ugrave;';
  charMap["218"] = '&Uacute;';
  charMap["219"] = '&Ucirc;';
  charMap["220"] = '&Uuml;';
  charMap["221"] = '&Yacute;';
  charMap["222"] = '&THORN;';
  charMap["223"] = '&szlig;';
  charMap["224"] = '&agrave;';
  charMap["225"] = '&aacute;';
  charMap["226"] = '&acirc;';
  charMap["227"] = '&atilde;';
  charMap["228"] = '&auml;';
  charMap["229"] = '&aring;';
  charMap["230"] = '&aelig;';
  charMap["231"] = '&ccedil;';
  charMap["232"] = '&egrave;';
  charMap["233"] = '&eacute;';
  charMap["234"] = '&ecirc;';
  charMap["235"] = '&euml;';
  charMap["236"] = '&igrave;';
  charMap["237"] = '&iacute;';
  charMap["238"] = '&icirc;';
  charMap["239"] = '&iuml;';
  charMap["240"] = '&eth;';
  charMap["241"] = '&ntilde;';
  charMap["242"] = '&ograve;';
  charMap["243"] = '&oacute;';
  charMap["244"] = '&ocirc;';
  charMap["245"] = '&otilde;';
  charMap["246"] = '&ouml;';
  charMap["247"] = '&divide;';
  charMap["248"] = '&oslash;';
  charMap["249"] = '&ugrave;';
  charMap["250"] = '&uacute;';
  charMap["251"] = '&ucirc;';
  charMap["252"] = '&uuml;';
  charMap["253"] = '&yacute;';
  charMap["254"] = '&thorn;';
  charMap["255"] = '&yuml;';
  charMap["338"] = '&OElig;';
  charMap["339"] = '&oelig;';
  charMap["352"] = '&Scaron;';
  charMap["353"] = '&scaron;';
  charMap["376"] = '&Yuml;';
  charMap["402"] = '&fnof;';
  charMap["710"] = '&circ;';
  charMap["732"] = '&tilde;';
  charMap["913"] = '&Alpha;';
  charMap["914"] = '&Beta;';
  charMap["915"] = '&Gamma;';
  charMap["916"] = '&Delta;';
  charMap["917"] = '&Epsilon;';
  charMap["918"] = '&Zeta;';
  charMap["919"] = '&Eta;';
  charMap["920"] = '&Theta;';
  charMap["921"] = '&Iota;';
  charMap["922"] = '&Kappa;';
  charMap["923"] = '&Lambda;';
  charMap["924"] = '&Mu;';
  charMap["925"] = '&Nu;';
  charMap["926"] = '&Xi;';
  charMap["927"] = '&Omicron;';
  charMap["928"] = '&Pi;';
  charMap["929"] = '&Rho;';
  charMap["931"] = '&Sigma;';
  charMap["932"] = '&Tau;';
  charMap["933"] = '&Upsilon;';
  charMap["934"] = '&Phi;';
  charMap["935"] = '&Chi;';
  charMap["936"] = '&Psi;';
  charMap["937"] = '&Omega;';
  charMap["945"] = '&alpha;';
  charMap["946"] = '&beta;';
  charMap["947"] = '&gamma;';
  charMap["948"] = '&delta;';
  charMap["949"] = '&epsilon;';
  charMap["950"] = '&zeta;';
  charMap["951"] = '&eta;';
  charMap["952"] = '&theta;';
  charMap["953"] = '&iota;';
  charMap["954"] = '&kappa;';
  charMap["955"] = '&lambda;';
  charMap["956"] = '&mu;';
  charMap["957"] = '&nu;';
  charMap["958"] = '&xi;';
  charMap["959"] = '&omicron;';
  charMap["960"] = '&pi;';
  charMap["961"] = '&rho;';
  charMap["962"] = '&sigmaf;';
  charMap["963"] = '&sigma;';
  charMap["964"] = '&tau;';
  charMap["965"] = '&upsilon;';
  charMap["966"] = '&phi;';
  charMap["967"] = '&chi;';
  charMap["968"] = '&psi;';
  charMap["969"] = '&omega;';
  charMap["977"] = '&thetasym;';
  charMap["978"] = '&upsih;';
  charMap["982"] = '&piv;';
  charMap["8194"] = '&ensp;';
  charMap["8195"] = '&emsp;';
  charMap["8201"] = '&thinsp;';
  charMap["8204"] = '&zwnj;';
  charMap["8205"] = '&zwj;';
  charMap["8206"] = '&lrm;';
  charMap["8207"] = '&rlm;';
  charMap["8211"] = '&ndash;';
  charMap["8212"] = '&mdash;';
  charMap["8216"] = '&lsquo;';
  charMap["8217"] = '&rsquo;';
  charMap["8218"] = '&sbquo;';
  charMap["8220"] = '&ldquo;';
  charMap["8221"] = '&rdquo;';
  charMap["8222"] = '&bdquo;';
  charMap["8224"] = '&dagger;';
  charMap["8225"] = '&Dagger;';
  charMap["8226"] = '&bull;';
  charMap["8230"] = '&hellip;';
  charMap["8240"] = '&permil;';
  charMap["8242"] = '&prime;';
  charMap["8243"] = '&Prime;';
  charMap["8249"] = '&lsaquo;';
  charMap["8250"] = '&rsaquo;';
  charMap["8254"] = '&oline;';
  charMap["8260"] = '&frasl;';
  charMap["8364"] = '&euro;';
  charMap["8465"] = '&image;';
  charMap["8472"] = '&weierp;';
  charMap["8476"] = '&real;';
  charMap["8482"] = '&trade;';
  charMap["8501"] = '&alefsym;';
  charMap["8592"] = '&larr;';
  charMap["8593"] = '&uarr;';
  charMap["8594"] = '&rarr;';
  charMap["8595"] = '&darr;';
  charMap["8596"] = '&harr;';
  charMap["8629"] = '&crarr;';
  charMap["8656"] = '&lArr;';
  charMap["8657"] = '&uArr;';
  charMap["8658"] = '&rArr;';
  charMap["8659"] = '&dArr;';
  charMap["8660"] = '&hArr;';
  charMap["8704"] = '&forall;';
  charMap["8706"] = '&part;';
  charMap["8707"] = '&exist;';
  charMap["8709"] = '&empty;';
  charMap["8711"] = '&nabla;';
  charMap["8712"] = '&isin;';
  charMap["8713"] = '&notin;';
  charMap["8715"] = '&ni;';
  charMap["8719"] = '&prod;';
  charMap["8721"] = '&sum;';
  charMap["8722"] = '&minus;';
  charMap["8727"] = '&lowast;';
  charMap["8730"] = '&radic;';
  charMap["8733"] = '&prop;';
  charMap["8734"] = '&infin;';
  charMap["8736"] = '&ang;';
  charMap["8743"] = '&and;';
  charMap["8744"] = '&or;';
  charMap["8745"] = '&cap;';
  charMap["8746"] = '&cup;';
  charMap["8747"] = '&int;';
  charMap["8756"] = '&there4;';
  charMap["8764"] = '&sim;';
  charMap["8773"] = '&cong;';
  charMap["8776"] = '&asymp;';
  charMap["8800"] = '&ne;';
  charMap["8801"] = '&equiv;';
  charMap["8804"] = '&le;';
  charMap["8805"] = '&ge;';
  charMap["8834"] = '&sub;';
  charMap["8835"] = '&sup;';
  charMap["8836"] = '&nsub;';
  charMap["8838"] = '&sube;';
  charMap["8839"] = '&supe;';
  charMap["8853"] = '&oplus;';
  charMap["8855"] = '&otimes;';
  charMap["8869"] = '&perp;';
  charMap["8901"] = '&sdot;';
  charMap["8968"] = '&lceil;';
  charMap["8969"] = '&rceil;';
  charMap["8970"] = '&lfloor;';
  charMap["8971"] = '&rfloor;';
  charMap["9001"] = '&lang;';
  charMap["9002"] = '&rang;';
  charMap["9674"] = '&loz;';
  charMap["9824"] = '&spades;';
  charMap["9827"] = '&clubs;';
  charMap["9829"] = '&hearts;';
  charMap["9830"] = '&diams;';

	var encoded = "";
	for (var i = 0; i < plainText.length; i++ ) {
		var ch = plainText.charAt(i);
	    if (ch == " ") {
		    encoded += " "; //"+";	
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
        alert(charCode);
			if (typeof(charMap["charCode"]) != 'undefined') {
			  encoded += charMap["charCode"];
			} else {
				encoded += "&x";//"%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} 

	return encoded;
}

function urlDecode(encoded)
{  var HEXCHARS = "0123456789ABCDEFabcdef"; 
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2) 
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while
   return plaintext;
}


function search7Ads(query,cnt)
{ var xml = new JKL.ParseXML('http://www.jackpotpayout.com/cgi-bin/7search.cgi?Query='+escape(query)+'&AdCnt='+cnt);
  var data = xml.parse();
  //document.write(dump(data));
  for(i=0;i<data.RESULTS.SITE.length;i++)
  { document.write('<a href="'+data.RESULTS.SITE[i].URL+'" target="_blank"><b>'+data.RESULTS.SITE[i].NAME+'</b></a><br/>');
    document.write(data.RESULTS.SITE[i].DESCRIPTION+'<br/><hr/>\n');
  }
}
