/* Execute a vote on reviews */
function dovote(rv_id, vote)
{
    var args, td;
    td = document.getElementById("vote_"+rv_id);
    if (!td)	/* oops? */
    	return;
    /* change graphic to waiting status */
    td.innerHTML = "<small>voting...</small>";
    args = new Array();
    args.rv_id = rv_id;
    args.vote = vote;
    asyncCallServer("/reviews/dovote.php", args, voteCallback);
}

/* called once vote response from server is received
 * expects following fields to be set:
 * res.rv_id ... rv_id of review
 * res.vote ... vote that has been cast
 * res.error ... set to TRUE if an error has been encountered
 */
function voteCallback(res)
{
    var td, gfx;

    td = document.getElementById("vote_"+res.rv_id);
    if (!td)	/* oops? */
	return;
    /* change graphic to resulting voted status */
    if (res.error)
	gfx = "<small>Error</small>";
    else
    {
	if (res.vote == 0)
        {
	    gfx = "<a onclick='dovote("+res.rv_id+",1)' title='I like this review'><img src='/style/thumbs-up.png' border=0></a>\n";
	    gfx += "<a onclick='dovote("+res.rv_id+",-1)' title='I do not like this review'><img src='/style/thumbs-down.png' border=0></a>";
	}
        else
        {
	    if (res.vote == 1)
		gfx = "<img src='/style/thumbs-up-done.png' alt='Voted: thumbs up' title='Vote cast: I like this review'>\n";
	    else
		gfx = "<img src='/style/thumbs-down-done.png' alt='Voted: thumbs down' title='Vote cast: I do not like this review'>\n";
	    gfx += "<a onclick='dovote("+res.rv_id+",0)' title='Remove my vote'><img src='/style/delete.png' alt='X' border=0></a>\n";
	}
    }
    td.innerHTML = gfx;
}


/* helper function to create the XMLHttpRequest object
 * depending on the browser used
 * returns the object on success, NULL on failure
 */
function createXMLHttpRequest()
{
    try { return new XMLHttpRequest(); }
	catch(exception) { /* nop */ }
    try { return new ActiveXObject("Microsoft.XMLHTTP"); }
	catch(exception) { /* nop */ }
    try { return new ActiveXObject("Msxml2.XMLHTTP"); }
	catch(exception) { /* nop */ }
    return null;
}


/* simple Pool class that manages objects and reuses empty spots
 * provides add(), get(), and remove() functions
 */
function Pool()
{
    this.add = function(obj, callback)
    {
	var o = new Object;
	o.request = obj;
	o.callback = callback;
	for (i=0; i<this.pool.length; i++)
	    if (typeof this.pool[i] != 'object')
	    {
		this.pool[i] = o;
		return i;
	    }
	this.pool.push(o);
	return (this.pool.length - 1);
    };

    this.get = function(objid)
    {
	return this.pool[objid];
    };

    this.remove = function(objid)
    {
	this.pool[objid] = 0;
    };

    this.pool = new Array();
}


var req_pool = new Pool();


/* helper function for callbacks
 * checks for correct state and server response
 * decodes response into an array and calls real callback function
 * (server response is assumed to be serialized PHP array with callback entry)
 */
function asyncCallback(req_id)
{
    var res, req;

    res = req_pool.get(req_id);
    req = res.request;
    if (req.readyState != 4)	/* wait until response is "LOADED" */
	return;
    if (req.status != 200)
	return;			/* silently ignore server error */
    
    var phpszr = new PHP_Serializer(true);
    result = phpszr.unserialize(req.responseText);

    res.callback(result);	/* callback function with result array */
    req_pool.remove(req_id);
}


/* calls server with GET method
 * url ... URL to call. It is assumed that it has no parameters attached yet
 * args ... array of arguments to be passed to server
 * callback ... function to process result from server asynchronously
 */
