/// DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING! - this file should be included seperately  

/*

Copyright (c) 2008 jack angers, jacktasia@gmail.com

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

 */
 
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function encode64(input) {
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

   do {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
         enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
         enc4 = 64;
      }

      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 
         keyStr.charAt(enc3) + keyStr.charAt(enc4);
   } while (i < input.length);
   
   return output;
}

function decode64(input) {
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   do {
      enc1 = keyStr.indexOf(input.charAt(i++));
      enc2 = keyStr.indexOf(input.charAt(i++));
      enc3 = keyStr.indexOf(input.charAt(i++));
      enc4 = keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
         output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
         output = output + String.fromCharCode(chr3);
      }
   } while (i < input.length);

   return output;
}
 
function ieXML(response) {
	//var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
	//xmlDoc.async = "true";
	//xmlDoc.loadXML(response);
	//return xmlDoc;
	
	var xml = document.createElement("xml");
	///xml.src = "data.xml";
	xml.innerHTML = response;
	document.body.appendChild(xml);
	var xmlDocument = xml.XMLDocument;
	document.body.removeChild(xml);
	return xmlDocument;
}

function mozillaXML(response) {
	var parser = new DOMParser();
	var domParsed = parser.parseFromString(response, "text/xml");
	return domParsed;
}


function jayhawk(php_file, debug) {
	this.php_file = php_file;
	this.debug = debug;
};

jayhawk.prototype.initialize = function() {
	var request;
	try {
		// Mozilla / Safari
		request = new XMLHttpRequest();
		return request;
	} catch (e) {
		// IE
		var ieModels = new Array(
			'MSXML2.XMLHTTP.5.0',
			'MSXML2.XMLHTTP.4.0',
			'MSXML2.XMLHTTP.3.0',
			'MSXML2.XMLHTTP',
			'Microsoft.XMLHTTP'
			);
		var success = false;
		// Try to locate latest XMLRequest available
		for (var i = 0; i < ieModels.length && !success; i++) {
			try {
				request = new ActiveXObject(ieModels[i]);
				success = true;
			} catch (e) { }
		}
		if (!success) {
			return false; // nothing worked
		}
		return request;
	}
}

jayhawk.prototype.call_php_function = function () { 
	var args = this.call_php_function.arguments;
	var args_num = args.length;
	var returnString = '';
	var php_func = args[0];
	
	for (var i = 1;i < args_num; i++) {
		returnString += "&jayhawk_arg_ser" + (i-1) + "=" + encode64(serialize(args[i]));
	}
	
	returnString += "&jayhawk_arg_count=" + (args_num - 1);
	returnString += "&jayhawk_function=" + php_func ;
	returnString = returnString.substring(1);
	this.send(returnString);
}

jayhawk.prototype.busy = function(request) {
	// Check to see if request is busy
	currentState = request.readyState;
	return (currentState && (currentState < 4));
}

jayhawk.prototype.send = function(data,func,funcVals) {
	var request = this.initialize();
	var thisCopy = this; //since we have a nested function below that needs to access this version of "this"
	if (request && !this.busy(request)) {
		request.onreadystatechange = function() {
			if (request.readyState == 4 && request.status == 200) { // request is done
				var response = "";
				 if (window.ActiveXObject) { // IE
					response = request.responseText;
					if (response != "") { // only create XML document if given one
						 domParsed = ieXML(response);
					}
				} else if (window.XMLHttpRequest) { // Mozilla, Safari...
					var xmlDoc = document.implementation.createDocument("", "", null);
					response = request.responseText; //this
					if (response != "") {
						domParsed = mozillaXML(response);
					}
				}
				
				var getFunc = domParsed.getElementsByTagName("argument")[0]; //only one
				if (getFunc) {
					var theFunc = getFunc.getAttribute('function');
					var toEval = theFunc + '(';
					var getArgs = domParsed.getElementsByTagName("argument");
					if (theFunc != 'jayhawk_noreturn' && getArgs.length != 0) { //if it passes this there is a func we have to call
						var theArgs = '';
						var jayhawk_arg = new Array();
						for (var i = 0;i<getArgs.length;i++){
							jayhawk_arg[i] = PHP_Unserialize(decode64(getArgs[i].getAttribute('ser')));
							theArgs += ",jayhawk_arg["+ i +"]";
						
						}
						theArgs = theArgs.substring(1);
						toEval = toEval + theArgs + ')'; 
						eval(toEval);
					}
				} else {
					if (thisCopy.debug == true) {
						alert("ERROR IN YOUR PHP CODE: \n\n" + response);
					}
				}
			}
		}
		request.open("POST",this.php_file,true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		request.send(data);
	}
}

/*
 * END JAYHAWK CODE
 * 
 Below are functions needed to make jayhawk work. 
 */
 
 
/*
These next two protypes are NEEDED FOR IE, as ie6 does not support Array.map & Array.filter by default

this prototype is provided by the Mozilla foundation and
is distributed under the MIT license.
http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
*/

if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var res = new Array();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
      {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }

    return res;
  };
}

if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        res[i] = fun.call(thisp, this[i], i, this);
    }

    return res;
  };
}

