/* Data Connectors */
// REST-Windows Communication Foundation Service
var REST_WCF_DataConnector = Class.create();

REST_WCF_DataConnector.prototype = {
    initialize: function(proxy, serviceURL, events) {
        this.proxy = proxy;
        this.serviceURL = serviceURL;
        this.resultSet = [{}];

        // Register Events
        this['$.query.success'] = $A();
        this['$.query.failure'] = $A();
        this['$.query.exception'] = $A();
        this['$.query.complete'] = $A();

        if (!Object.isUndefined(events)) {
            if (events.onsuccess) this['$.query.success'].push(events.onsuccess);
            if (events.onfailure) this['$.query.failure'].push(events.onfailure);
            if (events.onexception) this['$.query.exception'].push(events.onexception);
            if (events.oncomplete) this['$.query.exception'].push(events.oncomplete);
        }
    },

    MergeDTO: '',

    _handleOnSuccess: function(memo, data) {
        this['$.query.success'].each(function(afunc) {
            afunc.call(null, memo, data);
        });
    },

    _handleOnFailure: function(memo, object) {
        this['$.query.failure'].each(function(afunc) {
            afunc.call();
        });
    },

    _handleOnException: function(memo, object) {
        this['$.query.exception'].each(function(afunc) {
            afunc.call();
        });
    },

    _handleOnComplete: function(memo, object) {
        this['$.query.complete'].each(function(afunc) {
            afunc.call();
        });
    },

    _getEntities: function(commandString) {
        var keyCommand = commandString;
        var keyParts = keyCommand.split('/');

        var keyEntities = $A();

        keyParts.each(function(keyPart) {
            if (keyPart.indexOf('{') == -1) {
                keyEntities.push(keyPart);
            }
        }, this);

        return keyEntities;

    },

    _getKeys: function(commandString) {
        // Returns a hash with {key} = value ...
        // the {key} is in the commandString
        // the value is in the command.parameters
        var keyCommand = this.dto.SelectSingle;
        var keyParts = keyCommand.split('/');

        var keyNames = $A();

        keyParts.each(function(keyPart) {
            if (keyPart.indexOf('{') != -1) {
                var keyPartContent = keyPart.substr(1, keyPart.length - 2);
                keyNames.push(keyPartContent);
            }
        }, this);

        var keyHash = $H();

        // Search for key values in the primaryKeys and/or collection
        keyNames.each(function(keyName) {
            if (this.dto.primaryKeys) var parameterValue = this.dto.primaryKeys[keyName];

            if (parameterValue) {
                keyHash.set(keyName, parameterValue);
            }

            // If not found as a PrimaryKey then search the parameters 
            if (keyHash.get(keyName) == null) {
                var parameterValue = this.command.parameters[keyName];

                if (parameterValue) {
                    keyHash.set(keyName, parameterValue);
                }
            }
        }, this);

        return keyHash;
    },

    _getServiceURL: function(commandString, command) {
        var template = new Template(commandString.gsub('{', '#{'));
        return this.serviceURL + template.evaluate(this.command.parameters);
    },

    AutoBackup: function(dataBag)
    {
        keyEntities = this._getEntities(this.dto.AutoBackupCommand);

        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                entity: keyEntities[0],
                method: 'AutoBackup',
                data: dataBag.toJSON()
            }
        });        
    },

    Save: function(dataBag) {
        keyEntities = this._getEntities(this.dto.UpdateCommand);

        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                entity: keyEntities[0],
                method: 'Save',
                data: dataBag.toJSON()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('Save', $H(json));
            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();

            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    DeleteWithGet: function(dataBag) {
        keyEntities = this._getEntities(this.dto.DeleteCommand);

        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters:
            {
                params: $H(this.command.parameters.QueryString).toJSON(),
                key: keyEntities[0],
                method: 'DeleteWithGet'
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();

                if (Object.isString(json)) {
                    json = json.escapeHTML().evalJSON();
                }

                var jsonHash = $H(json);
                this._handleOnSuccess('Delete', jsonHash);
            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();
            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },


    SaveAndReturnWithPost: function(dataBag) {
        keyEntities = this._getEntities(this.dto.UpdateCommand);

        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                entity: keyEntities[0],
                method: 'SaveWithPost',
                data: dataBag.toJSON()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('SaveAndReturn', $H(json));
            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();

            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    SaveWithPost: function(dataBag) {
        keyEntities = this._getEntities(this.dto.UpdateCommand);

        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                entity: keyEntities[0],
                method: 'SaveWithPost',
                data: dataBag.toJSON()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('Save', $H(json));
            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();

            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    Insert: function(dataBag) {
        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                url: this._getServiceURL(this.dto.InsertCommand, this.command),
                data: dataBag.toJSON()
            },
            onSuccess: (function() {
                this._handleOnSuccess();
            }).bind(this),

            onFailure: (function() {
                this._handleOnFailure();
            }).bind(this),

            onException: (function() {
                this._handleOnException();
            }).bind(this),

            onComplete: (function() {
                this._handleOnComplete();
            }).bind(this)

        });
    },

    Update: function(dataBag) {
        new Ajax.Request(this.proxy, {
            method: 'put',
            parameters: {
                url: this._getServiceURL(this.dto.UpdateCommand, this.command),
                data: dataBag.toJSON()
            },

            onSuccess: (function() {
                this._handleOnSuccess();
            }).bind(this),

            onFailure: (function() {
                this._handleOnFailure();
            }).bind(this),

            onException: (function() {
                this._handleOnException();
            }).bind(this),

            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)
        });
    },

    Delete: function() {
        new Ajax.Request(this.proxy, {
            method: 'delete',
            parameters: {
                url: this._getServiceURL(this.dto.DeleteCommand, this.command)
            },

            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();

                if (Object.isString(json)) {
                    json = json.escapeHTML().evalJSON();
                }

                var jsonHash = $H(json);
                this._handleOnSuccess('Delete', jsonHash);
            }).bind(this),

            onFailure: (function(transport) {
                this._handleOnFailure(transport.responseText);
            }).bind(this),

            onException: (function(transport) {
                this._handleOnException(transport.responseText);
            }).bind(this),

            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)
        });
    },

    SelectSingle: function() {
        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters: {
                method: this.command.queryVerb,
                url: this._getServiceURL(this.dto.SelectSingle, this.command),
                odd: Math.random()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();

                if (Object.isString(json)) {
                    json = json.escapeHTML().evalJSON();
                }

                var jsonHash = $H(json);
                this._handleOnSuccess('SelectSingle', jsonHash);

            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();
            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    SelectSingleWithGet: function() {
        keyEntities = this._getEntities(this.dto.SelectSingle);

        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters:
            {
                params: $H(this.command.parameters.QueryString).toJSON(),
                key: keyEntities[0],
                method: 'SelectSingleWithGet',
                odd: Math.random()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;

                // Hack: if a string is already HTML-escaped attempting to 
                // escape it again will produce illegal JSON...therefore...
                var json = resultString.escapeHTML().evalJSON();

                if (Object.isString(json)) {
                    json = json.escapeHTML().evalJSON();
                }

                var jsonHash = $H(json);
                this._handleOnSuccess('SelectSingle', jsonHash);

            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();
            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    StoredProcedure: function() {
        // TODO: how to pass parameters to WCF?
        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters: {
                url: this.serviceURL + this.dto.StoredProcedure,
                method: this.command.queryVerb,
                parameters: this.command.parameters,
                filters: this.command.filters
            },

            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess(procedureName, json);
            }).bind(this),

            onFailure: (function(transport) {
                this._handleOnFailure(procedureName, transport);
            }).bind(this),

            onException: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnException(procedureName, json);
            }).bind(this),
            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)
        });
    },

    SelectMany: function() {
        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters: {
                method: this.command.queryVerb,
                url: this._getServiceURL(this.dto.SelectMany, this.command),
                filters: this.command.filters,
                odd: Math.random()
            },

            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('SelectMany', json);
            }).bind(this),

            onFailure: (function(transport) {
                this._handleOnFailure('SelectMany', transport);
            }).bind(this),

            onException: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnException('SelectMany', json);
            }).bind(this),

            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)

        });
    },

    SelectManyWithGet: function() {
        keyEntities = this._getEntities(this.dto.SelectMany);

        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters:
            {
                params: $H(this.command.parameters.QueryString).toJSON(),
                key: keyEntities[0],
                method: 'SelectManyWithGet',
                odd: Math.random()
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();

                if (Object.isString(json)) {
                    json = json.escapeHTML().evalJSON();
                }

                this._handleOnSuccess('SingleManyWithGet', json);

            }).bind(this),
            onFailure: (function(transport) {
                this._handleOnFailure();
            }).bind(this),
            onException: (function(transport) {
                this._handleOnException();
            }).bind(this)
        });
    },

    SelectManyWithPost: function() {
        keyEntities = this._getEntities(this.dto.SelectMany);

        new Ajax.Request(this.proxy, {
            method: 'post',
            parameters: {
                entity: keyEntities[0],
                method: 'SelectManyWithPost',
                data: this.command.parameters.data.toJSON()
            },

            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('SelectMany', json);
            }).bind(this),

            onFailure: (function(transport) {
                this._handleOnFailure('SelectMany', transport);
            }).bind(this),

            onException: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnException('SelectMany', json);
            }).bind(this),

            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)

        });
    },

    SendMail: function(eMailId) {
        keyEntities = this._getEntities(this.dto.SendMail);

        new Ajax.Request(this.proxy, {
            method: 'get',
            parameters: {
                params: $H(this.command.parameters.QueryString).toJSON(),
                key: keyEntities,
                method: 'SendMail'
            },
            onSuccess: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnSuccess('SendMail', json);
            }).bind(this),

            onFailure: (function(transport) {
                this._handleOnFailure('SendMail', transport);
            }).bind(this),

            onException: (function(transport) {
                var resultString = transport.responseText;
                var json = resultString.escapeHTML().evalJSON();
                this._handleOnException('SendMail', json);
            }).bind(this),

            onComplete: (function(transport) {
                this._handleOnComplete();
            }).bind(this)

        });
    }
};
