/**
 * This singleton class makes JSON-RPC calls via AJAX, then returns an object
 * that allows access to the response via accessor methods.
 */
var jsonRpcWrapper = ( function() {
    
    var currentId = 0;
    var url = URL_DOMAIN + "/rpc/jsonrpc.tmpl";

    var createError = function(errorMsg) {
        var errorObj = new JsonRpcResponse({
            "error" : {
                "messages" : [{
                    "text" : errorMsg,
                    "display_locations" : [],
                    "severity" : "MESSAGE",
                    "tags" : [],
                    "key" : ""
                }]
            },
            "id" : currentId
        });
        return errorObj;
    };
    var that = {};
   /**
    * 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.
    */
    var JsonRpcResponse = 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;
        };
        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) {
                            if (i === "CARTITEM") {
                                for (var j in resultObj.result[i]) {
                                    resultObj[j] = resultObj.result[i][j];
                                }                                
                            } else {
                                resultObj[i] = resultObj.result[i];                                
                            }
                        }
                    }
                });
                return rawResponse.result.data.ac_results;
            }
            return null;
        };
        jsonRpcResponseObj.getValue = function() {
            if (rawResponse &&
                    rawResponse.result &&
                    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;
    };
    that.fetch = function(args) {
        currentId++;
        var successHandler;
        if (typeof args.onSuccess === "function") {
            successHandler = function(responseObj) {
                args.onSuccess(responseObj);
            };
        } else { // create default success handler function
            successHandler = function(responseObj) {
                alert(responseObj.toJSON());
            };
        }
        var errorHandler;
        if (typeof args.onError === "function") {
            errorHandler = function(responseObj) {
                args.onError(responseObj);
            };
        } else {  // create default error handler function
            errorHandler = function(responseObj) {
                alert(Object.toJSON(responseObj));
            };
        }

        var requestOptions = {};

        requestOptions.onSuccess = function (responseObj) {
            document.fire('RPC:RESULT',responseObj);
            if (responseObj) {
                var responseArray = responseObj.responseText.evalJSON(true);
                if (Object.isArray(responseArray)) {
                    resultObj = responseArray[0];
                    if (resultObj) {
                        var jsonRpcResponse = JsonRpcResponse(resultObj);
                        if (resultObj.error) { // server returns an error
                            errorHandler(jsonRpcResponse);
                        } else if (resultObj.result) { // successful response in expected format
                            successHandler(jsonRpcResponse);
                        }
                    } else { // top-level response array is empty
                        var err = createError("Your request did not return any results.");
                        errorHandler(err);
                    }
                } else { // response is not in expected format (array)
                    var err = createError("Response is not in the expected format.");
                    errorHandler(err);
                }
            } else { // empty response
                var err = createError("Your request did not return any results.");
                errorHandler(err);
            }
        }; // end requestOptions.onSuccess
        
        requestOptions.onFailure = function(responseObj) {
            errorHandler(responseObj);
        };
        
        var postObj = {
            method: args.method,
            id: currentId
        };
        //
        // make sure parameters were passed
        var params = args.params || [];
        if (typeof params === 'string') {
            postObj.params = params.evalJSON();
        } else if (typeof params === 'object') {
            postObj.params = params;
        } else {
            errorHandler(createError("The data type of the request parameters is not supported."));
            return null;
        }
        //
        // make sure a method was passed        
        var rpcMethod;
        if ( Object.isString(args.method) && args.method.length > 0 ) {
            rpcMethod = args.method;
        } else {
            errorHandler(createError("The data type of this method is not supported."));
            return null;
        }

        var postString = (Object.toJSON(postObj));
        requestOptions.method = 'post';
        requestOptions.parameters = $H({JSONRPC:'[' + postString + ']'}).toQueryString(); 

        // add qs for apache logs
        var targetUrl = url + '?dbgmethod=' + rpcMethod;
        var req = new Ajax.Request(targetUrl, requestOptions);

        return currentId;
        
    }; // end fetch()
    
    return that;
    
})();

