//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',
  'backgrid',
  "modules/modal2",
  'moment',

  'backgrid/infinator',
  'backgrid/moment-cell',
  'js/jquery.clearsearch/jquery.clearsearch',
],
function (app, T, Backgrid, Modal, moment) {
    //replace all 'Audit' with your view's name.
    var Audit = {
        Models: {},
        Views: {},
        Collections: {},
    };

    Audit.Models.AuditMessage = Backbone.Epoxy.Model.extend({
        defaults: {
            id: 0,
            message: '',
            moduleName: '',
            timestamp: null,
            userName: '',
        },
    });

    Audit.Collections.AuditMessages = Backbone.Collection.extend({
        model: Audit.Models.AuditMessage,

        comparator: function (modA, modB) {
            var a = new moment(modA.get('timestamp')),
                b = new moment(modB.get('timestamp')); 

            return (a.isAfter(b))
                    ? -1
                    : (a.isBefore(b))
                        ? 1
                        : 0;      
        },

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

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

            this.isFetching = true;

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

                this.fixedParameters = [
                    { Name: '@start', Type: 'DATE', Value: params.start, },
                    { Name: '@end', Type: 'DATE', Value: params.end, },
                    { Name: '@search', Type: 'VARCHAR', Value: params.search, },
                    { Name: '@timeZoneCode', Type: 'CHAR', Value: app.models.user.get('timezoneCode'), },
                ];
            }

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

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

            Core.Json.CallProcedure(
                app.DatabaseNames.System + '.SYSTEM.GetAuditDataWeb',
                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, function (record) {
                                    return {
                                        id: record.Id,
                                        message: record.Message,
                                        moduleName: record.ModuleName,
                                        timestamp: record.Timestamp,
                                        userName: record.UserName,
                                    };
                                });


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

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

                                that[method](newColl)
                                    //.sort()
                                    .trigger('fetch', this, records);

                                //decreasing page since we couldn't get any data on this page.
                                if (newColl.length == 0 && method == 'add')
                                    that.currentPage--;

                                that.isFetching = false;


                                ////Put props in the order to be displayed
                                //that.set(newColl)
                                //    .trigger('fetch', this, records);
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error('Server response not valid.');
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        insert: function (options) {
            var that = this,
                qp = new Core.Database.QueryParameters(),
                opt = _.extend(
                    {
                        params: [],
                    },
                    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.System + '.SYSTEM.InsertAuditItemManually',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp && !resp.Message) {
                                if (opt.success != null && _.isFunction(opt.success))
                                    opt.success(that, resp);
                            } else {
                                var errorMsg = (resp && resp.Message)
                                                    ? resp.Message
                                                    : "SERVER_RESPONSE_NOT_VALID"

                                if (opt.error != null && _.isFunction(opt.error))
                                    opt.error(that, resp.Message);

                                console.error(errorMsg);
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onError: function (errorMsg) {
                        try {
                            if (opt.error != null && _.isFunction(opt.error))
                                opt.error(that, errorMsg);

                            console.error(errorMsg);
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    Async: true,
                    Secured: true,
                },
                app.ConnectionStrings.app
            );
        },
        getNextPage: function (options) {
            if (!this.isFetching) {
                this.currentPage++;
                options = (_.isObject(options)) ? options : {};
                this.fetch(options);
            }
        },
        resetPagination: function (force) {
            if (!this.isFetching || force == true) {
                this.currentPage = 1;
            } else {
                _.delay(this.resetPagination, 100);
            }
        },
    });

    Audit.Models.Main = Backbone.Epoxy.Model.extend({
        defaults: {
            start: new moment().subtract(1, "day").format('MM/DD/YYYY'),
            end: new moment().format('MM/DD/YYYY'),
            search: null,

            hasData: false,
            isLoading: true,
        },
    });

    //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.
    Audit.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return 'audit';
        } catch (Error) { }
    }

    Audit.Views.Main = Backbone.Epoxy.View.extend({
        template: 'audit'
        , id: 'audit'
        , title: 'Audit'
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a fetch method to reset the view without erasing the DOM.
        , isCacheable: false
        , events: function () {
            return {
                'click .add-item': this.addNewBtn_click,
                'click #excelBtn': this.excelBtn_click,
                'click #refreshBtn': this.refreshBtn_click,
            };
        }
        , bindings: 'data-bind'
        , templates: null

        , auditColl: null
        , viewParams: null

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

            this.model = new Audit.Models.Main();
            this.auditColl = new Audit.Collections.AuditMessages();

            this.templates = {
                addNewModal: null,
            };

            this.bindEvents();
        }

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

            if (opt.refresh == true)
                this.model.set('isLoading', true);

            this.auditColl.fetch({
                start: opt.params.start,
                end: opt.params.end,
                search: (opt.params.search) ? opt.params.search : null,

                refresh: opt.refresh,
            });
        }
        , refresh: function (params) {
            var fixedParams = _.extend({}, Audit.Models.Main.prototype.defaults, params);

            if (params.start)
                fixedParams.start = (fixedParams.start != '-') ? new moment(fixedParams.start, 'YYYYMMDD').format('MM/DD/YYYY') : null;
            if (fixedParams.end)
                fixedParams.end = (fixedParams.end != '-') ? new moment(fixedParams.end, 'YYYYMMDD').format('MM/DD/YYYY') : null;
            if (fixedParams.search)
                fixedParams.search = (fixedParams.search != '-') ? fixedParams.search : null;

            this.model.set(fixedParams);

            var params = this.model.toJSON();

            this._refresh(_.extend(
                {},
                params,
                {
                    refresh: true,
                    params: _.extend(
                        {},
                        params,
                        {
                            start: new moment(params.start, "MM/DD/YYYY").format("YYYY-MM-DD"),
                            end: new moment(params.end, "MM/DD/YYYY").format("YYYY-MM-DD"),
                        }
                    ),
                }
            ));
        }
        , 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/IHConfiguration/audit/';

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


                    var grid = new Backgrid.Grid({
                        className: 'backgrid table table-hover table-condensed',
                        columns: [
                            {
                                name: 'timestamp',
                                label: 'Datetime',
                                editable: false,
                                cell: Backgrid.Extension.MomentCell.extend({
                                    className: 'momment-cell align-center-cell timestamp',
                                    modelFormat: 'YYYY-MM-DD HH:mm:ss',
                                    displayFormat: 'YYYY-MM-DD HH:mm:ss',
                                }),
                            },
                            {
                                name: 'moduleName',
                                label: 'Module',
                                editable: false,
                                cell: Backgrid.StringCell.extend({
                                    orderSeparator: '',
                                    className: 'string-cell align-center moduleName',
                                }),
                            },
                            {
                                name: 'userName',
                                label: 'User',
                                editable: false,
                                cell: Backgrid.StringCell.extend({
                                    orderSeparator: '',
                                    className: 'string-cell align-center userName',
                                }),
                            },
                            {
                                name: 'message',
                                label: 'Message',
                                editable: false,
                                cell: Backgrid.StringCell.extend({
                                    orderSeparator: '',
                                    className: 'string-cell align-left message',
                                }),
                            },
                        ],
                        collection: that.auditColl,
                        footer: Backgrid.Extension.Infinator.extend({
                            scrollToTop: false,
                        }),
                    });

                    that.$el.find('.items-grid-container').append(grid.render().el);


                    that.$el.find('.input-date').datepicker();


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


                    that.templates.addNewModal = Handlebars.compile(that.$el.find('#add_new_modal_template').html());


                    //Set model with view params here to prevent changes on the model when the view bindings are applied.
                    var fixedParams = _.extend({}, viewParams);

                    if (fixedParams.start)
                        fixedParams.start = (fixedParams.start != '-') ? new moment(fixedParams.start, 'YYYYMMDD').format('MM/DD/YYYY') : null;
                    if (fixedParams.end)
                        fixedParams.end = (fixedParams.end != '-') ? new moment(fixedParams.end, 'YYYYMMDD').format('MM/DD/YYYY') : null;
                    if (fixedParams.search)
                        fixedParams.search = (fixedParams.search != '-') ? fixedParams.search : null;

                    that.model.set(fixedParams);

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

                    that._refresh(_.extend(
                        {},
                        params,
                        {
                            refresh: true,
                            params: _.extend(
                                {},
                                params,
                                {
                                    start: new moment(params.start, "MM/DD/YYYY").format("YYYY-MM-DD"),
                                    end: new moment(params.end, "MM/DD/YYYY").format("YYYY-MM-DD"),
                                }
                            ),
                        }
                    ));

                }, true, customPath);
            }, customPath);
        }

        , searchChanged: _.debounce(function (a, b, c) {
            this.refreshBtn_click(); 
        }, 300)

        , 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;
            }
        }
        , 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.auditColl, 'fetch', this.auditColl_fetch);
            this.listenTo(this.model, 'change:search', this.searchChanged);
        }
        , bindViewScopedEvents: function () {
            var that = this;
        }
        , unbindViewScopedEvents: function () {

        }
        , close: function () {
            this.options.state = app.view_states.closed;

            this.remove();
            this.unbindViewScopedEvents();
            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();
        }
        , preRender: function () {
            app.models.subnavbar.set('subnavbar', false);
        }
        , reRender: function (viewParams) {
            try {
                this.refresh(viewParams);
            } catch (Error) { }
        }


        , addNewBtn_click: function (e) {
            try {
                var that = this,
                    clickedBtn = $(e.target);

                //Disable clicked button to prevent issues with multiple clicks.
                clickedBtn.attr("disabled", true);

                var modal = new Audit.Views.AddNewModal({
                    i18n: this.options.i18n[this.template],
                    template: this.templates.addNewModal,
                });

                var fn_modal_shown_hidden = function () {
                    try {
                        //Enable button in both events, shown and hidden, just to prevent issues if one of them fails
                        //or it is not executed for some reason.
                        clickedBtn.attr("disabled", false);
                    }
                    catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                };

                this.listenToOnce(modal, 'shown', fn_modal_shown_hidden)
                    .listenToOnce(modal, 'hidden', fn_modal_shown_hidden)
                    .listenTo(modal, 'saving', function (modal, data, callbacks) {
                        try {
                            that.auditColl.insert({
                                params: [
                                        { name: 'Message', type: 'VARCHAR', value: data.message, },
                                ],
                                success: function (coll) {
                                    try {
                                        callbacks.success();
                                    }
                                    catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                                },
                                error: function (coll, msg) {
                                    try {
                                        callbacks.error(msg);
                                    }
                                    catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                                }
                            });
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    })
                    .listenToOnce(modal, 'finish', function (modal, data) {
                        try {
                            if (data.result == 'SUCCESS') {
                                that._refresh({ refresh: true, });
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    });;

                modal.show();
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
        , excelBtn_click: function (e) {
            try {
                var qp = new Core.Database.QueryParameters(),
                    attrs = this.model.toJSON(),
                    params;

                params = [
                    { Name: '@start', Type: 'DATE', Value: attrs.start, },
                    { Name: '@end', Type: 'DATE', Value: attrs.end, },
                    { Name: '@search', Type: 'VARCHAR', Value: attrs.search, },
                    { Name: '@timeZoneCode', Type: 'CHAR', Value: app.models.user.get('timezoneCode'), },
                ];

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


                Core.Export.Excel(
                    {
                        Data: [
                            {
                                SheetName: 'Audit',
                                RowsData: [],
                                StartRowIndex: 2,
                                DataSourceName: 'data',
                                DataSourceTableIndex: 0,
                                SQLCellsData: [
                                    { ExcelColumnName: 'A', SQLDataColumnName: 'Timestamp', DataType: 'String' },
                                    { ExcelColumnName: 'B', SQLDataColumnName: 'Message', DataType: 'String' },
                                    { ExcelColumnName: 'C', SQLDataColumnName: 'ModuleName', DataType: 'String' },
                                    { ExcelColumnName: 'D', SQLDataColumnName: 'UserName', DataType: 'String' },
                                ],
                            },
                        ],
                        ConnectionStringName: app.ConnectionStrings.app,
                        FileName: 'Audit report',
                        TemplateFileFullPath: this.template + '-template-excel.xls',
                        SQLDataSources: [
                            {
                                Name: 'data',
                                DatabaseParameters: {
                                    DBEngine: 'SQLSERVER',
                                    Procedure: app.DatabaseNames.System + '.SYSTEM.GetAuditDataWeb',
                                    QueryParameters: qp, 
                                },
                            },
                        ]
                    }, 
                    function (resp) {
                        try {
                            if ((resp) && (resp.Success == true) && (resp.Data)) {
                                location.href = app.foldersRoot + '/excel/' + resp.Data;
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error('Server response not valid.');
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    function (resp) {
                        console.error(resp);
                    }
                );


                //Core.Export.Excel(
                //    {

                //        Data: [
                //            {
                //                SheetName: 'Data',
                //                RowsData: [{
                //                    CellsData: [
                //                        { Column: "A", Value: "Datetime" },
                //                        { Column: "B", Value: "Message" },
                //                        { Column: "C", Value: "Module" },
                //                        { Column: "D", Value: "User" },
                //                    ]
                //                }],
                //                StartRowIndex: 1,
                //            },
                //            {
                //                SheetName: 'Data',
                //                RowsData: [],
                //                StartRowIndex: 2,
                //                DataSourceName: 'data',
                //                DataSourceTableIndex: 0,
                //                SQLCellsData: [
                //                    { ExcelColumnName: 'A', SQLDataColumnName: 'Timestamp', DataType: 'String' },
                //                    { ExcelColumnName: 'B', SQLDataColumnName: 'Message', DataType: 'String' },
                //                    { ExcelColumnName: 'C', SQLDataColumnName: 'ModuleName', DataType: 'String' },
                //                    { ExcelColumnName: 'D', SQLDataColumnName: 'UserName', DataType: 'String' },
                //                ],
                //            }
                //        ],
                //        ConnectionStringName: app.ConnectionStrings.app,
                //        FileName: 'Audit report',
                //        TemplateFileFullPath: 'generic.xls',
                //        SQLDataSources: [
                //            {
                //                Name: 'data',
                //                DatabaseParameters: {
                //                    DBEngine: 'SQLSERVER',
                //                    Procedure: app.DatabaseNames.System + '.SYSTEM.GetAuditDataWeb',
                //                    QueryParameters: qp,
                //                },
                //            },
                //        ]
                //    },
                //    function (resp) {
                //        try {
                //            if ((resp) && (resp.Success == true) && (resp.Data)) {
                //                location.href = app.foldersRoot + '/excel/' + resp.Data;
                //            }
                //            else {
                //                if ((resp) && (resp.Message))
                //                    console.error(resp.Message);
                //                else
                //                    console.error('Server response not valid.');
                //            }
                //        }
                //        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                //    },
                //    function (resp) {
                //        console.error(resp);
                //    }
                //);
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }            
        }
        , refreshBtn_click: function (model) {
            try {
                var params = this.model.toJSON();

                //app.router.navigate(
                //    app.router.resolveURL(
                //        app.router.currentModule,
                //        _.extend(
                //            {},
                //            params,
                //            {
                //                start: (params.start) ? new moment(params.start, 'MM/DD/YYYY').format('YYYY-MM-DD') : '-',
                //                end: (params.end) ? new moment(params.end, 'MM/DD/YYYY').format('YYYY-MM-DD') : '-',
                //                search: (params.search) ? params.search : '-',
                //            }
                //        ),
                //        false
                //    ),
                //    { trigger: false, }
                //);

                this._refresh(_.extend(
                    {},
                    params,
                    {
                        refresh: true,
                        params: _.extend(
                            {},
                            params,
                            {
                                start: new moment(params.start, "MM/DD/YYYY").format("YYYY-MM-DD"),
                                end: new moment(params.end, "MM/DD/YYYY").format("YYYY-MM-DD"),
                            }
                        ),
                    }
                ));
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
        , auditColl_fetch: function (coll, rawData) {
            try {
                var that = this;

                setTimeout(
                    function () {
                        that.model.set({
                            hasData: (that.auditColl.length > 0),
                            isLoading: false,
                        });
                    },
                    100
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
    });

    Audit.Models.AddNewModal = Backbone.Epoxy.Model.extend({
        defaults: {
            message: null,

            //errorMsg: "",
            processing: false,
        },
    });

    Audit.Views.AddNewModal = Modal.Views.SimpleModal.extend({
        className: Modal.Views.SimpleModal.prototype.className + ' add-new-modal',

        initialize: function (options) {
            _.extend(this, options);

            if (!this.model)
                this.model = new Audit.Models.AddNewModal();


            this.bindEvents();

            return this;
        },

        save: function () {
            var that = this,
                attrs = this.model.toJSON();

            if (attrs.processing == false) {
                this.model.set('processing', true);

                try {
                    this.trigger(
                        'saving', 
                        this, 
                        attrs,
                        {
                            success: function () {
                                try {
                                    that.model.set('processing', false);

                                    that.finish({ result: 'SUCCESS', });

                                    that.hide();
                                    //setTimeout(_.bind(that.hide, that), 1500);
                                }
                                catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                            },
                            error: function (errorMsg) {
                                try {
                                    app.views.topMessages.showMessage(app.translate([{ options: { i18n: { 1: that.i18n, }, }, template: 1, }, app], errorMsg), { stay: 5 * 1000, });
                                }
                                catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                                finally {
                                    that.model.set('processing', false);
                                }
                            },
                        }
                    );
                }
                catch (e) {
                    this.model.set('processing', false);
                    throw e;
                }
            }
        },
        show: function () {
            if (!this.isRendered) {
                this.render();
            }
            else {
                this.$el.modal({
                    keyboard: false,
                    backdrop: 'static',
                });
            }

            return this;
        },

        acceptBtn_click: function (e) {
            try {
                this.save();
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        },
    });

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

});