/*
next two functions from php.js project
kevin.vanzonneveld.net/techblog/category/php2js 
php.js is copyright 2008 Kevin van Zonneveld.
*/
function get_class(obj) {
     // http://kevin.vanzonneveld.net
    // +   original by: Ates Goral (http://magnetiq.com)

    if (obj instanceof Object && !(obj instanceof Array) &&
        !(obj instanceof Function) && obj.constructor) {
        var arr = obj.constructor.toString().match(/function\s*(\w+)/);
 
        if (arr && arr.length == 2) {
            return arr[1];
        }
    }
 
    return false;
}
function serialize( mixed_val ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Ates Goral (http://magnetiq.com)
    // -    depends on: get_class

    switch (typeof(mixed_val)){
        case "number":
            if (isNaN(mixed_val) || !isFinite(mixed_val)){
                return false;
            } else{
                return (Math.floor(mixed_val) == mixed_val ? "i" : "d") + ":" + mixed_val + ";";
            }
        case "string":
            return "s:" + mixed_val.length + ":\"" + mixed_val + "\";";
        case "boolean":
            return "b:" + (mixed_val ? "1" : "0") + ";";
        case "object":
            if (mixed_val == null) {
                return "N;";
            } else if (mixed_val instanceof Array) {
                var idxobj = { idx: -1 };
                return "a:" + mixed_val.length + ":{" + mixed_val.map( function ( item ) {
                        this.idx++;
                        var ser = serialize(item);
 
                        return ser ? serialize(this.idx) + ser : false;
                    }, idxobj).filter( function ( item ) {
                        return item;
                    }).join("") + "}";
            }
            else {
                var class_name = get_class(mixed_val);
 
                if (class_name == undefined){
                    return false;
                }
 
                var props = new Array();
                for (var prop in mixed_val) {
                    var ser = serialize(mixed_val[prop]);
 
                    if (ser) {
                        props.push(serialize(prop) + ser);
                    }
                }
                return "O:" + class_name.length + ":\"" + class_name + "\":" + props.length + ":{" + props.join("") + "}";
            }
        case "undefined":
            return "N;";
    }
 
    return false;
}


/*
The following two functions are part of the PHP_Unserialize package (http://www.phpguru.org/)
it is released under the terms of the GNU General Public License v2
© Copyright 2005 Richard Heyes
http://www.phpguru.org/
*/
function PHP_Unserialize(input)
{
    var result = PHP_Unserialize_(input);
    return result[0];
}

function PHP_Unserialize_(input)
{
    var length = 0;
    
    switch (input.charAt(0)) {
	/**
	* Array
	*/
	case 'a':
	    length = PHP_Unserialize_GetLength(input);
	    input  = input.substr(String(length).length + 4);

	    var arr   = new Array();
	    var key   = null;
	    var value = null;

	    for (var i=0; i<length; ++i) {
		key   = PHP_Unserialize_(input);
		input = key[1];

		value = PHP_Unserialize_(input);
		input = value[1];

		arr[key[0]] = value[0];
	    }

	    input = input.substr(1);
	    return [arr, input];
	    
	     break;
	
	/**
	* Objects
	*/
	case 'O':
	    length = PHP_Unserialize_GetLength(input);
	    var classname = String(input.substr(String(length).length + 4, length));
	    
	    input  = input.substr(String(length).length + 6 + length);
	    var numProperties = Number(input.substring(0, input.indexOf(':')))
	    input = input.substr(String(numProperties).length + 2);

	    var obj      = new Object();
	    var property = null;
	    var value    = null;

	    for (var i=0; i<numProperties; ++i) {
		key   = PHP_Unserialize_(input);
		input = key[1];
		
		// Handle private/protected
		key[0] = key[0].replace(new RegExp('^\x00' + classname + '\x00'), '');
		key[0] = key[0].replace(new RegExp('^\x00\\*\x00'), '');

		value = PHP_Unserialize_(input);
		input = value[1];

		obj[key[0]] = value[0];
	    }

	    input = input.substr(1);
	    return [obj, input];
	    break;

	/**
	* Strings
	*/
	case 's':
	    length = PHP_Unserialize_GetLength(input);
	    return [String(input.substr(String(length).length + 4, length)), input.substr(String(length).length + 6 + length)];
	    break;

	/**
	* Integers and doubles
	*/
	case 'i':
	case 'd':
	    var num = Number(input.substring(2, input.indexOf(';')));
	    return [num, input.substr(String(num).length + 3)];
	    break;
	
	/**
	* Booleans
	*/
	case 'b':
	    var bool = (input.substr(2, 1) == 1);
	    return [bool, input.substr(4)];
	    break;
	
	/**
	* Null
	*/
	case 'N':
	    return [null, input.substr(2)];
	    break;

	/**
	* Unsupported
	*/
	case 'o':
	case 'r':
	case 'C':
	case 'R':
	case 'U':
	    alert('Error: Unsupported PHP data type found!');

	/**
	* Error
	*/
	default:
	    return [null, null];
	    break;
    }
}
    
function PHP_Unserialize_GetLength(input)
{
    input = input.substring(2);
    var length = Number(input.substr(0, input.indexOf(':')));
    return length;
}

