
Ext.namespace( 'Builder56.Remoting' );


/**
  * Extended connection object that automatically sets up a call to the
  * server handler for executing a class method on an object on the remote server
  *
  * @author Mark Hewitt <mark@file56.com>
  * @version 0.1
  *
  * @class Builder56.Remoting.Call
  * @extends Ext.data.Connection
  * @constructor
  * @param {Object} config Configuration options
  *                             call    : class/method to call in format "class->method"
  *                             constr  : parameters to the constructor
  *                             params  : parameters to pass to the method
  *                             isStatic: true to make static method call, ignored otherwise
  *                                         [note: not implemented on server yet]
  *                             callback: function to be called with return value of server method
  *                                         function(response) where reponse is:
  *                                             1. JS obj is reponse content-type is "text/json"
  *                                             2. raw response string otherwise
  *
  */
Builder56.Remoting.Call = function(config)
{
    var callDescriptor = "";
    if ( typeof config.isStatic == 'undefined' || config.isStatic === false )
    {
        var c = config.call.split('::');
        if ( c.length > 1 ) 
        {
            callDescriptor = c[0] + '->' + c[1];
        }
        else
        {
            callDescriptor = c[0];
        }    
    }
                
    config.url = typeof config.url === 'undefined' ? "server.php?c=" + callDescriptor : config.url;
    config.extraParams = ( typeof config.params === 'object' ? config.params : {} );
    
    // if the caller wants us to pass a set of parameters to the objects constructor we must
    // include these in the extraParams
    if ( typeof config.constr !== 'undefined' )
    {
        config.extraParams.constr = config.constr;
    }

    // we need to encode objects into a special JSON format that can be recognised by the
    // server as encoded JSON that needs to be converted into a structure server-side, as 
    // opposed to a straight string
    
    if ( typeof config.extraParams === 'object' )
    {
        for ( var n in config.extraParams )
        {
            if ( typeof config.extraParams[n] === 'object' )
            {
                config.extraParams[n] = Builder56.encode(config.extraParams[n]);
            }
        }
    }
    
    // create a unique tracking number for this call so that we can ask the server to
    // reissue its response should the reply timeout
    config.extraParams.__tracking = Ext.id();
        
    this.successCallback = config.callback;
    
    Builder56.Remoting.Call.superclass.constructor.call(this, config ); 
    
    this.request( {success: this.processCallback.createDelegate(this),failure: this.processFailure.createDelegate(this)} );
};

Ext.extend( Builder56.Remoting.Call, Ext.data.Connection, {
    
    timeoutRetries: 3
    
    ,retryOnTimeout: true
    
    ,errorMsg : false    
    
    /**
     * we process the reponse to handle any remoting specific attachments that the server side system
     * added to the payload, then we pass control on to the user defined callback function [if set]
     */
    ,processCallback: function( xmlHttpResponse, options )
    {
        // if there was a previous error/warning displayed we mus hide it now the call succeeded
        if ( typeof this.errorMsg === 'object' )
        {
            this.errorMsg.hide();
            delete this.errorMsg;
            this.errorMsg = false;
        }
        
        // if the server responded with a JSON block, then we must examine it, process any remoting 
        // attachments and pass the object on to the user-defined callback, if the reply is NOT in a
        // JSON format we ignore remoting processing and pass the raw string to the callback
        
        // @note we trim whitespace off the string, IE6 has a trailing newline on the content-type
        
        var response = "";
        if ( xmlHttpResponse.getResponseHeader["Content-Type"].trim() == "text/json"  )
        {       
            response = Ext.util.JSON.decode(xmlHttpResponse.responseText);
            
            if ( typeof response === 'object' && typeof response.multipart === 'object' )
            {
                // the original response will be in the multiple.response field
                // additional data packets are in the data array
                
                for ( var i = 0; i < response.multipart.data.length; i++ )
                {
                    alert( response.multipart.data[i].msg );
                }
                
                // save the call response so it can be processed as normal
                response = response.multipart.response;                
            }
            
        }    
        else
        {
            response = xmlHttpResponse.responseText;
        }
        
        // the success callback can be a function, or an array of functions that
        // must be called after the call completes
        if ( this.successCallback instanceof Array )
        {
            for ( var i = 0; i < this.successCallback.length; i++ )
            {
                if ( typeof this.successCallback[i] === 'function' ) { this.successCallback[i](response); } 
            }
        }
        else if ( typeof this.successCallback === 'function' ) 
        { 
            this.successCallback(response); 
        }
    }
    
    ,processFailure: function( xmlHttpResponse, options )
    {
        switch ( xmlHttpResponse.status )
        {
            // no connection or server offline
            case 0:
            {
                new Builder56.Window.Message({title:"Communications Error"
                                                             ,textTitle:"Connection Failed"
                                                             ,text:"There is no connectivity to the server and this call cannot be completed."
                                                             ,icon: Builder56.Icon32('Antenna_Warning')
                                                             ,closable:false
                                                             ,buttons:[Builder56.Window.Message.OK]
                                                            }).show();
                break;
            }
            
            // timeout
            case -1:
            {
                this.timeoutRetries--;
                if ( this.retryOnTimeout && this.timeoutRetries > 0 )
                {
                    if ( typeof this.errorMsg !== 'object' )
                    {
                        this.errorMsg = new Builder56.Window.Message({title:"Communications Error"
                                                                     ,textTitle:"Connection Timeout"
                                                                     ,text:"A system call has timed out trying to contact the server.<br>The action is being executed again."
                                                                     ,icon: Builder56.Icon32('Clock-Alarm-Warning')
                                                                     ,closable:false
                                                                     ,buttons:[]
                                                                    });
                        this.errorMsg.show();
                    }                                                                
                    this.request( {success: this.processCallback.createDelegate(this),failure: this.processFailure.createDelegate(this)} );
                }                
                break;
            }
            
            // internal server error - exceptions caught by remoting system are returned as status 500
            case 500:
            {
                //decode the error message
                debugger;
                var ex = Ext.util.JSON.decode(xmlHttpResponse.responseText);
                this.errorMsg = new Builder56.Window.Message({title:"System Error"
                                                             ,textTitle:"Execution Exception"
                                                             ,text: ( typeof ex == 'object' ? ex.message : "An unknown server error has occured." )
                                                             ,icon: Builder56.Icon32('Web_Server_Error')
                                                             ,closable:false
                                                             ,buttons:[Builder56.Window.Message.OK]
                                                            }).show();                
                break;
            }
        }       
        
    }
    
});


Builder56.Remoting.Download = function( config )
{
	var params = "";
	var call = "";

	if ( typeof config === 'object' )
	{	
		if ( typeof config.params === "object" )
		{
  			for ( var n in config.params ) 
			{
			     params += "&" + n + "=" + ( typeof config.params[n] === 'object' ? Builder56.encode(config.params[n]) : config.params[n] ); 
			}
		}

		call = config.call;
	}
	else
	{
		call = config;
	}

	window.location.href = "server.php?c=" + call + params;
}