function asyncCallServer(url, args, callback)
{
    var req, req_id, delimiter, handler;

    if (window.XMLHttpRequest)
    {
	req = createXMLHttpRequest();
    }
    else
    {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req_id = req_pool.add(req, callback);
    handler = function() { asyncCallback(req_id); };
    req.onreadystatechange = handler;
    delimiter = "?";
    for (var reqvalue in args)
    {
	url += delimiter + reqvalue + "=" + encodeURIComponent(args[reqvalue]);
	delimiter = "&";
    }
    req.open("GET", url, true);  /* no user/pw -> doesn't work in admin area */
    req.send("");
}


/*************************************************************************
 *
 * Object PHP_Serializer
 * 	JavaScript to PHP serialize / unserialize class.
 * This class converts php variables to javascript and vice versa.
 *
 * @author              Andrea Giammarchi
 * @site		www.devpro.it
 * @date                2005/11/26
 * @specialthanks	Fabio Sutto, Kentaromiura, Kroc Camen, Cecile Maigrot, John C.Scott, Matteo Galli
 *
 * @version             2.2, tested on FF 1.0, 1.5, IE 5, 5.5, 6, 7 beta 2, Opera 8.5, Konqueror 3.5, Safari 2.0.3
 */
function PHP_Serializer(UTF8) {
	
	/** public methods */
	function serialize(v) {
		// returns serialized var
		var	s;
		switch(v) {
			case null:
				s = "N;";
				break;
			default:
				s = this[this.__sc2s(v)] ? this[this.__sc2s(v)](v) : this[this.__sc2s(__o)](v);
				break;
		};
		return s;
	};
	
	function unserialize(s) {
		// returns unserialized var from a php serialized string
		__c = 0;
		__s = s;
		return this[__s.substr(__c, 1)]();
	};
	
	function stringBytes(s) {
		// returns the php lenght of a string (chars, not bytes)
		return s.length;
	};
	
	function stringBytesUTF8(s) {
		// returns the php lenght of a string (bytes, not chars)
		var 	c, b = 0,
			l = s.length;
		while(l) {
			c = s.charCodeAt(--l);
			b += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4));
		};
		return b;
	};
	
	/** private methods */
	function __sc2s(v) {
		return v.constructor.toString();
	};
	
	function __sc2sKonqueror(v) {
		var	f;
		switch(typeof(v)) {
			case ("string" || v instanceof String):
				f = "__sString";
				break;
			case ("number" || v instanceof Number):
				f = "__sNumber";
				break;
			case ("boolean" || v instanceof Boolean):
				f = "__sBoolean";
				break;
			case ("function" || v instanceof Function):
				f = "__sFunction";
				break;
			default:
				f = (v instanceof Array) ? "__sArray" : "__sObject";
				break;
		};
		return f;
	};
	
	function __sNConstructor(c) {
		return (c === "[function]" || c === "(Internal Function)");
	};
	
	function __sCommonAO(v) {
		var	b, n,
			a = 0,
			s = [];
		for(b in v) {
			n = v[b] == null;
			if(n || v[b].constructor != Function) {
				s[a] = [
					(!isNaN(b) && parseInt(b).toString() === b ? this.__sNumber(b) : this.__sString(b)),
					(n ? "N;" : this[this.__sc2s(v[b])] ? this[this.__sc2s(v[b])](v[b]) : this[this.__sc2s(__o)](v[b]))
				].join("");
				++a;
			};
		};
		return [a, s.join("")];
	};
	
	function __sBoolean(v) {
		return ["b:", (v ? "1" : "0"), ";"].join("");
	};
	
	function __sNumber(v) {
		var 	s = v.toString();
		return (s.indexOf(".") < 0 ? ["i:", s, ";"] : ["d:", s, ";"]).join("");
	};
	
	function __sString(v) {
		return ["s:", v.length, ":\"", v, "\";"].join("");
	};
	
	function __sStringUTF8(v) {
		return ["s:", this.stringBytes(v), ":\"", v, "\";"].join("");
	};
	
	function __sArray(v) {
		var 	s = this.__sCommonAO(v);
		return ["a:", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObject(v) {
		var 	o = this.__sc2s(v),
			n = o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObjectIE7(v) {
		var 	o = this.__sc2s(v),
			n = o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		if(n.charAt(0) === " ")
			n = n.substring(1);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObjectKonqueror(v) {
		var	o = v.constructor.toString(),
			n = this.__sNConstructor(o) ? "Object" : o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sFunction(v) {
		return "";
	};
	
	function __uCommonAO(tmp) {
		var	a, k;
		++__c;
		a = __s.indexOf(":", ++__c);
		k = parseInt(__s.substr(__c, (a - __c))) + 1;
		__c = a + 2;
		while(--k)
			tmp[this[__s.substr(__c, 1)]()] = this[__s.substr(__c, 1)]();
		return tmp;
	};

	function __uBoolean() {
		var	b = __s.substr((__c + 2), 1) === "1" ? true : false;
		__c += 4;
		return b;
	};
	
	function __uNumber() {
		var	sli = __s.indexOf(";", (__c + 1)) - 2,
			n = Number(__s.substr((__c + 2), (sli - __c)));
		__c = sli + 3;
		return n;
	};
	
	function __uStringUTF8() {
		var 	c, sls, sli, vls,
			pos = 0;
		__c += 2;
		sls = __s.substr(__c, (__s.indexOf(":", __c) - __c));
		sli = parseInt(sls);
		vls = sls = __c + sls.length + 2;
		while(sli) {
			c = __s.charCodeAt(vls);
			pos += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4));
			++vls;
			if(pos === sli)
				sli = 0;
		};
		pos = (vls - sls);
		__c = sls + pos + 2;
		return __s.substr(sls, pos);
	};
	
	function __uString() {
		var 	sls, sli;
		__c += 2;
		sls = __s.substr(__c, (__s.indexOf(":", __c) - __c));
		sli = parseInt(sls);
		sls = __c + sls.length + 2;
		__c = sls + sli + 2;
		return __s.substr(sls, sli);
	};
	
	function __uArray() {
		var	a = this.__uCommonAO([]);
		++__c;
		return a;
	};
	
	function __uObject() {
		var 	tmp = ["s", __s.substr(++__c, (__s.indexOf(":", (__c + 3)) - __c))].join(""),
			a = tmp.indexOf("\""),
			l = tmp.length - 2,
			o = tmp.substr((a + 1), (l - a));
		if(eval(["typeof(", o, ") === 'undefined'"].join("")))
			eval(["function ", o, "(){};"].join(""));
		__c += l;
		eval(["tmp = this.__uCommonAO(new ", o, "());"].join(""));
		++__c;
		return tmp;
	};
	
	function __uNull() {
		__c += 2;
		return null;
	};
	
	function __constructorCutLength() {
		function ie7bugCheck(){};
		var	o1 = new ie7bugCheck(),
			o2 = new Object(),
			c1 = __sc2s(o1),
			c2 = __sc2s(o2);
		if(c1.charAt(0) !== c2.charAt(0))
			__ie7 = true;
		return (__ie7 || c2.indexOf("(") !== 16) ? 9 : 10;
	};
	
	/** private variables */
	var 	__c = 0,
		__ie7 = false,
		__b = __sNConstructor(__c.constructor.toString()),
		__n = __b ? 9 : __constructorCutLength(),
		__s = "",
		__a = [],
		__o = {},
		__f = function(){};
	
	/** public prototypes */
	PHP_Serializer.prototype.serialize = serialize;
	PHP_Serializer.prototype.unserialize = unserialize;
	PHP_Serializer.prototype.stringBytes = UTF8 ? stringBytesUTF8 : stringBytes;
	
	/** serialize: private prototypes */
	if(__b) { // Konqueror / Safari prototypes
		PHP_Serializer.prototype.__sc2s = __sc2sKonqueror;
		PHP_Serializer.prototype.__sNConstructor = __sNConstructor;
		PHP_Serializer.prototype.__sCommonAO = __sCommonAO;
		PHP_Serializer.prototype[__sc2sKonqueror(__b)] = __sBoolean;
		PHP_Serializer.prototype.__sNumber = 
		PHP_Serializer.prototype[__sc2sKonqueror(__n)] = __sNumber;
		PHP_Serializer.prototype.__sString = PHP_Serializer.prototype[__sc2sKonqueror(__s)] = UTF8 ? __sStringUTF8 : __sString;
		PHP_Serializer.prototype[__sc2sKonqueror(__a)] = __sArray;
		PHP_Serializer.prototype[__sc2sKonqueror(__o)] = __sObjectKonqueror;
		PHP_Serializer.prototype[__sc2sKonqueror(__f)] = __sFunction;
	}
	else { // FireFox, IE, Opera prototypes
		PHP_Serializer.prototype.__sc2s = __sc2s;
		PHP_Serializer.prototype.__sCommonAO = __sCommonAO;
		PHP_Serializer.prototype[__sc2s(__b)] = __sBoolean;
		PHP_Serializer.prototype.__sNumber = 
		PHP_Serializer.prototype[__sc2s(__n)] = __sNumber;
		PHP_Serializer.prototype.__sString = PHP_Serializer.prototype[__sc2s(__s)] = UTF8 ? __sStringUTF8 : __sString;
		PHP_Serializer.prototype[__sc2s(__a)] = __sArray;
		PHP_Serializer.prototype[__sc2s(__o)] = __ie7 ? __sObjectIE7 : __sObject;
		PHP_Serializer.prototype[__sc2s(__f)] = __sFunction;
	};
	
	/** unserialize: private prototypes */
	PHP_Serializer.prototype.__uCommonAO = __uCommonAO;
	PHP_Serializer.prototype.b = __uBoolean;
	PHP_Serializer.prototype.i =
	PHP_Serializer.prototype.d = __uNumber;
	PHP_Serializer.prototype.s = UTF8 ? __uStringUTF8 : __uString;
	PHP_Serializer.prototype.a = __uArray;
	PHP_Serializer.prototype.O = __uObject;
	PHP_Serializer.prototype.N = __uNull;
};
