var JSON = {

	server : 'json.php',
	
	errorHandler : function (error) {
	    //$('debug_error').innerHTML = error + 
	        //'<button onclick="this.parentNode.style.display = \'none\'">Close</button>';
	    //$('debug_error').style.display = 'block';
		alert (error);
	},
	
    instance : function (server) {
        if (server) this.server = server;
    },
    
    encode : function (data) {
    	var encoder = new JSON.encoder (data, 25);
    	return encoder.encode (data);
    },
        
	callPhpFunction : function (func, params, callback) {
		var json = new JSON.request (this.server, callback, func, params);
    	json.doRequest();
	},
    
    callClass : function (className, method, params, callback) {
    	var json = new JSON.request (JSON.server, callback, [className, method], params);
    	json.doRequest();
    }
    
}
		
JSON.request = new Class ({		
	
	__construct : function (server, callback, func, params) {
		this.server = server;		
		this.callback = callback;
		this.func = func;
		this.params = params;
	},
		
	doRequest : function() {
		var query = JSON.encode ({ 'method' : this.func, 'params' : this.params, 'id' : 1 });

		var thisref = this;
		Ajax.request (this.server, query, function (data) {
			var callOk, callErr;

			if (thisref.callback instanceof Array) {
				callOk = thisref.callback[0];
				callErr = thisref.callback[1];
			} else {
				callOk = thisref.callback;
				callErr = JSON.errorHandler;
			}
			
			try {
			    data = eval ("(" + data + ")");
			} catch (e) {
			    callErr ("Invalid response: " + data);
			    return;
			}
			if (data.error == null) {
				callOk (data.result);
			} else {
				callErr (data.error);
			}
		});
	},
	
	call : function (callback, func) {
		var extra = '';
		for (var i = 2; i < arguments.length; i++) extra += ", arguments[" + i + "]";
		return eval ("this.callServer_old (this.server, callback, func" + extra + ");");
	}
			
});

JSON.encoder = new Class ({
	
	__construct : function (source, maxDepth) {
		this.source = source;
		this.maxDepth = maxDepth || 25;
		this.depth = 0;
		this.pieces = [];
		this.piecesLength = 0;
	},
	
	escapeSymbols : {
		'\b' : '\\b',
		'\f' : '\\f',
		'\n' : '\\n',
		'\r' : '\\r',
		'\t' : '\\t'
	},
		
	addPiece : function (piece) {
		this.pieces[this.piecesLength++] = piece;
	},
				
	parseSource : function (cVar) {
		this.depth++;
		if (this.depth > this.maxDepth) return this.addPiece ('null');
		
		switch (typeof cVar) {
	        case 'boolean': return this.addPiece (String (cVar));
	        case 'number': return this.addPiece (isFinite (cVar) ? +cVar : 'null');
	        case 'string':
	        	var len = cVar.length;
	        	this.addPiece ('"');
	        	for (var i = 0; i < len; i++) {
	        		var ch = cVar.charAt (i);
	        		if (ch < ' ') {
	        			var escSymbol = this.escapeSymbols [ch];
	        			if (escSymbol) {
	        				this.addPiece (escSymbol);
	        			} else {
	        				ch = ch.charCodeAt();
	                        this.addPiece (
	                        	'\\u00' + 
	                        	Math.floor(ch / 16).toString(16) +
	                            (ch % 16).toString(16)
	                        );
	        			}
	        		} else {
	                    if (ch == '\\' || ch == '"') this.addPiece ("\\");
	                    this.addPiece (ch);
	        		}
	        	}
	        	return this.addPiece ('"');
	        case 'object':
	        	if (!cVar) return this.addPiece ('null');
	        	if (cVar instanceof Array) {
	        		var len = cVar.length;
	        		this.addPiece ('[');
	        		for (var i = 0; i < len; i++) {
	        			if (i) this.addPiece (',');
	        			this.parseSource (cVar[i]);
	        			this.depth--;
	        		}
	        		return this.addPiece (']');
	        	}
	        	if (typeof cVar.toString == 'undefined') return this.addPiece ('null');
	        	this.addPiece ('{');
				var isFirst = true;
				for (var i in cVar) {
					var obj = cVar[i];
					var oType = typeof obj;
					if (/*cVar.hasOwnProperty (obj) &&*/ oType != 'undefined' && oType != 'function') {
						if (isFirst) isFirst = false; else this.addPiece (',');
						this.parseSource (i);
	        			this.depth--;
						this.addPiece (':');
						this.parseSource (obj);
	        			this.depth--;
					}
				}
	        	return this.addPiece ('}');
	        	
		}
		return this.addPiece ('null');
	},
	
	encode : function() {		
		this.parseSource (this.source);
		return this.pieces.join ('');
	}

});