 
generic.jsonRPC = Class.create({
      id: 0, 
      url: generic.env.domain + "/rpc/jsonrpc.tmpl",
      errorCodes: {
		101: "The data type of this method is not supported.",
		102: "The data type of the request parameters is not supported.",
		103: "Your request did not return any results.",
		104: "Response is not in the expected format."  
	},
      initialize: function () { 
	 
      },

      /** args is a hash, required key: args.method 
      optional keys: args.params, args.onBoth func, args.onSuccess func and args.onFailure func **/
      fetch: function(/* Object*/args) {  
	var self = this;
	this.id++;  
	 
	var options = {method:'post'};
	
	if (args.onBoth) { 
	     options.onSuccess = args.onBoth;
	     options.onFailure = args.onBoth; 
	} else {
	     options.onSuccess = args.onSuccess || function (response) {
		console.log('JSON-RPC success');
            	console.log(Object.toJSON(response.getValue()));
	     };
	     options.onFailure = args.onFailure || function (response) {
		console.log('JSON-RPC failure');
            	console.log(Object.toJSON(response.getMessages()));
	     }; 
	}

	options.onSuccess = options.onSuccess.wrap( 
  	       function(proceed, response) {   
			if (!response||!response.responseText) { // empty response 
               	errorHandler(this.createErrorResponse(103));
				return;
            }		 
            // Analytics general event for RPC..  
            generic.events.fire({event:'RPC:RESULT',msg:response}); 
            
            var responseArray = response.responseText.evalJSON(true);
           
            if (Object.isArray(responseArray)) { 
                    		     var resultObj = responseArray[0]; 
                    		     
                    		     if (resultObj) {
                        	          var jsonRpcResponse = self.response(resultObj);
                       		             if (resultObj.error) { // server returns an error
                                              errorHandler(jsonRpcResponse);
                                         } else if (resultObj.result) { // successful response in expected format
                                             //console.log("generic.jsonrpc.onSuccess");  
                                             proceed(jsonRpcResponse);
                                         }
                                    } else { // top-level response array is empty 
                                          errorHandler(self.createErrorResponse(103));
                              	     }
            		} else { // response is not in expected format (array) 
                                   errorHandler(self.createErrorResponse(104));
      			}
  	}); 
	options.onFailure = options.onFailure.wrap( 
  		function(proceed, response) {   
    		    var resp = response;  
    		    
    		    //server returned failure, i.e. onFailure was not triggered by this class
    		    if (typeof response.responseText != "undefined") { 
    		       //console.log("generic.jsonRPC onFailure: server error");
    		       try { //server returns an error in json
    		    	var responseArray = response.responseText.evalJSON(true);
    		    	var resultObj = responseArray[0];
    		    	resp = self.response(resultObj); 
    		       } catch(e) { //server response is not json
    		    	//console.log("generic.jsonRPC onFailure: server error, result is not json");
    		    	resp = self.createErrorResponse(response.status,response.responseText); 
    		       }  
    		    }
    		     
    		    proceed(resp);
  	});  
  	 	
	var errorHandler = options.onFailure;

        	var method = args.method;
	var params = args.params || [];
	 	
	var postObj = {
	 		method: method,
	 		id: self.id 
	 	};
		
        	// make sure a method was passed          
        	if ( !Object.isString(method) || method.length <= 0 ) { 
               errorHandler(self.createErrorResponse(101)); 
               return null;
        	} 
		
        	//make sure that the params type is an obj
        	if (typeof params === 'string') {
            	postObj.params = params.evalJSON();
        	} else if (typeof params === 'object') {
            	postObj.params = params;
        	} else {
            	errorHandler(self.createErrorResponse(102));
            	return null;
        	}
        		  
	var postString = "[" + Object.toJSON(postObj) + "]";  
	
        	options.parameters = $H({JSONRPC:[postString]}).toQueryString(); 
        	var url = this.url + '?dbgmethod=' + method;  
        	new Ajax.Request( url, options );
		 
        	return this.id;	
     },
     createErrorResponse: function(errorCode, errorMsg) { 
               errorMsg = errorMsg || this.errorCodes[errorCode];  
               var errorObj = new this.response({
                    "error" : {
                          "code": errorCode,
                          "data": {
                          	"messages" : [{ 
	                	"text" : errorMsg,
                               "display_locations" : [],
                               "severity" : "MESSAGE",
                                "tags" : [],
                                "key" : ""
                            }]
                          }
                    },
                    "id" : this.id
                }); 
                return errorObj;
          },
      
     /**
    * A JsonRpcResponse object is instantiated and returned to the onSuccess and onError
    * callback functions that are passed to the fetch() method. It exposes the contents
    * of the response through its getData, getError, and getMessages methods.
    */
      response: function (resultObj) {
        var jsonRpcResponseObj = {};
        var rawResponse = resultObj;
        jsonRpcResponseObj.getId = function() {
               if (rawResponse) {
                  return rawResponse.id;
               }
               return null;
            },
        jsonRpcResponseObj.getData = function() {
            if (rawResponse &&
                    rawResponse.result &&
                    rawResponse.result.data) {
                return rawResponse.result.data;
            }
            return null;
        };
        jsonRpcResponseObj.getError = function() {
            if (rawResponse &&
                    rawResponse.error) {
                return rawResponse.error;
            }
            return null;
        };
        /** MK: still needed? 
        jsonRpcResponseObj.getCartResults = function() {
            if (rawResponse &&
                    rawResponse.result &&
                    rawResponse.result.data &&
                    rawResponse.result.data.ac_results &&
                    Object.isArray(rawResponse.result.data.ac_results) ) {
                rawResponse.result.data.ac_results.each(function (resultObj) {
                    if (resultObj.result) {
                        for (var i in resultObj.result) {
                            resultObj[i] = resultObj.result[i];
                        }
                    }
                });
                return rawResponse.result.data.ac_results;
            }
            return null;
        };
        **/
        jsonRpcResponseObj.getValue = function() {
            if (rawResponse &&
                    rawResponse.result &&
                    typeof rawResponse.result.value != "undefined") {
                return rawResponse.result.value;
            }
            return null;
        };
        /**
         * This method returns the contents of the response's error property.
         * It first checks the result property, then checks the error property.
         */        
        jsonRpcResponseObj.getMessages = function() { 
            if (rawResponse) {
                if (rawResponse.result &&
                        rawResponse.result.data &&
                        rawResponse.result.data.messages) {
                    return rawResponse.result.data.messages;
                } else if (rawResponse.error &&
                        rawResponse.error.data &&
                        rawResponse.error.data.messages) {
                    return rawResponse.error.data.messages;
                }
            }
            return null;
        };
        return jsonRpcResponseObj;
    }
}); 
generic.jsonrpc = new generic.jsonRPC();
