//SCREEN-BOILERPLATE

//this boilerplate builds screens that are gonna be shown in the <div class="content"> tag of our main HTML.
//do not build app components with this boilerplate, only screens (reports)

define([
  // Application variable, always include it to have access to app methods.
  "app",

  //templates-loader: this loads templates async.
  "js/templates-loader",
  "modules/modal", 
  "backgrid",
  "moment",
  "modules/dmt-script",

  'backgrid/moment-cell',
  'backgrid/select-integer-cell',
  'js/FileSaver',
],

function (app, T, Modal, Backgrid, moment, Script) {
    //replace all "Screen" with your view's name.
    var Screen = { Models: {}, Views: {}, Collections: {} };

    Screen.Models.Main = Backbone.Epoxy.Model.extend({
        defaults: {
            agentId: 0,
            agents: [],
            search: '',

            isLoading: true,
            hasData: false,
        },
        computeds: {
            hasAgents: {
                deps: ['agents'],
                get: function (agents) {
                    return agents.length != 0;
                },
            },
        },

        fetchAgents: function () {
            var that = this,
                qp = new Core.Database.QueryParameters();

            qp.Add('@onlyEnabled', 'BIT', 1);

            Core.Json.CallProcedure(
                app.DatabaseNames.IH + ".WEB.GetAgentsDDP",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                var records = resp.Table;

                                var dmtAgents = _.filter(records, function (obj) {
                                    return obj.Name.substring(0, 3) == "DMT";
                                });

                                var newItems = _.map(dmtAgents, function (obj) { return { value: obj.Id, label: obj.Name, }; });

                                that.set("agents", newItems);
                            }
                            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); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: false,
                },
                app.ConnectionStrings.app
            );

            return this;
        },
    });

    //the generate id method is called everytime a view is going to be shown by the router and returns and id that
    //is used by the router to store in cache (if it is cacheable) and to know the current shown view.
    //this is useful in case your view is reusable, and displays different data depending on url parameters 
    //(such as a catalog view, or a report that doesnt change in terms of UI but it does change in terms of data)
    //so you can always use the same view on the router but the cache can tell which view is which by using differents ids.
    Screen.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return "dmt/scripts-status" + (viewParams && viewParams.id) ? "-" + viewParams.id.toString() : "";
        } catch (Error) { }
    };

    Screen.Views.Main = Backbone.Epoxy.View.extend({
        template: "scripts-status",
        id: "dmt-scripts-status",
        title: "DMT Scripts Status",
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        isCacheable: false,
        events: function () {
            return {
            };
        },

        autoRefresh: null,
        bindingSources: null,
        grids: null,
        items: null,
        subviews: null,

        currentModal: null,
        listeners: null,

        initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            var that = this;

            this.autoRefresh = {
                enabled: null
                , toid: null
                , every: 5 * 1000
            };

            this.model = new Screen.Models.Main();
            this.model.fetchAgents();

            this.subviews = {
                subnavbarControls: new Screen.Views.SubnavBarControls({
                    model: this.model,
                    parent: this,
                    container: app.views.subnavbar.getSectionContainer(1, 12),
                    events: function () {
                        return {
                            'click .add-item': _.bind(that.addNewBtn_click, that),
                        };
                    },
                }),
            };

            this.subviews.subnavbarControls.model.set('agents', this.model.get('agents'));

            this.items = new Script.Collections.Scripts();

            this.grids = {};

            this.bindingSources = {};

            this.listeners = {};

            this.bindEvents();
        },

        bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
            this.listenTo(this.subviews.subnavbarControls.model, "change:showRunning change:showPaused change:showStopped change:showNew change:agentId", this.search_filters_changed);
            this.listenTo(this.subviews.subnavbarControls.model, "change:search", _.debounce(this._search_changed, 800));
            this.listenTo(this.items, 'fetch', this.collection_fetch);
        },        
        _refresh: function (opt) {
            //console.log('autorefresh: ' + new Date().toString()); 
            if (this.autoRefresh.toid != null) {
                clearTimeout(this.autoRefresh.toid);
                this.autoRefresh.toid = null;
            }

            var attrs = this.subviews.subnavbarControls.model.toJSON();

            //var searchFilter = this.subviews.subnavbarControls.model.get("search");

            this.refreshItemsColl(_.extend(
                {},
                opt,
                {
                    params: {
                        agentId: attrs.agentId,
                        showRunning: attrs.showRunning,
                        showPaused: attrs.showPaused,
                        showStopped: attrs.showStopped,
                        showNew: attrs.showNew,
                        search: attrs.search,
                        onlyEnabledAgents: 1,
                    }
                })
            );

            if (this.autoRefresh.enabled == true) {
                var that = this;

                this.autoRefresh.toid = setTimeout(
                    function () { that._refresh(); },
                    this.autoRefresh.every
                );
            }
        },
        refresh: function (viewParams) {
            var fixedParams = _.extend({}, Screen.Models.Main.prototype.defaults, viewParams);

            //If currentModal exists, hide it and erase it.
            if (this.currentModal) {
                this.currentModal.hide();
                this.currentModal = null;
            }

            //check if agentId param (sectionParam1) is defined
            if (viewParams.sectionParam1) {
                this.model.set('agentId', (fixedParams.sectionParam1 != '') ? parseInt(fixedParams.sectionParam1, 10) : 0);
                this.subviews.subnavbarControls.model.set('agentId', (fixedParams.sectionParam1 != '') ? parseInt(fixedParams.sectionParam1, 10) : 0);
            }

            //Call first refresh.
            var params = this.model.toJSON();

            this._refresh(_.extend(
                {},
                params,
                {
                    reset: true,
                    params: _.extend(
                        {},
                        params,
                        {
                            agentId: params.agentId,
                        }
                    ),
                }
            ));
        },
        refreshItemsColl: function (options) {
            try {
                var that = this,
                    modelAttrs = this.model.toJSON(),
                    opt = _.extend({}, { params: {}, refresh: true, }, options);

                //var agentId = ()
                //                ? opt.params.agentId
                //                : (modelAttrs.agentId)
                //                    ? modelAttrs.agentId
                //                    : null;

                if (opt.reset == true) {
                    this.model.set({
                        isLoading: true,
                    });
                }

                //Parameter details:
                // > Parameter 'reset' is used to reload only the first page of records and
                // show the 'Loading' poster.
                // > Parameter 'refresh' is uset to reload all the currently loaded records
                // without showing the 'Loading' poster.
                this.items.fetch({
                    params: {
                        agentId: opt.params.agentId,
                        showRunning: opt.params.showRunning,
                        showPaused: opt.params.showPaused,
                        showStopped: opt.params.showStopped,
                        showNew: opt.params.showNew,
                        search: opt.params.search,
                        onlyEnabledAgents: 1,
                    },
                    refresh: opt.refresh,
                    reset: opt.reset,
                });
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        render: function (container, viewParams) {
            var that = this;

            this.viewParams = viewParams;

            var thatContainer = (this.options.container) ? this.options.container : container;
            this.options.container = thatContainer;

            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = '/app/custom-screens/dmt/' + this.template + '/';

            T.render.call(
                this,
                this.template,
                function (tmp) {
                    if (!that.options.i18n) that.options.i18n = {};

                    app.getI18NJed(
                        that,
                        that.template,
                        function (i18nJED) {
                            //storing internationalization data
                            that.options.i18n[that.template] = i18nJED;
                            //start: before the view is visible, but the template was already loaded (not instanced nor appended)

                            //end:

                            //loading the view and appeding it to the views's $el.
                            that.$el.html(tmp());
                            that.applyBindings();

                            that.bindViewScopedEvents();

                            that.subviews.subnavbarControls.render();


                            //start: the view was already loaded an is on a div element, but not appended to the main container
                            //here you can perform anything you want DOM related, by getting the dom element via that.$el.find("#id")
                            //or this.$("#id")

                            var customRow = Backgrid.Row.extend({
                                initialize: function () {
                                    Backgrid.Row.prototype.initialize.apply(this, arguments);

                                    this.bindEvents();
                                },
                                render: function () {
                                    Backgrid.Row.prototype.render.apply(this, arguments);

                                    if (this.model.get('isLoading')) {
                                        this.$el.addClass('locked-row');
                                    } else {
                                        this.$el.removeClass('locked-row');
                                    }

                                    return this;
                                },
                                bindEvents: function () {
                                    this.listenTo(this.model, 'change:isLoading', this.model_change_isLoading);
                                },
                                model_change_isLoading: function () {
                                    try{
                                        this.render();
                                    } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                },
                            });

                            var grid = that.grids.items = new Backgrid.Grid({
                                className: 'backgrid table table-hover',
                                row: customRow,
                                columns: [
                                    {
                                        name: 'name',
                                        label: app.translate([that, app], 'name_col_label'),
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.StringCell.extend({
                                            orderSeparator: '',
                                            className: 'string-cell align-center-cell name',
                                            //Override enterEditMode to prevent the edition of
                                            //scripts already saved in the database
                                            enterEditMode: function () {
                                                var model = this.model;
                                                var column = this.column;

                                                var editable = (this.model.get('statusCode') == 'NEWROW' || this.model.get('statusCode') == null);
                                                if (editable) {

                                                    this.currentEditor = new this.editor({
                                                        column: this.column,
                                                        model: this.model,
                                                        formatter: this.formatter
                                                    });

                                                    model.trigger("backgrid:edit", model, column, this, this.currentEditor);

                                                    // Need to redundantly undelegate events for Firefox
                                                    this.undelegateEvents();
                                                    this.$el.empty();
                                                    this.$el.append(this.currentEditor.$el);
                                                    this.currentEditor.render();
                                                    this.$el.addClass("editor");

                                                    model.trigger("backgrid:editing", model, column, this, this.currentEditor);
                                                }
                                            },
                                        }),
                                    },
                                    {
                                        name: 'agentId',
                                        label: app.translate([that, app], 'agent_col_label'),
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.Extension.SelectIntegerCell.extend({
                                            optionValues: _.map(that.model.get('agents'), function (obj) { return [obj.label, obj.value, ]; }),
                                            className: 'select-cell align-center-cell agentId',
                                            //Override enterEditMode to prevent the edition of
                                            //scripts already saved in the database
                                            enterEditMode: function () {
                                                var model = this.model;
                                                var column = this.column;

                                                var editable = (this.model.get('statusCode') == 'NEWROW' || this.model.get('statusCode') == null);
                                                if (editable) {

                                                    this.currentEditor = new this.editor({
                                                        column: this.column,
                                                        model: this.model,
                                                        formatter: this.formatter
                                                    });

                                                    model.trigger("backgrid:edit", model, column, this, this.currentEditor);

                                                    // Need to redundantly undelegate events for Firefox
                                                    this.undelegateEvents();
                                                    this.$el.empty();
                                                    this.$el.append(this.currentEditor.$el);
                                                    this.currentEditor.render();
                                                    this.$el.addClass("editor");

                                                    model.trigger("backgrid:editing", model, column, this, this.currentEditor);
                                                }
                                            },
                                        }),
                                    },
                                    {
                                        name: 'lastValueTime',
                                        label: app.translate([that, app], 'last_value_time_col_label'),
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.NumberCell.extend({
                                            decimals: 3,
                                            className: 'numeric-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'lastExecutionTime',
                                        label: app.translate([that, app], 'last_execution_time_col_label'),
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.Extension.MomentCell.extend({
                                            className: 'momment-cell align-center-cell lastExecutionTime',
                                            modelFormat: 'YYYY-MM-DD HH:mm:ss',
                                            displayFormat: 'YYYY-MM-DD HH:mm:ss',
                                        }),
                                    },
                                    {
                                        name: 'statusCode',
                                        label: app.translate([that, app], 'status_code_col_label'),
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: "string-cell align-center-cell status-cell statusCode",
                                            initialize: function () {
                                                Backgrid.StringCell.prototype.initialize.apply(this, arguments);

                                                this.bindEvents();
                                            }, 
                                            render: function () {
                                                var template = null;
                                                var popover_message = null;

                                                var statusCodeClass = 'dmt-script-' + (this.model.get('statusCode')).toLowerCase();
                                                var statusCode = this.model.get('statusCode');
                                                var popover_message_key = statusCode.toLowerCase();

                                                this.template = Handlebars.compile(that.$el.find('#status_cell_template').html());

                                                this.$el.html(this.template(this.model.toJSON({ computed: true, })));

                                                //this.$el.addClass(statusCodeClass);
                                                this.$el.find('.fa-circle').addClass(statusCodeClass);

                                                if (popover_message_key) popover_message = that.options.i18n[that.template].translate("popover_row_status_icon_" + popover_message_key).fetch();
                                                if (popover_message != null) {
                                                    this.$el.find(".popover-on-icon").popover({
                                                        trigger: "hover",
                                                        html: true,
                                                        content: popover_message,
                                                        placement: "top",
                                                    });
                                                }

                                                this.$el.find(".status-error").popover({
                                                    trigger: "hover",
                                                    html: true,
                                                    //content: this.model.get('errorStatus'),
                                                    placement: "top",
                                                });

                                                return this;
                                            },
                                            bindEvents: function () {
                                                this.listenTo(this.model, 'change:hasError', this.model_change_hasError);
                                            },

                                            model_change_hasError: function (model, value, opt) {
                                                try {
                                                    this.render();
                                                }
                                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                        })
                                    },
                                    {
                                        name: "configure",
                                        label: "",
                                        sortable: false,
                                        editable: false,
                                        //renderable: (_.isBoolean(ctx.editable)) ? ctx.editable : false,
                                        headerCell: Backgrid.HeaderCell.extend({
                                            className: "configuretd",
                                        }),
                                        cell: Backgrid.Cell.extend({
                                            template: Handlebars.compile(that.$el.find('#actions_cell_template').html()),
                                            className: 'actions-cell',
                                            events: {
                                                'click .btn-cell-action': 'cellActionClick',

                                                "click .btn-dropdown-config-option": "configure_dropdown_config_opt_click",
                                                "click .btn-dropdown-action-option": "configure_dropdown_action_opt_click",

                                                "show.bs.dropdown .btn-group": "btnGroup_show",
                                                "hide.bs.dropdown .btn-group": "btnGroup_hide",
                                            },

                                            initialize: function () {
                                                Backgrid.Cell.prototype.initialize.apply(this, arguments);

                                                ////creating new locked attr on column
                                                //this.model.set("locked", false);

                                                //this.locksChanged();

                                                //_.bindAll(this);

                                                this.bindEvents();
                                            },
                                            render: function () {
                                                Backgrid.Cell.prototype.render.apply(this, arguments);
                                                this.$el.html(this.template(this.model.toJSON()));

                                                if (this.model.get("editing")) {
                                                    this.render_newRow();
                                                } else {
                                                    this.render_actions();
                                                }

                                                this.delegateEvents();
                                                return this;
                                            },
                                            render_newRow: function () {
                                                this.$el.find('[data-toggle="tooltip"]').tooltip();

                                                return this;
                                            },
                                            render_actions: function () {
                                                this.$el.find("[data-toggle=popover]").popover();

                                                //this.$el.find(".dropdown-menu").on("s", function (event) {
                                                //    alert('A');
                                                //});

                                                //this.$el.find(".dropdown-menu").on("hide.bs.dropdown", function (event) {
                                                //    alert('B');
                                                //});

                                                //if (!ctx.editable) {
                                                //  this.$el.find(".configure-source-btn").attr("disabled", true);
                                                //}

                                                this.checkAnyOptions();
                                                return this;
                                            },
                                            bindEvents: function () {
                                                this.listenTo(this.model, 'change:editing change:isLoading', this.checkMode);
                                            },
                                            /////////////////////////////////////////////////////////////////////////////////////
                                            checkMode: function () {
                                                try {
                                                    this.render();
                                                } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                            cellActionClick: function (e) {
                                                try {
                                                    var target = $(e.target);
                                                    var actionData = target.closest('[data-cell-action]').data('cell-action');
                                                    if (actionData) {
                                                        that.actionOnRow(this.model, actionData);
                                                    }
                                                }
                                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                            /////////////////////////////////////////////////////////////////////////////////////
                                            btnGroup_show: function(e){
                                                try {
                                                    that.stopAutoRefresh();
                                                    //If there's an error, this line prevents 
                                                    this.startAutoRefreshTimeoutId = setTimeout(function () { that.startAutoRefresh(); }, 60 * 1000);
                                                }
                                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                            btnGroup_hide: function (e) {
                                                try {
                                                    clearTimeout(this.startAutoRefreshTimeoutId);
                                                    that.startAutoRefresh();
                                                }
                                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                            checkAnyOptions: function () {
                                                var actionSourceBtn = this.$el.find(".action-source-btn");
                                                if (this.$el.find(".action-source-dropdown").find("li").length > 0) {
                                                    actionSourceBtn.attr("disabled", false);
                                                } else {
                                                    actionSourceBtn.attr("disabled", true);
                                                }
                                            },
                                            configure_dropdown_config_opt_click: function (e) {
                                                try {
                                                    e.preventDefault();
                                                    if (!$(e.target).hasClass("disabled-link")) {
                                                        that.configureSource(this.model, { option: $(e.target).data("option") });
                                                    }
                                                } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                                            },
                                        }),
                                    },
                                ],
                                collection: that.items,
                            });
                            that.$el.find('.items-grid-container').append(grid.render().el);

                            //end
                            //appending view to the main container 

                            var fixedParams = _.extend({}, viewParams);

                            //check if agentId param (sectionParam1) is defined
                            if (viewParams.sectionParam1) {
                                that.model.set('agentId', (fixedParams.sectionParam1 != '') ? parseInt(fixedParams.sectionParam1, 10) : 0);
                                that.subviews.subnavbarControls.model.set('agentId', (fixedParams.sectionParam1 != '') ? parseInt(fixedParams.sectionParam1, 10) : 0);
                            }
                            
                            //Call first refresh.
                            var params = that.model.toJSON();

                            that._refresh(_.extend(
                                {},
                                params,
                                {
                                    reset: true,
                                    params: _.extend(
                                        {},
                                        params,
                                        {
                                            agentId: params.agentId,
                                        }
                                    ),
                                }
                            ));

                            that.append(thatContainer, that.$el);

                            //Call first refresh.
                            that.startAutoRefresh();
                        },
                        true,
                        customPath
                    );
                },
                customPath
            );
        },
        search_filters_changed: function () {
            try {
                var params = this.subviews.subnavbarControls.model.toJSON();

                app.router.navigate(
                    app.router.resolveURL(
                        app.router.currentModule,
                        _.extend(
                            {},
                            params,
                            {
                                section: app.router.currentParameters.section,
                                sectionParam1: params.agentId,
                            }
                        ),
                        false
                    ),
                    { trigger: false, }
                );

                this._refresh({ reset: true, });
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        _search_changed: function () {
            try {
                this.doSearch.call(this); 
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }
        , doSearch: function () {
            var search = this.subviews.subnavbarControls.model.get("search");
            
            this.model.set('search', search);

            this._refresh({ reset: true, });
        }
        , configureSource: function (model, data) {
            try {
                //var row = model.attributes; 

                //var type = row.systemType;
                //var typeClass = row.systemTypeClass;
                var menu_option = (data && data.option) ? data.option : null;

                switch (menu_option.toUpperCase()) {
                    case "OPT-RUN":
                        var that = this;
                        this.currentModal = new Modal.Views.Main({
                                focusOk: false,
                                focusSelector: '#btn-cancel',
                                title: app.translate([this, app], "run_modal_confirm_title"),
                                message: app.translate([this, app], "run_modal_confirm_message"),
                                buttons_type: "CONTINUE-CANCEL",
                            });

                        this.listenToOnce(this.currentModal, "continue", function (modal) {
                            try {
                                that.runScript(model);
                                that.currentModal = null;
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        });

                        this.currentModal.show();
                        break;
                    case "OPT-PAUSE":
                        var that = this;
                        this.currentModal = new Modal.Views.Main({
                                focusOk: false,
                                focusSelector: '#btn-cancel',
                                title: app.translate([this, app], "pause_modal_confirm_title"),
                                message: app.translate([this, app], "stop_modal_confirm_message"),
                                buttons_type: "CONTINUE-CANCEL",
                            });

                        this.listenToOnce(this.currentModal, "continue", function (modal) {
                            try {
                                that.pauseScript(model);
                                that.currentModal = null;
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        });

                        this.currentModal.show();
                        break;
                    case "OPT-STOP":
                        var that = this; 
                        this.currentModal = new Modal.Views.Main({
                                focusOk: false,
                                focusSelector: '#btn-cancel',
                                title: app.translate([this, app], "stop_modal_confirm_title"),
                                message: app.translate([this, app], "stop_modal_confirm_message"),
                                buttons_type: "CONTINUE-CANCEL",
                            });

                        this.listenToOnce(this.currentModal, "continue", function (modal) {
                            try {
                                that.stopScript(model);
                                that.currentModal = null;
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        });

                        this.currentModal.show();
                        break;
                    case "OPT-CLONE":
                        this.addNewClone(model);
                        break;
                    case "OPT-DELETE":
                        var that = this;
                        this.currentModal = new Modal.Views.Main({
                                focusOk: false,
                                focusSelector: '#btn-cancel',
                                title: app.translate([this, app], "delete_item_modal_confirm_title"),
                                message: app.translate([this, app], "delete_item_modal_confirm_message"),
                                buttons_type: "CONTINUE-CANCEL",
                            });

                        this.listenToOnce(this.currentModal, "continue", function (modal) {
                            try {
                                that.removeRow(model);
                                that.currentModal = null;
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        });

                        this.currentModal.show();
                        break;
                    case "OPT-DOWNLOAD":
                        this.downloadScript(model);
                        break;
                    case "OPT-GET-LOGS":
                        this.getScriptLogs(model);
                        break;
                }
                
            }catch(Error){}
        }, 
        actionOnRow: function (model, action) {
            try {
                switch (action.toUpperCase()) {
                    case 'SAVE':
                        this.startAutoRefresh();
                        this.saveRow(model);
                        break;
                    case 'DISCARD':
                        this.startAutoRefresh();
                        this.discardRow(model);
                        break;
                }
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        addNewBtn_click: function (e) {
            try {
                this.addNew();
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        addNew: function () {
            var newSourceId = null;

            this.stopAutoRefresh();

            //Set preview scripts 'isNew' attribute to false
            this.items.forEach(function (model, index) {
                model.set('isNew', false);
            });

            this.items.unshift({
                id: -1,
                agentId: this.model.get('agents')[0].value,
                statusCode: 'NEWROW',

                isNew: true,
                editing: true,
            });

            // When 'No data avaliable' is shown, the Add Script button does
            // not show the backgrid because of the attribute hasData is false
            this.model.set('hasData', true);

            //Scroll to top
            this.$el.scrollTop(0);
            
            //Get the model of the new row
            for (var i = 0; i < this.grids.items.body.rows.length; i++) {
                if (this.grids.items.body.rows[i].model.get('id') == -1) {
                    newSourceId = i;
                    break;
                }
            }

            //Enter edit mode of the new row
            if (newSourceId >= 0)
                this.grids.items.body.rows[newSourceId].cells[0].enterEditMode();
        },
        addNewClone: function (model) {
            var newCloneId = null;

            this.stopAutoRefresh();

            //Set preview scripts 'isNew' attribute to false
            this.items.forEach(function (model, index) {
                model.set('isNew', false);
            });

            this.items.unshift({
                id: -1,
                agentId: model.get('agentId'),
                name: model.get('name') + app.translate([this, app], 'copy_label'),
                statusCode: 'NEWROW',
                toCloneId: model.get('id'),

                isNew: true,
                editing: true,
            });

            //Scroll to top
            setTimeout(
            function () {
                $('html, body').scrollTop(0);
            }, 10);

            //Get the model of the new row
            for (var i = 0; i < this.grids.items.body.rows.length; i++) {
                if (this.grids.items.body.rows[i].model.get('id') == -1) {
                    newCloneId = i;
                    break;
                }
            }

            //Enter edit mode of the new row
            if (newCloneId >= 0)
                this.grids.items.body.rows[newCloneId].cells[0].enterEditMode();
        },
        collection_fetch: function (coll, resp) {
            try {
                this.model.set({
                    hasData: (this.items.length > 0),
                    isLoading: false,
                });
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        discardRow: function (m) {
            //to discard just remove the model from the collection.
            m.collection.remove(m);
        },
        removeRow: function (model) {
            var that = this;
            model.collection.removeItem(
                model.get('id')
                , function (coll, data) {
                    app.views.topMessages.showMessage(app.translate([that, app], 'SAVED_CHANGES_SUCCESSFUL'), { stay: 5 * 1000, });

                    that.items.remove(model);
                }
                , function (coll, msg) {
                    app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                    that._refresh();
                }
            );
        },
        saveRow: function (m) {
            try {
                var that = this;

                //If the model has the property toCloneId, it will call the procedure to clone the item
                if (!m.get('toCloneId')) {
                    m.collection.upsertItem(null, [
                        { name: 'Name', type: 'VARCHAR', value: m.get('name') },
                        { name: 'AgentId', type: 'VARCHAR', value: m.get('agentId') },
                    ], function (ref, data) {
                        m.setRaw(data);
                        m.set({ editing: false, isNew: true, }, { avoidSync: true });
                        that._refresh({ refresh: true });
                    }, function (coll, msg) {
                        app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                        that._refresh();
                    });
                }
                else
                {
                    Script.clone(
                        {
                            params: [
                                { name: 'Id', type: 'INT', value: m.get('toCloneId') },
                                { name: 'Name', type: 'VARCHAR', value: m.get('name') },
                                { name: 'AgentId', type: 'INT', value: m.get('agentId') },
                            ],
                            success: function (ref, data) {
                                m.setRaw(data);
                                m.set({ editing: false, toCloneId: null}, { avoidSync: true });
                                that._refresh({ refresh: true });
                            },
                            error: function (coll, msg) {
                                app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                                that._refresh();
                            },
                        }
                    );
                }
            }
            catch (error) {console.error((error.stack) ? error.stack : new Error(error).stack);}
        },
        runScript: function (m) {
            try {
                var that = this;

                //Set model property to indicates loading state on screen
                m.set('isLoading', true);

                m.run(
                    {
                        success: function (commandResp) {
                            try {
                                if (commandResp.statusCode == "OK") {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_RUN_COMMAND_SUCCESSFUL'), { stay: 5 * 1000, });
                                }
                                else {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_RUN_COMMAND_ERROR'), { stay: 5 * 1000, });
                                }
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                        error: function (msg, msgParams) {
                            try {
                                app.views.topMessages.showMessage(app.translate([that, app], msg, msgParams), { stay: 10 * 1000, });
                                m.set('isLoading', false);
                                that._refresh();
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        },
                        //success: function (ref, ids) {
                        //    m.set('isLoading', false);
                        //},
                        //error: function (coll, msg) {
                        //    m.set('isLoading', false);
                        //    that._refresh();
                        //},
                    }
                );
            }
            catch (error) {
                m.set('isLoading', false);

                console.error((error.stack) ? error.stack : new Error(error).stack);
            }
        },
        pauseScript: function (m) {
            try {
                var that = this;

                //Set model property to indicates loading state on screen
                m.set('isLoading', true);

                m.pause(
                    {
                        success: function (commandResp) {
                            try {
                                if (commandResp.statusCode == "OK") {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_PAUSE_COMMAND_SUCCESSFUL'), { stay: 5 * 1000, });
                                }
                                else {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_PAUSE_COMMAND_ERROR'), { stay: 5 * 1000, });
                                }
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                        error: function (msg, msgParams) {
                            try {
                                app.views.topMessages.showMessage(app.translate([that, app], msg, msgParams), { stay: 10 * 1000, });
                                m.set('isLoading', false);
                                that._refresh();
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        },
                        //success: function (ref, ids) {
                        //    m.set('isLoading', false);
                        //},
                        //error: function (coll, msg) {
                        //    app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                        //    m.set('isLoading', false);
                        //    that._refresh();
                        //},
                    }
                );
            }
            catch (error) {
                m.set('isLoading', false);

                console.error((error.stack) ? error.stack : new Error(error).stack);
            }
        },
        stopScript: function (m) {
            try
            {
                var that = this;

                //Set model property to indicates loading state on screen
                m.set('isLoading', true);

                m.stop(
                    {
                        success: function (commandResp) {
                            try {
                                if (commandResp.statusCode == "OK") {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_STOP_COMMAND_SUCCESSFUL'), { stay: 5 * 1000, });
                                }
                                else {
                                    app.views.topMessages.showMessage(app.translate([that, app], 'DMT_STOP_COMMAND_ERROR'), { stay: 5 * 1000, });
                                }
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                        error: function (msg, msgParams) {
                            try {
                                app.views.topMessages.showMessage(app.translate([that, app], msg, msgParams), { stay: 10 * 1000, });
                                m.set('isLoading', false);
                                that._refresh();
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        },
                        //success: function (ref, ids) {
                        //    m.set('isLoading', false);
                        //},
                        //error: function (coll, msg) {
                        //    app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                        //    m.set('isLoading', false);
                        //    that._refresh();
                        //},
                    }
                );
            }
            catch (error) {
                m.set('isLoading', false);

                console.error((error.stack) ? error.stack : new Error(error).stack);
            }
        },
        getScriptLogs: function (m) {
            try
            {
                var that = this;

                //Set model property to indicates loading state on screen
                m.set('isLoading', true);

                m.getLogs(
                    {
                        success: function (model, data) {
                            try {
                                var byteString = atob(data);

                                // Convert that text into a byte array.
                                var ab = new ArrayBuffer(byteString.length);

                                var ia = new Uint8Array(ab);

                                for (var i = 0; i < byteString.length; i++)
                                    ia[i] = byteString.charCodeAt(i);

                                // Blob for saving.
                                var blob = new Blob([ia], { type: 'application/octet-stream' });

                                // Tell the browser to download the file.
                                saveAs(blob, 'logs.' + m.get('name') + '.' + new moment().format('YYYYMMDDHHmmss') + '.zip');
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                        error: function (model, msg) {
                            try {
                                app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                    }
                );
            }
            catch (error) {
                m.set('isLoading', false);

                console.error((error.stack) ? error.stack : new Error(error).stack);
            }
        },
        downloadScript: function (m) {
            try {
                var that = this;

                //Set model property to indicates loading state on screen
                m.set('isLoading', true);

                m.download(
                    {
                        success: function (model, data) {
                            try {
                                // Blob for saving.
                                var blob = new Blob([new Uint8Array(data.Content)], { type: 'application/octet-stream' });

                                // Tell the browser to download the file.
                                saveAs(blob, data.FileName);
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                        error: function (model, msg) {
                            try {
                                app.views.topMessages.showMessage(app.translate([that, app], msg), { stay: 10 * 1000, });
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            finally {
                                try {
                                    m.set('isLoading', false);
                                }
                                catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                            }
                        },
                    }
                );
            }
            catch (error) {
                m.set('isLoading', false);

                console.error((error.stack) ? error.stack : new Error(error).stack);
            }
        },

        append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

            if (this.options.state == app.view_states.loading
                || this.options.state == app.view_states.shown) {
                //appending view to the main container and set state to shown

                this.options.state = app.view_states.shown;
                container.append(el);

                this.options.onappend(this);
            }

            if (this.options.state == app.view_states.hidden) {
                //append and remain hidden
                container.append(el);
            }

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        },
        bindViewScopedEvents: function () {
            //TODO - Put this in events object.
            var that = this;

            this.listeners['beforeunload'] = _.bind(that.window_beforeUnload, that);
            $(window).on('beforeunload', this.listeners['beforeunload']);
        },
        close: function () {
            this.options.state = app.view_states.closed;

            //If currentModal exists, hide it and erase it.
            if (this.currentModal) {
                this.currentModal.hide();
                this.currentModal = null;
            }

            this.stopAutoRefresh();
            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        },
        closeSubviews: function () {
            _.each(this.subviews, function (sview) {
                sview.close();
            });
        },
        hide: function () {
            this.options.state = app.view_states.hidden;

            this.hideSubviews();
            this.stopAutoRefresh();

            this.$el.hide();
            this.unbind();
            this.stopListening();
        },
        hideSubviews: function () {
            _.each(this.subviews, function (sview) {
                sview.hide();
            });
        },
        preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("notificationBar", false);
            app.models.subnavbar.set("dateTimeScopeControl", false); 
            app.models.subnavbar.set("subnavbar", true);
            app.models.subnavbar.set("sections", "12"); 
        },
        remove: function () {
            this.removeBindings();
            this.$el.remove();
            this.stopListening();
            return this;
        },
        reRender: function () {
            this.startAutoRefresh();
        },
        show: function () {
            this.options.state = app.view_states.shown;

            this.showSubviews();
            this.bindEvents();
            this.$el.show();
        },
        showSubviews: function () {
            _.each(this.subviews, function (sview) {
                sview.show();
            });
        },
        startAutoRefresh: function () {
            try {
                if (this.autoRefresh.enabled !== true) {
                    var that = this;

                    if (this.autoRefresh.toid != null) {
                        clearTimeout(this.autoRefresh.toid);
                        this.autoRefresh.toid = null;
                    }

                    this.autoRefresh.enabled = true;

                    //use a timeout to execute the first refresh to return the handle to the start function caller.
                    //So when the caller finish it will do the first refresh.
                    this.autoRefresh.toid = setTimeout(
                        function () { that._refresh(); },
                        1
                    );
                }
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        stopAutoRefresh: function () {
            if (this.autoRefresh.toid != null) {
                clearTimeout(this.autoRefresh.toid);
                this.autoRefresh.toid = null;
            }
            this.autoRefresh.enabled = false;
        },
        unbindViewScopedEvents: function () {
            $(window).off('beforeunload', this.listeners['beforeunload']);

            this.stopAutoRefresh();
        },
        window_beforeUnload: function (e) {
            try {
                if (this.currentModal) {
                    this.currentModal.hide();
                }
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
    });

    Screen.Models.SubnavBarControls = Backbone.Epoxy.Model.extend({
        defaults: {
            search: '',
            agentId: 0,
            agents: [],

            showRunning: true,
            showPaused: true,
            showStopped: true,
            showNew: true,
        },
        computeds: {
            hasAgents: {
                deps: ['agents'],
                get: function (value) {
                    return ((value) && (value.length != 0));
                },
            },
        },
    });

    //subview for the subnavbar controls
    Screen.Views.SubnavBarControls = Backbone.Epoxy.View.extend({
        id: 'scripts-status-subnavbar-controls',
        title: '',
        template: 'scripts-status',

        initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            this.model = new Screen.Models.SubnavBarControls({});

            this.bindEvents();
        },
        events:{
            "change #show_running_tags_checkbox": "_showOnlyEnabledTags_checkbox_click", 
            "change #show_paused_tags_checkbox": "_showOnlyEnabledTags_checkbox_click",
            "change #show_stopped_tags_checkbox": "_showOnlyEnabledTags_checkbox_click",
        },

        render: function (container, onComplete) {
            var that = this;
            var thatContainer = (container) ? container : (this.options.container) ? this.options.container : null;
            var onViewComplete = (onComplete) ? onComplete : function () { };

            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = '/app/custom-screens/dmt/' + this.template + '/';

            T.render.call(this, this.template, function (tmp) {
                if (!that.options.i18n) that.options.i18n = {};
                app.getI18NJed(that, that.template, function (i18nJED) {
                    //storing internationalization data
                    that.options.i18n[that.template] = i18nJED;

                    var ctx = {
                        editable: (($.inArray('AdminUserRole', app.models.user.get('roles')) != -1
                            || $.inArray('SupervisorUserRole', app.models.user.get('roles')) != -1) ? true : false),
                    };

                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp(
                        _.extend({}, ctx, (that.model) ? that.model.toJSON() : {})
                    ));

                    that.applyBindings();

                    //that.$el.find('.clear-search').clearSearch();

                    that.append(thatContainer, that.$el);

                }, true, customPath);
            }, customPath, 'subnavbar_controls');

        },
        bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
        },

        append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

            if (this.options.state == app.view_states.loading
                || this.options.state == app.view_states.shown) {
                //appending view to the main container and set state to shown

                this.options.state = app.view_states.shown;
                container.append(el);

                this.options.onappend(this);
            }

            if (this.options.state == app.view_states.hidden) {
                //append and remain hidden
                container.append(el);
            }

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        },
        close: function () {
            this.options.state = app.view_states.closed;

            this.remove();
            this.unbind();
        },
        show: function () {
            this.options.state = app.view_states.shown;

            this.bindEvents();
            this.$el.show();
        },
        hide: function () {
            this.options.state = app.view_states.hidden;

            this.$el.hide();
            this.unbind();
            this.stopListening();
        },
    });
    
    // Required, return the module for AMD compliance.
    return Screen;

});
