define([
  'app',
],

function (app) {

    function callAPI(method, data, success, error) {
        $.ajax({
            url: app.foldersRoot + "/app/custom-screens/dmt/api/api.svc/" + method,
            type: 'POST',
            data: JSON.stringify(data),
            success: function (respString) {
                var resp = JSON.parse(respString);

                if ((resp) && (resp.Success == true)) {
                    if (success)
                        success(resp.Data);
                }
                else {
                    if (error) {
                        //Parse response message. Split it by '|'.
                        // - The first item will be the message.
                        // - The rest of the items, if they exist, will be parameter
                        //to be inserted into the message.
                        var msgSplit = resp.Message.split('|');

                        error(msgSplit.shift(0), msgSplit);
                    }
                }
            },
            error: function (resp) {
                console.log(resp);

                if (error)
                    error('INTERNAL_SERVER_ERROR', []);
            },
        });
    };
    function parseCommandData(obj) {
        return {
            id: obj.CommandId,
            responseText: obj.CommandResponseText,
            statusCode: obj.CommandStatusCode,
        };
    };

    var Main = {
        Models: {},
        Collections: {},

        download: function (options) {
            var that = this,
                opt = _.extend({ params: {}, }, options);

            callAPI(
                'DownloadSource',
                {
                    id: opt.params.id,
                },
                function (data) {
                    try {
                        if (opt.success)
                            opt.success(that, data);
                    }
                    catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                },
                function (errorMsg, errorMsgParams) {
                    try {
                        if (opt.error)
                            opt.error(that, errorMsg, errorMsgParams);
                    }
                    catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                }
            );
        },
        getLogs: function (options) {
            var that = this,
                qp = new Core.Database.QueryParameters(),
                opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            for (var q in opt.params) {
                qp.Add(opt.params[q].name, opt.params[q].type, opt.params[q].value);
            }

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.GetScriptLogs',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table) && (resp.Table.length > 0)) {
                                if (opt.success)
                                    opt.success(that, resp.Table[0].LogContent);
                            }
                            else {
                                var errorMsg = ((resp) && (resp.Message))
                                                            ? resp.Message
                                                            : 'SERVER_RESPONSE_NOT_VALID';
                                console.error(errorMsg);

                                if (opt.error)
                                    opt.error(that, errorMsg);
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (errorMsg) {
                        try {
                            if (opt.error)
                                opt.error(that, errorMsg);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: opt.asyc,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },

        run: function (options) {
            var that = this;
            var qp = new QueryParameters();
            var opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            for (var q in opt.params)
                qp.Add(opt.params[q].name, opt.params[q].type, opt.params[q].value);

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.RunScript',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp && resp.Table && resp.Table.length > 0) {
                                if (opt.success)
                                    opt.success(parseCommandData(resp.Table[0]));
                            }
                            else {
                                if (opt.error) {
                                    //Parse response message. Split it by '|'.
                                    // - The first item will be the message.
                                    // - The rest of the items, if they exist, will be parameter
                                    //to be inserted into the message.
                                    var msgSplit = resp.Message.split('|');

                                    var msg = msgSplit.shift(0);

                                    opt.error((msg) ? msg : 'INTERNAL_SERVER_ERROR', msgSplit);
                                }
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (data) {
                        try {
                            if (opt.error)
                                opt.error('INTERNAL_SERVER_ERROR', []);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        pause: function (options) {
            var that = this;
            var qp = new QueryParameters();
            var opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            for (var q in opt.params)
                qp.Add(opt.params[q].name, opt.params[q].type, opt.params[q].value);

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.PauseScript',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp && resp.Table && resp.Table.length > 0) {
                                if (opt.success)
                                    opt.success(parseCommandData(resp.Table[0]));
                            }
                            else {
                                if (opt.error) {
                                    //Parse response message. Split it by '|'.
                                    // - The first item will be the message.
                                    // - The rest of the items, if they exist, will be parameter
                                    //to be inserted into the message.
                                    var msgSplit = resp.Message.split('|');

                                    var msg = msgSplit.shift(0);

                                    opt.error((msg) ? msg : 'INTERNAL_SERVER_ERROR', msgSplit);
                                }
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (data) {
                        try {
                            if (opt.error)
                                opt.error('INTERNAL_SERVER_ERROR', []);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        stop: function (options) {
            var that = this;
            var qp = new QueryParameters();
            var opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            for (var q in opt.params)
                qp.Add(opt.params[q].name, opt.params[q].type, opt.params[q].value);

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.StopScript',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp && resp.Table && resp.Table.length > 0) {
                                if (opt.success)
                                    opt.success(parseCommandData(resp.Table[0]));
                            }
                            else {
                                if (opt.error) {
                                    //Parse response message. Split it by '|'.
                                    // - The first item will be the message.
                                    // - The rest of the items, if they exist, will be parameter
                                    //to be inserted into the message.
                                    var msgSplit = resp.Message.split('|');

                                    var msg = msgSplit.shift(0);

                                    opt.error((msg) ? msg : 'INTERNAL_SERVER_ERROR', msgSplit);
                                }
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (data) {
                        try {
                            if (opt.error)
                                opt.error('INTERNAL_SERVER_ERROR', []);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        clone: function (options) {
            var that = this;
            var qp = new QueryParameters();
            var opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            for (var q in opt.params) {
                qp.Add(opt.params[q].name, opt.params[q].type, opt.params[q].value);
            }

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.CloneScript',
                qp,
                {
                    onSuccess: function (data) {
                        try {
                            if (data && data.Table) {
                                var data = data.Table[0];
                                //var ids = _.pluck(data, 'Id');

                                if (opt.success != null && _.isFunction(opt.success))
                                    opt.success.call(this, that, data);
                            } else {
                                if (data.Message)
                                    opt.error.call(this, that, data.Message);
                                else
                                    opt.error.call(this, that);
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (data) {
                        try {
                            if (opt.error != null && _.isFunction(opt.error))
                                opt.error.call(this, that);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        remove: function (options) {
            var that = this;
                opt = _.extend({
                    params: {},
                    async: true,
                }, options);

            callAPI(
                'RemoveScript',
                {
                    id: opt.params.id,
                },
                function (data) {
                    try {
                        if (opt.success)
                            opt.success(that, data);
                    }
                    catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                },
                function (errorMsg, errorMsgParams) {
                    try {
                        if (opt.error)
                            opt.error(that, errorMsg, errorMsgParams);
                    }
                    catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                }
            );
        },
    };

    Main.Models.Script = Backbone.Epoxy.Model.extend({
        defaults: {
            id: null,

            activeSourceId: null,
            lastModifiedSourceId: null,
            agentId: null,
            agentName: null,
            errorStatus: null,
            errorStatusDescription: null,
            name: null,
            lastExecutionTime: null,
            lastValueTime: null,
            onlineSourceId: null,
            statusCode: null,
            trendingViewName: null,
        },
        computeds: {
            hasError: {
                deps: ['errorStatus'],
                get: function (value) {
                    return ((value != null) && (value != ''));
                },
            },
        },

        parse: function (obj) {
            return {
                id: obj.Id,

                activeSourceId: obj.ActiveSourceId,
                lastModifiedSourceId: obj.LastModifiedSourceId,
                agentId: obj.AgentId,
                agentName: obj.AgentName,
                errorStatus: obj.ErrorStatus,
                errorStatusDescription: obj.ErrorStatusDescription,
                name: obj.Name,
                lastExecutionTime: obj.LastExecutionTimeString,
                lastValueTime: obj.LastValueTime,
                onlineSourceId: obj.OnlineSourceId,
                statusCode: obj.StatusCode,
                trendingViewName: obj.TrendingViewName,
            };
        },
        setRaw: function (obj) {
            this.set(this.parse(obj));
        },

        download: function (options) {
            var sourceId = (this.get('activeSourceId')) ? this.get('activeSourceId') : this.get('lastModifiedSourceId');

            var opt = _.extend(
                {},
                options,
                {
                    params: {
                        id: sourceId,
                    },
                }
            );

            Main.download(opt);
        },
        getLogs: function (options) {
            var opt = _.extend(
                {},
                options,
                {
                    params: [
                        { name: 'Id', type: 'INT', value: this.get('id') },
                    ],
                }
            );

            Main.getLogs(opt);
        },
        run: function (options) {
            var opt = _.extend(
                {},
                options,
                {
                    params: [
                        { name: 'Id', type: 'INT', value: this.get('id') },
                    ],
                }
            );

            Main.run(opt);
        },
        pause: function (options) {
            var opt = _.extend(
                {},
                options,
                {
                    params: [
                        { name: 'Id', type: 'INT', value: this.get('id') },
                    ],
                }
            );

            Main.pause(opt);
        },
        stop: function (options) {
            var opt = _.extend(
                {},
                options,
                {
                    params: [
                        { name: 'Id', type: 'INT', value: this.get('id') },
                    ],
                }
            );

            Main.stop(opt);
        },
    });

    Main.Collections.Scripts = Backbone.Collection.extend({
        model: Main.Models.Script,

        comparator: function (a, b) {
            var attrsA = a.toJSON(),
                attrsB = b.toJSON();

            if (attrsA.isNew) return -1;
            else if (attrsB.isNew) return 1;
            else if (attrsA.name < attrsB.name) return -1;
            else if (attrsA.name > attrsB.name) return 1;
            else return 0;
        },

        currentPage: 1,
        fixedParameters: [],
        isFetching: false,
        pageSize: -1,
        transaction_timestamp: null,

        fetch: function (opt) {
            var that = this,
                qp = new Core.Database.QueryParameters(),
                ttimestamp = this.transaction_timestamp = new Date().getTime(),
                options = opt ? _.clone(opt) : {};

            this.isFetching = true;

            //qp.Add('@onlyActives', 'BIT', false);

            if (options.reset) {
                this.resetPagination(true);

                this.fixedParameters = [
                    { Name: '@showRunning', Type: 'BIT', Value: options.params.showRunning, },
                    { Name: '@showPaused', Type: 'BIT', Value: options.params.showPaused, },
                    { Name: '@showStopped', Type: 'BIT', Value: options.params.showStopped, },
                    { Name: '@showNew', Type: 'BIT', Value: options.params.showNew, },
                    { Name: '@agentId', Type: 'INT', Value: options.params.agentId, },
                    { Name: '@search', Type: 'VARCHAR', Value: options.params.search, },
                    { Name: '@onlyEnabledAgents', Type: 'BIT', Value: options.params.onlyEnabledAgents, },
                ];
            }

            _.each(this.fixedParameters, function (qpParams) {
                qp.Add(qpParams.Name, qpParams.Type, qpParams.Value);
            });

            if (options.reset) {
                qp.Add('@fromRow', 'INT', 0);
                qp.Add('@rowsToFetch', 'INT', this.pageSize);
            }
            else if (options.refresh) {
                qp.Add('@fromRow', 'INT', 0);
                qp.Add('@rowsToFetch', 'INT', this.currentPage * this.pageSize);
            }
            else {
                qp.Add('@fromRow', 'INT', (this.currentPage - 1) * this.pageSize);
                qp.Add('@rowsToFetch', 'INT', this.pageSize);
            }

            qp.Add('@timeZoneCode', 'CHAR', app.models.user.get("timezoneCode"));

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.GetScripts',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            //checking transaction timestamp
                            if (ttimestamp != that.transaction_timestamp)
                                return;

                            if ((resp) && (resp.Table)) {
                                var records = resp.Table,
                                    newColl;

                                newColl = _.map(records, that.model.prototype.parse);

                                var method = ((options.refresh) || ((options.reset))) ? 'set' : 'add';

                                //checking transaction timestamp
                                if (ttimestamp != that.transaction_timestamp)
                                    return;

                                if (!options.reset) {
                                    var editingItems = _.where(that.toJSON(), { editing: true });

                                    [].push.apply(newColl, editingItems);
                                }

                                that[method](newColl, { from: 'fetch' })
                                    .trigger('fetch', that, records);

                                that.isFetching = false;
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error('Server response not valid.');
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: options.async,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );

            return this;
        },
        getNextPage: function (options) {
            if (!this.isFetching) {
                this.currentPage++;
                options = (_.isObject(options)) ? options : {};
                this.fetch(options);
            }
        },
        removeItem: function (id, success, error) {
            var model = this.get(id);

            if (model) {
                var that = this;

                callAPI(
                    'RemoveScript',
                    {
                        id: id,
                    },
                    function (data) {
                        try {
                            if (success)
                                success(that, data);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    function (errorMsg, errorMsgParams) {
                        try {
                            if (error)
                                error(that, errorMsg, errorMsgParams);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    }
                );
            }
        },
        resetPagination: function (force) {
            if (!this.isFetching || force == true) {
                this.currentPage = 1;
            } else {
                _.delay(this.resetPagination, 100);
            }
        },
        upsertItem: function (id, props, success, error) {
            var that = this;
            var qp = new QueryParameters();

            qp.Add('@id', 'INT', id);

            for (var q in props) {
                qp.Add(props[q].name, props[q].type, props[q].value);
            }

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + '.WEB.UpsertScript',
                qp,
                {
                    onSuccess: function (data) {
                        try {
                            if (data && data.Table) {
                                var data = data.Table[0];
                                //var ids = _.pluck(data, 'Id');

                                if (success != null && _.isFunction(success))
                                    success.call(this, that, data);
                            } else {
                                if (data.Message)
                                    error.call(this, that, data.Message);
                                else
                                    error.call(this, that);
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onError: function (data) {
                        try {
                            if (error != null && _.isFunction(error))
                                error.call(this, that);
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
    });

    // Required, return the module for AMD compliance.
    return Main;

});