var JSON_RPC = function() {

  var _lastErrorHTML = null;

  function displayLastError(){

      // Assuming that an error occurred because an HTML error docuemnt was returned
      var errorWindow = window.open( "about:blank", "error_window" );
      errorWindow.document.write( _lastErrorHTML );
			return; 
  };


  var JSON_RPC_URL = "/bn/jsonAPI.jsp";

  function send( jsonrpcCallback, methodName ){
    // params to methodName are passed after the methodName

    // turn the params into an array
    var params = [];
    if( arguments.length > 2 ){
      for( var i=2; i < arguments.length; i++ ){
        params[ params.length ] = arguments[i];
      }
    }

    // make the json-rpc request object
    var jsonRequest = {};
    jsonRequest.method = methodName;
    jsonRequest.params = params;
		// jsonRequest.id = $$$$$ generate a request ID

    // make a form to hold the json-rpc request
    var form = document.createElement( "FORM" );
    var input = document.createElement( "INPUT" );
    input.type = "text";
    input.name = "json-rpc";
		input.value = JSONMarshaller.toJSONString( jsonRequest );
    form.appendChild( input );

		var internalCallback = { success: _jsonrpcInternalCallback,
										 failure: _jsonrpcInternalCallback,
                     argument: jsonrpcCallback
		};


		YUC.setForm( form );
		YUC.asyncRequest( "POST", JSON_RPC_URL, internalCallback );
  };

	function _jsonrpcInternalCallback( o ){
    
    try {

      var responseValue = eval( "(" + o.responseText + ")" );   // $$$$$ potentially unsafe if we dont control the content
      var jsonrpcCallback = o.argument;

    } catch( e ){
      var errorMsg = e.message;

      // $$$$$ makes this library know too much about the application
      _lastErrorHTML = o.responseText;
      gNewImageProcess.showErrorScreen( "<div>The response from the server could not be parsed.</div><div style='width:100%; text-align:center; color:blue; text-decoration:underline;' onclick='JSON_RPC.displayLastError()'>See Error Response</div>.");
      return;

//       // Assuming that an error occurred because an HTML error docuemnt was returned
//       var errorWindow = window.open( "about:blank", "error_window" );
//       errorWindow.document.write( o.responseText );
// 			return; 
    }

		if( responseValue.error === null ){
			jsonrpcCallback.success( responseValue.response );
		} else {
			jsonrpcCallback.failure( responseValue );
		}
	};

  return { send: send,
                   displayLastError: displayLastError
                   };

}();


var JSONMarshaller = function() {

  function toJSONString( obj )
  {
    if( obj === null ) {
      return "null";
    }

    switch( obj.constructor ) {
      case Object:
        return _marshStruct( obj );
      case Array:			
		    return _marshArray( obj );
      case String:
        // $$$$$ definitely need to escape some string characters
        return "\"" + _escapeString(obj) + "\"";

      case Number:
      case Boolean:
        return "" + obj;
      default:
        throw { message:"Error: Object type not recognized by the JSON Marshaller (typeof is: \"" + typeof(obj) + "\")." };
    }
  };



  function _escapeString( str ){
    return str.replace( /\\/g, "\\\\" ).replace( /\"/g, "\\\"" );
  };


  function _marshStruct( struct )	
  {
    var valueStr = "{";
    for(var key in struct) {
			// guard against unexpected Object.prototype extensions with this test
			if( struct.hasOwnProperty( key ) ) {  
				valueStr += "\"" + key + "\":" + toJSONString( struct[ key ] ) + ",";
			}
		}
    
    // drop the last comma
    var finalValue = valueStr.substring( 0, valueStr.length - 1 ) + "}";
    return finalValue;
  };
  
  function _marshArray( arr )	
  {
    var valueStr = "[";
    var length = arr.length;
    for(var i=0; i < length; i++) {			
      valueStr += toJSONString( arr[i] ) + ",";
    }

    var finalValue = valueStr.substring(0, valueStr.length - 1) + "]";
    return finalValue;
  };

	return {
		toJSONString : toJSONString
      };
}();




