//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",

  "modules/dateControl",
  "moment",

  "js/bootstrap-timepicker/js/bootstrap-timepicker",
  //"js/perfect-scrollbar/js/perfect-scrollbar",
  "js/perfect-scrollbar/js/perfect-scrollbar.jquery",

],

function (app, T, Modal, DateControl, moment) {

    //replace all "Shifts" with your view's name.
    var Shifts = { Models: {}, Views: {}, Collections: {} }

    Shifts.Models.Shift = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
            start: null,
            end: null,
            duration: null,
            weekdays: null,
            enabled: null, 
        }, 
    });

    Shifts.Models.NoActivityPeriod = Backbone.Model.extend({
        defaults: {
            id: null, 
            from: null,
            to: null, 
        }, 
    }); 

    Shifts.Collections.NoActivityPeriods = Backbone.Collection.extend({
        model: Shifts.Models.NoActivityPeriod,
        fetch: function (opt) {
            var options = {
                method: "set",
                async: true,
                callback: null,
            };

            options = _.extend(options, (opt) ? opt : {});

            var that = this,
                QP = new Core.Database.QueryParameters();

            var items = [];

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.GetNoActivityPeriods", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var data = data.Table;

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];

                            items.push({
                                id: itemData.Id, 
                                from: itemData.From,
                                to: itemData.To,
                            });
                        }
                    }

                    var newItems = _.where(that.toJSON(), { isNew: true });
                    [].push.apply(items, newItems);

                    that[options.method](items, { from: "fetch" });

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(this, that);
                },
                Async: options.async,
                Secured: true,
            }, app.ConnectionStrings.app);

            return this;
        },
        callRemoveItem: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

            QP.Add("@Id", "INT", id);

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.RemoveNoActivityPeriod", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that);
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        removeItem: function (id, success, error) {
            var that = this;
            var model = this.get(id);
            if (model) {
                this.callRemoveItem(
                    id
                    , function (ref, ids) {
                        //removing from collection; 
                        that.remove(model);

                        if (success && _.isFunction(success))
                            success.call(this, that, ids);
                    },
                    function (ref) {
                        if (error && _.isFunction(error))
                            error.call(this, that);
                    }
                );
            }
        },
    }); 

    Shifts.Collections.Shifts = Backbone.Collection.extend({
        model: Shifts.Models.Shift,
        initialize: function () {
            _.bindAll(this);
        },
        fetch: function (opt) {
            var options = {
                method: "set",
                async: true,
                callback: null,
            };

            options = _.extend(options, (opt) ? opt : {});

            var that = this,
                QP = new Core.Database.QueryParameters();

            var items = [];

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.GetShiftsCatalog", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var data = data.Table;

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];

                            items.push({
                                id: itemData.Id,
                                name: itemData.Name,
                                start: itemData.Start,
                                end: itemData.End,
                                duration: itemData.Duration, 
                                weekdays: itemData.WeekDays,
                                enabled: itemData.Enabled, 
                            });
                        }
                    }

                    var newItems = _.where(that.toJSON(), { isNew: true });
                    [].push.apply(items, newItems);

                    that[options.method](items, { from: "fetch" });

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(this, that);
                },
                Async: options.async,
                Secured: true,
            }, app.ConnectionStrings.app);

            return this;
        },
        callRemoveItem: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

            QP.Add("@Id", "INT", id);

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.RemoveShift", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that);
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        removeItem: function (id, success, error) {
            var that = this;
            var model = this.get(id);
            if (model) {
                this.callRemoveItem(
                    id
                    , function (ref, ids) {
                        //removing from collection; 
                        //that.remove(model);

                        if (success && _.isFunction(success))
                            success.call(this, that, ids);
                    },
                    function (ref) {
                        if (error && _.isFunction(error))
                            error.call(this, that);
                    }
                );
            }
        },
        setItemEnabled: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

            QP.Add("@Id", "INT", id);
            QP.Add("@Enabled", "BIT", 1); 

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.SetShiftEnabled", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that);
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        }
    }); 

    Shifts.Models.Main = Backbone.Model.extend({
        defaults: {
            shifts: null,
            noActivityPeriods: null, 
        },
        initialize: function () {
            this.attributes.shifts = new Shifts.Collections.Shifts();
            this.attributes.noActivityPeriods = new Shifts.Collections.NoActivityPeriods(); 
        }, 
    });

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

    Shifts.Views.Main = Backbone.View.extend({
        template: "shifts"
        , id: "shifts"
        , title: "Shifts"     
        //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: true
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            var model = new Shifts.Models.Main({                
            });

            this.model = model;

            this.options.MYREFERENCES = {
                subviews: {
                    shiftConfiguration: {
                        view: null,
                        model: null, 
                    }
                }
                , autoRefresh: {
                    enabled: true
                    , toid: null
                }
            };

            this.bindEvents();
            _.bindAll(this);
        },

        events: {
            "click .btn-add-shift": "pre_addShift",
            "click .btn-add-day": "addDay", 
            "click .btn-add-period": "addPeriod",

            "click .btn-cancel-add-shift": "pre_cancel_addShift",
            "submit .add-shift-form": "addShift",
        },

        render: function (container) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.options.container;

            //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/IHDelaysConfiguration/shifts/";

            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());

                    var ActionsCell = Backgrid.Cell.extend({
                        template: Handlebars.compile(that.$el.find("#actions_cell_template").html()),
                        className: "actions-cell",
                        initialize: function () {
                            Backgrid.Cell.prototype.initialize.apply(this, arguments);
                        },
                        events: {
                            "click .btn-cell-action": "cellActionClick"
                        },
                        cellActionClick: function (e) {
                            var target = $(e.target);
                            var actionData = target.closest("[data-cell-action]").data("cell-action");
                            if (actionData) {
                                that.actionOnRow(this.model, actionData);
                            }
                        },
                        render: function () {
                            this.$el.html(this.template(
                                this.model.toJSON()
                            ));

                            this.$el.find("[data-toggle='tooltip']").tooltip({
                                delay: {
                                    show: 1000,
                                    hide: 100
                                }, 
                            });

                            this.delegateEvents();
                            return this;
                        },
                    });

                    var columns = [
                        {
                            name: "name",
                            label: "",
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell name",
                            })
                        },
                        {
                            name: "actions",
                            label: "",
                            editable: false,
                            sortable: false,
                            cell: ActionsCell
                        },
                    ];

                    var CustomRow = Backgrid.Row.extend({
                        events: {
                            "click": "onClick"
                        },
                        className: "clickeable-row",
                        initialize: function () {
                            Backgrid.Row.prototype.initialize.apply(this, arguments);

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

                            if (!this.model.get("enabled")) {
                                this.$el.addClass("disabled-row");
                            } else {
                                this.$el.removeClass("disabled-row");
                            }

                            return this; 
                        }, 
                        onClick: function (e) {
                            var target = $(e.target);
                            var data_prevent = (target.closest("[data-preventclick]").length > 0) ? target.closest("[data-preventclick]").data("preventclick") : false;

                            if (!data_prevent) {

                                that.$el.find(".shifts-grid-container").find(".selected").removeClass("selected"); 
                                this.$el.addClass("selected"); 
                                that.shiftClick(this.model);
                            }
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change:enabled", this.render); 
                        }, 
                    });

                    var grid = new Backgrid.Grid({
                        className: "backgrid table table-hover",
                        row: CustomRow, 
                        columns: columns,
                        collection: that.model.get("shifts"),
                    });

                    var grid_el = grid.render().el;
                    $(grid_el).find("th").hide(); 

                    that.$el.find(".shifts-grid-container").append(grid_el);

                    var ActionsCell = Backgrid.Cell.extend({
                        template: _.template(that.$el.find("#noactivity_actions_cell_template").html()),
                        className: "actions-cell",
                        initialize: function () {
                            Backgrid.Cell.prototype.initialize.apply(this, arguments);
                        },
                        events: {
                            "click .btn-cell-action": "cellActionClick"
                        },
                        cellActionClick: function (e) {
                            var target = $(e.target);
                            var actionData = target.closest("[data-cell-action]").data("cell-action");
                            if (actionData) {
                                that.actionOnNoActivityRow(this.model, actionData);
                            }
                        },
                        render: function () {
                            this.$el.html(this.template());

                            this.$el.find("[data-toggle='tooltip']").tooltip();

                            this.delegateEvents();
                            return this;
                        },
                    });

                    var columns = [
                        //{
                        //    name: "from",
                        //    label: "From",
                        //    editable: false,
                        //    sortable: false,
                        //    cell: Backgrid.StringCell.extend({
                        //        orderSeparator: '',
                        //        className: "string-cell align-center-cell name",
                        //    })
                        //},
                        //{
                        //    name: "to",
                        //    label: "To",
                        //    editable: false,
                        //    sortable: false,
                        //    cell: Backgrid.StringCell.extend({
                        //        orderSeparator: '',
                        //        className: "string-cell align-center-cell name",
                        //    })
                        //},
                        {
                            label: app.translate(that, "period_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell name",
                                render: function () {
                                    Backgrid.StringCell.prototype.render.apply(this, arguments); 
                                    var from = this.model.get("from");
                                    var to = this.model.get("to"); 

                                    var text = ""; 
                                    if (from == to) {
                                        text = from;
                                    } else {
                                        text = from + " - " + to; 
                                    }

                                    this.$el.text(text); 

                                    return this;
                                }, 
                            })
                        }, 
                        {
                            name: "actions",
                            label: "",
                            editable: false,
                            sortable: false,
                            cell: ActionsCell
                        },
                    ];

                    var grid = new Backgrid.Grid({
                        className: "backgrid table table-hover",
                        columns: columns,
                        collection: that.model.get("noActivityPeriods"),
                    });

                    var grid_el = grid.render().el;

                    that.$el.find(".no-activity-grid-container").append(grid_el);

                    //end

                    //appending view to the main container
                    that.append(thatContainer, that.$el);

                    //perfect scrollbar custom code start
                    that.$el.find(".shifts-grid-container").perfectScrollbar({
                        suppressScrollX: true,
                    });
                    var _updateScrollbar = function(){
                        that.$el.find(".shifts-grid-container").perfectScrollbar('update'); 
                    }; 
                    that.listenTo(that.model.get("shifts"), "add", _updateScrollbar);
                    that.listenTo(that.model.get("shifts"), "remove", _updateScrollbar);
                    //perfect scrollbar custom code end

                    that.drawShiftsWeekOverviewBar(); 

                    that._startAutoRefresh();
                }, true, customPath);
            }, customPath, "main_template");
        }

        , drawShiftsWeekOverviewBar: function () {
            var that = this; 
            var bar = this.$el.find(".shifts-week-overview-bar");
            var labels = this.$el.find(".shifts-week-overview-bar-labels");

            labels.empty();
            var ttkeys = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]; 
            var day_labels = _.map(ttkeys, function (tkey) {
                return app.translate(that, tkey + "_bar_label");
            });

            for (var i = 0; i < 7; i++) {
                var daylbl = $('<small style="position:absolute;top:-15px;"></small>');
                var marker = $('<div style="position:absolute;top:-50px;height:50px;width:0px;border-left:1px dashed #ccc;"></div>');

                daylbl.text(day_labels[i]);
                var left = ((i * 24 * 100) / 168);

                daylbl.css({ left: (left + 0.5) + '%' });
                marker.css({ left: left + '%' });
                labels.append(marker);
                labels.append(daylbl);
            }

            var shifts = this.model.get("shifts");

            var colors = [
                '#5B89C9', //blue
                '#77D182', //green
                '#DEA02F', // orange
                '#D94C4C', //red
                '#E053E0', //purple
                '#B5B543', //olive
                '#94FF94', //lime
                '#A33C3C', //maroon
                '#F0F07D', //yellow
                '#3FD1D1', //aqua
                '#35B8B8', //team
                '#5050EB', //navy
                '#DE5DDE', //fushua
                '#C2C2C2' //gray
            ];

            //var pastel_colors = _.times(shifts.length, function (n) { return pastelColors() }); 

            var startsFrom = 2;
            bar.empty(); 
            _.forEach(shifts.where({ enabled: true }), function (m, inx) {
                var color = colors[Math.round(inx % colors.length)];
                if (_.isString(m.get("weekdays"))) {
                    _.forEach(m.get("weekdays").split(","), function (weekday) {
                        var b = $('<div class="bar" style="position:absolute;cursor:pointer;overflow:hidden;"></div>');
                        //2: monday, 3: tuesday, 4: wed, 5: thursday, 6: friday, 7: sat, 1: sun
                        var wday = parseInt(weekday, 10);
                        wday = (wday == 1) ? 8 : wday; 

                        var starts = moment.duration(m.get("start"));
                        var duration = parseInt(m.get("duration"), 10);

                        var hoursStart = ((wday - startsFrom) * 24) + starts.as('hours');
                        var left = (hoursStart * 100) / 168;
                        var wd = (duration * 100) / 168;

                        b.css({ width: wd + '%', left: left + '%', 'background-image': 'none' });
                        b.attr('style', function (i, s) { return s + 'background-color: ' + color + ' !important;' });
                        b.text(m.get("name"));

                        bar.append(b);

                        b.popover({
                            html: true,
                            title: m.get("name"),
                            content: _.template("<strong><%= start_lbl %>:</strong> <%= weekday %> <%= start %><br /><strong><%= hours_lbl %>:</strong> <%= duration %></br>")({
                                start: m.get("start"), duration: m.get("duration"), weekday: day_labels[wday - 2],
                                start_lbl: app.translate(that, "start_lbl_popover"), hours_lbl: app.translate(that, "hours_lbl_popover"), 
                            }),
                            placement: "top",
                            trigger: "hover",
                            container: 'body',
                        });
                    });
                }
            }); 
        }

        , pre_addShift: function () {
            var add_shift_form = this.$el.find('.add-shift-form');
            var add_shift_btn = this.$el.find('.btn-add-shift');

            this.set_addshift_buttons_state(false);
            add_shift_form.get(0).reset();

            add_shift_btn.addClass('hide');
            add_shift_form.removeClass('hide');
        }
        , set_addshift_buttons_state: function (v) {
            var add_shift_form = this.$el.find('.add-shift-form');

            var addShiftBtn = add_shift_form.find(".btn-add-shift-final");
            var cancelBtn = add_shift_form.find(".btn-cancel-add-shift"); 
            var shiftNameInput = add_shift_form.find(".input-shift-name"); 

            if (v) {
                addShiftBtn.button('loading'); 
                cancelBtn.attr('disabled', true);
                shiftNameInput.attr('disabled', true); 
            } else {
                addShiftBtn.button('reset');
                cancelBtn.attr('disabled', false);
                shiftNameInput.attr('disabled', false);
            }
        }
        , pre_cancel_addShift: function () {
            this.hide_addShift(); 
        }
        , hide_addShift: function () {
            var add_shift_form = this.$el.find('.add-shift-form');
            var add_shift_btn = this.$el.find('.btn-add-shift');

            add_shift_form.addClass('hide');
            add_shift_btn.removeClass('hide');
        }

        , addShift: function (e) {
            var that = this;
            var add_shift_form = this.$el.find('.add-shift-form');
            if (e && e.preventDefault) e.preventDefault();
            var name = this.$el.find(".input-shift-name").val().trim(); 

            var error_handler = function (b) {
                that.set_addshift_buttons_state(false);

                var error = {
                    type: (b && b.ErrorType) ? b.ErrorType.toUpperCase() : "UNKNOWN",
                    message: (b && b.Message) ? b.Message : "UNKNOWN",
                };

                var error_message = "";
                switch (error.message) {
                    case "UNIQUE_KEY_NAME_ERROR":
                        error_message = app.translate(that, "UNIQUE_KEY_NAME_ERROR");
                        break;
                    default:
                        error_message = app.translate(app, "DEFAULT_CATALOG_ERROR_MESSAGE");
                        break;
                }

                app.views.topMessages.showMessage(error_message);
            }; 

            if (_.isString(name) && !(name.length === 0 || !name.trim())) {
                that.set_addshift_buttons_state(true); 

                var QP = new Core.Database.QueryParameters();
                QP.Add("Name", "VARCHAR", name);

                Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.CreateShift", QP, {
                    onSuccess: function (data) {
                        if (data && data.Table) {
                            //all good!
                            that.hide_addShift(); 
                        } else {
                            error_handler(data); 
                        }

                        that._autoRefresh();
                    },
                    onError: function (data) {
                        error_handler(); 
                    },
                    Async: true,
                    Secured: true,
                }, app.ConnectionStrings.app);
            } else {
                //invalid string
                app.views.topMessages.showMessage(app.translate(this, 'invalid_shift_name_error_message')); 
            }
        }

        , actionOnRow: function (model, action) {
            switch (action.toUpperCase()) {
                case "DELETE":
                    this.removeRow(model);
                    break;
                case "ENABLE":
                    this.enableRow(model);
                    break; 
            }
        }

        , actionOnNoActivityRow: function (model, action) {
            switch (action.toUpperCase()) {
                case "DELETE":
                    this.removeNoActivityRow(model);
                    break;
            }
        }

        , removeNoActivityRow: function (model) {
            var that = this;
            model.collection.removeItem(
                model.get("id")
                , function (data) {
                    that._autoRefresh();
                }
                , function (data) {
                    that._autoRefresh();
                }
            );
        }

        , removeRow: function (model) {
            var wasSelected = false;
            if (this.options.MYREFERENCES.subviews.shiftConfiguration.view != null) {
                if (this.options.MYREFERENCES.subviews.shiftConfiguration.view.model.get("id") == model.get("id")) {
                    wasSelected = true;
                    this.options.MYREFERENCES.subviews.shiftConfiguration.view.close(); 
                }
            }

            var that = this;
            model.collection.removeItem(
                model.get("id")
                , function (data) {
                    that._autoRefresh();
                    if (wasSelected) that.shiftClick(model);
                }
                , function (data) {
                    that._autoRefresh();
                    if (wasSelected) that.shiftClick(model);
                }
            );
        }

        , enableRow: function (model) {
            var wasSelected = false; 
            if (this.options.MYREFERENCES.subviews.shiftConfiguration.view != null) {
                if (this.options.MYREFERENCES.subviews.shiftConfiguration.view.model.get("id") == model.get("id")) {
                    wasSelected = true; 
                    this.options.MYREFERENCES.subviews.shiftConfiguration.view.close();
                }
            }

            var that = this;
            model.collection.setItemEnabled(
                model.get("id")
                , function (data) {
                    that._autoRefresh();
                    if (wasSelected) that.shiftClick(model);
                }
                , function (data) {
                    that._autoRefresh();
                    if (wasSelected) that.shiftClick(model);
                }
            );
        }

        , shiftClick: function (m) {
            if (this.options.MYREFERENCES.subviews.shiftConfiguration.view != null) {
                this.options.MYREFERENCES.subviews.shiftConfiguration.view.close();
                this.options.MYREFERENCES.subviews.shiftConfiguration.view = null; 
            }

            var shiftConfigurationContainer = this.$el.find(".shift-configuration-container");

            var model = new Shifts.Models.ShiftConfiguration();
            this.options.MYREFERENCES.subviews.shiftConfiguration.view = new Shifts.Views.ShiftConfiguration({
                container: shiftConfigurationContainer,
                model: model,
                parent: this, 
            });

            model.fetch({
                data: {
                    id: m.get("id"),
                }
            });

            this.options.MYREFERENCES.subviews.shiftConfiguration.view.render();
        }

        , addDay: function () {
            var that = this; 
            var modal = new Shifts.Views.AddNoActivityPeriodModal({
                singleDay: true,
                events: _.extend(Shifts.Views.AddNoActivityPeriodModal.prototype.events, {
                    "click .btn-add": function () { that.callAddDay(modal); },
                }), 
            });

            modal.show(); 
        }
        , callAddDay: function(modal){
            var that = this; 
            var fromModel = modal.options.viewModels.fromDateControl;
            var from = fromModel.get("date"); 

            this.addNoActivityPeriod(from, from
                , function () {
                    modal.hide();
                    that._autoRefresh(); 
                }
                , function () {
                    modal.hide();
                    that._autoRefresh();
                }
            );
        }
        , addPeriod: function () {
            var that = this;

            var modal = new Shifts.Views.AddNoActivityPeriodModal({
                singleDay: false,
                events: _.extend(Shifts.Views.AddNoActivityPeriodModal.prototype.events, {
                    "click .btn-add": function () { that.callAddPeriod(modal); },
                }),
            });

            modal.show();
        }, 
        callAddPeriod: function (modal) {
            var that = this;
            var fromModel = modal.options.viewModels.fromDateControl;
            var toModel = modal.options.viewModels.toDateControl;
            var from = fromModel.get("date");
            var to = toModel.get("date");

            this.addNoActivityPeriod(from, to
                , function () {
                    modal.hide();
                    that._autoRefresh();
                }
                , function () {
                    modal.hide();
                    that._autoRefresh();
                }
            );
        }, 
        addNoActivityPeriod: function (from, to, success, error) {
            var that = this; 
            var QP = new Core.Database.QueryParameters();

            QP.Add("From", "DATE", from);
            QP.Add("To", "DATE", to);

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.AddNoActivityPeriod", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that);
                    }
                },
                onError: function () {
                    if (error != null && _.isFunction(error))
                        error.call(this, that);
                }, 
                Async: true,
                Secured: true
            }, app.ConnectionStrings.app);
        }

        , 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;
            }
        }

        , _startAutoRefresh: function () {
            try {
                if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                    clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                    this.options.MYREFERENCES.autoRefresh.toid = null;
                }

                this.options.MYREFERENCES.autoRefresh.enabled = true;

                this._autoRefresh();
            } catch (Error) { }
        }

        , _autoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }

            this.refresh();

            if (this.options.MYREFERENCES.autoRefresh.enabled == true) {
                this.options.MYREFERENCES.autoRefresh.toid = setTimeout(this._autoRefresh, 5000);
            }
        }

        , _stopAutoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }
            this.options.MYREFERENCES.autoRefresh.enabled = false;
        }

        , refresh: function () {
            try {
                this.model.get("shifts").fetch();
                this.model.get("noActivityPeriods").fetch(); 
            } catch (Error) { }
        }

        , 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
            var fndebounced_drawShiftsWeekOverviewBar = _.debounce(this.drawShiftsWeekOverviewBar, 500); 

            this.listenTo(this.model.get("shifts"), "change", fndebounced_drawShiftsWeekOverviewBar);
            this.listenTo(this.model.get("shifts"), "add", fndebounced_drawShiftsWeekOverviewBar);
            this.listenTo(this.model.get("shifts"), "remove", fndebounced_drawShiftsWeekOverviewBar);
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
        }

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

            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        }

        , closeSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                if (sview.close)
                    sview.close();

                if (sview.view && sview.view.close)
                    sview.view.close();
            });
        }

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

            this.showSubviews();
            this.bindEvents();
            this.$el.show();
        }

        , showSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.show();
            });
        }

        , hide: function () {
            this.options.state = app.view_states.hidden;

            this.hideSubviews();
            this._stopAutoRefresh();

            this.$el.hide();
            this.unbind();
            this.stopListening();
        }

        , hideSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.hide();
            });
        }

        , preRender: function () {
            app.models.subnavbar.setAll(false); 
            app.models.subnavbar.set("subnavbar", false);
        }

        , reRender: function () {
            this._startAutoRefresh();
        }
    });

    Shifts.Models.ShiftConfiguration = Backbone.Epoxy.Model.extend({
        defaults: {
            id: null,
            name: null,
            start: null,
            end: null,
            duration: null,

            weekdays: [],
            enabled: null, 
        }
        , initialize: function () {
            var opts = { loaded: false, };
            this.options = _.extend(this.options ? this.options : {}, opts);
        }
        , fetch: function (options) {
            var that = this;
            var opt = {
                data: {
                    id: this.get("id"), 
                }, 
            }; 

            options = _.extend(opt, options); 

            var QP = new QueryParameters();
            if (options && options.data) {
                if (options.data.id) QP.Add("Id", "INT", options.data.id);
            }

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.GetShiftConfiguration", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table.0")) {
                        var shiftData = data.Table[0];
                        var weekdaysData = data.Table1; 

                        var shiftConfiguration = _.extend({}, that.attributes, {
                            id: shiftData.Id,
                            name: shiftData.Name,
                            start: shiftData.Start,
                            end: shiftData.End,
                            duration: shiftData.Duration,
                            enabled: shiftData.Enabled, 

                            weekdays: _.invoke(_.pluck(weekdaysData, "WeekDay"), 'toString'),
                        });

                        that.options.loaded = true;
                        that.set(shiftConfiguration, { from: "fetch" });
                    }
                },
                Async: true,
                Secured: true
            }, app.ConnectionStrings.app);
        }
        , save: function (success, error) {
            var that = this;

            var QP = new QueryParameters();

            var params = [
                ["@Id", "INT", "id"],
                ["@Name", "VARCHAR", "name"],
                ["@Start", "VARCHAR", "start"],
                ["@Duration", "INT", "duration"],
            ];

            for (var i = 0, len = params.length; i < len; i++) {
                var param = params[i];
                QP.Add(param[0], param[1], this.get(param[2]));
            }

            QP.Add("WeekDays", "VARCHAR", this.get("weekdays").join(','));
            QP.Add("Timezone", "CHAR", app.models.user.get("timezoneCode"));

            Core.Json.CallProcedure(app.DatabaseNames.IHDelays + ".WebApp.UpdateShiftConfiguration", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        if (success != null && _.isFunction(success))
                            success.call(this, that, data);
                    } else {
                        if (error != null && _.isFunction(error))
                            error.call(this, that, data); 
                    }
                },
                onError: function (data) {
                    if (error != null && _.isFunction(error))
                        error.call(this, that, data);
                }, 
                Async: true,
                Secured: true
            }, app.ConnectionStrings.app);
        },
    });

    Shifts.Views.ShiftConfiguration = Backbone.Epoxy.View.extend({
        template: "shifts"
        , id: "shifts"
        , title: "Shifts"
        //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
        , bindings: "data-bind"
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            this.options.MYREFERENCES = {
                autoRefresh: {
                    enabled: true
                    , toid: null
                }
            };

            this.options.MYREFERENCES.subviews = {};

            this.bindEvents();
            //_.bindAll(this);
        },

        events: {
        },

        render: function (container, viewParams) {
            var that = this;
            var thatContainer = this.options.container;

            //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/IHDelaysConfiguration/shifts/";

            if (this.model.options.loaded) {
                if (this.model.get("enabled")) {
                    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
                            if (!that.options.i18n[that.template])
                                that.options.i18n[that.template] = i18nJED;

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

                            that.applyBindings();

                            var timepicker_opts = {
                                template: false
                                , minuteStep: 1
                                , secondStep: 1
                                , showSeconds: false
                                , defaultTime: false
                                , showMeridian: false
                            };

                            that.options.fromTimePicker = that.$el.find(".from-timepicker").timepicker(timepicker_opts);
                            if (that.model.get("start")) that.options.fromTimePicker.timepicker('setTime', that.model.get("start"));
                            //that.options.fromTimePicker.timepicker().on("changeTime.timepicker",_.bind(that.timeChanged, that));
                            that.options.fromTimePicker.timepicker().on("blur", _.bind(that.timeChanged, that));

                            //appending view to the main container
                            that.append(thatContainer, that.$el);

                            //end:

                        }, true, customPath);
                    }, customPath, "shift_configuration");
                } else {
                    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
                            if (!that.options.i18n[that.template])
                                that.options.i18n[that.template] = i18nJED;

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

                            //appending view to the main container
                            that.append(thatContainer, that.$el);

                            //end:
                        }, true, customPath);
                    }, customPath, "disabled_shift_configuration");
                }
            } else {
                setTimeout(function () {
                    if (!that.model.options.loaded) {
                        that.$el.html('<div style="text-align:center;margin-top:10px;"><i class="fa fa-5x fa-cog fa-spin"></i><br /></div>');
                        that.append(thatContainer, that.$el);
                    }
                }, 300);
            }
        }

        , timeChanged: function () {
            var newTime = this.options.fromTimePicker.data("timepicker").getFormattedTime("24");
            this.model.set("start", newTime); 
        }

        , 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;
            }
        }

        , reRender: function (viewParams) {
            try {
            } catch (Error) { }
        }

        , refresh: function (viewParams) {
        }

        , checkRender: function (a, b, c) {
            var fromFetch = (b && b.from == "fetch") ? true : false;
            if (fromFetch) {
                this.render();
            }
        }

        , saveData: function (a, b, c) {
            var that = this;
            var fromFetch = (b && b.from == "fetch") ? true : false;

            var error_handler = function (a, b) {
                var error = {
                    type: (b && b.ErrorType) ? b.ErrorType.toUpperCase() : "UNKNOWN",
                    message: (b && b.Message) ? b.Message : "UNKNOWN",
                };

                var error_message = "";
                switch (error.message) {
                    case "UNIQUE_KEY_NAME_ERROR":
                        error_message = app.translate(that, "UNIQUE_KEY_NAME_ERROR");
                        break;
                    default:
                        error_message = app.translate(app, "DEFAULT_CATALOG_ERROR_MESSAGE");
                        break;
                }

                app.views.topMessages.showMessage(error_message);
                that.model.fetch(); 
            };
            
            if (!fromFetch) {
                this.model.save(
                    function () {
                        that.options.parent._autoRefresh();
                    }, 
                    error_handler
                );
            }
        }

        , 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.model, "change", this.checkRender);
            this.listenTo(this.model, "change", _.debounce(this.saveData, 200)); 
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
        }

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

            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        }

        , closeSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.close();
            });
        }

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

            this.showSubviews();
            this.bindEvents();
            this.$el.show();
        }

        , showSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.show();
            });
        }

        , resetModel: function () {
            this.model.set(this.model.defaults);
        }

        , hide: function () {
            this.options.state = app.view_states.hidden;

            this.resetModel();
            this.hideSubviews();

            this.$el.hide();
            this.unbind();
            this.stopListening();
        }

        , hideSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.hide();
            });
        }

        , preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("dateTimeScopeControl", false);
            app.models.subnavbar.set("sections", "4-4-4");
            app.models.subnavbar.set("subnavbar", true);
        }
    });

    Shifts.Views.AddNoActivityPeriodModal = Backbone.View.extend({
        template: "shifts"
        , id: "shifts"
        , title: ""
        , className: "modal hide fade modal-wider"
        //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: true
        , initialize: function () {

            this.options.MYREFERENCES = {
                autoRefresh: {
                    enabled: true
                    , toid: null
                },
                rowData: null,
            };

            if (this.options.viewParams) {
                this.options.MYREFERENCES.rowData = this.options.viewParams.rowData;
            }

            this.options.singleDay = (this.options.singleDay) ? this.options.singleDay : false; 

            this.options.viewModels = {
                fromDateControl: new DateControl.Model({
                    //date: ,
                }),
                toDateControl: new DateControl.Model({
                    //date: ,
                }),
            }; 

            this.options._isRendered = false;

            //this.model = new Delays1.Models.DelaySplitInformationModal();

            this.bindEvents();
            _.bindAll(this);
        },
        events: {
            'click .close': function (event) {
                event.preventDefault();

                this.trigger('cancel');

                if (this.options.content && this.options.content.trigger) {
                    this.options.content.trigger('cancel', this);
                }
            }
            , "click .btn-cancel": function (event) {
                event.preventDefault();

                this.trigger('cancel');

                if (this.options.content && this.options.content.trigger) {
                    this.options.content.trigger('cancel', this);
                }
            }
        },

        render: function (container) {
            var that = this;
            var thatContainer = container;

            //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/IHDelaysConfiguration/shifts/";

            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;

                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp({
                        singleDay: that.options.singleDay,
                    }));

                    var dc = new DateControl.Views.Main({ model: that.options.viewModels.fromDateControl });
                    dc.render(that.$el.find(".from-date-control-container"));

                    if (!that.options.singleDay) {
                        var dc = new DateControl.Views.Main({ model: that.options.viewModels.toDateControl });
                        dc.render(that.$el.find(".to-date-control-container"));
                    }

                }, true, customPath);

            }, customPath, "add_no_activity_period_modal");

            that.options._isRendered = true;
            that.refresh();
        }

        , refresh: function () {
            try {
                this.model.fetch(this.options.MYREFERENCES.rowData.id);
            } catch (Error) { }
        }

        , _startAutoRefresh: function () {
            try {
                if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                    clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                    this.options.MYREFERENCES.autoRefresh.toid = null;
                }

                this.options.MYREFERENCES.autoRefresh.enabled = true;

                this._autoRefresh();
            } catch (Error) { }
        }

        , _autoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }

            this.refresh();

            if (this.options.MYREFERENCES.autoRefresh.enabled == true) {
                this.options.MYREFERENCES.autoRefresh.toid = setTimeout(this._autoRefresh, 3000);
            }
        }

        , _stopAutoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }
            this.options.MYREFERENCES.autoRefresh.enabled = false;
        }
        , show: function () {

            if (!this.options._isRendered) {
                this.render();
                setTimeout(this.show, 100);
                return;
            }

            var self = this,
            $el = this.$el;

            //creating modal
            $el.modal({
                keyboard: false
                , backdrop: "static"
            });

            $backdrop = $('.modal-backdrop');

            $backdrop.one('click', function () {
                if (self.options.content && self.options.content.trigger) {
                    self.options.content.trigger('cancel', self);
                }

                self.trigger('cancel');
            });

            $(document).one('keyup.dismiss.modal', function (e) {
                e.which == 27 && self.trigger('cancel');

                if (self.options.content && self.options.content.trigger) {
                    e.which == 27 && self.options.content.trigger('shown', self);
                }
            });

            this.on('cancel', function () {
                self.hide();
            });

            return this;

        }
        , hide: function () {
            var self = this,
            $el = this.$el;

            $el.one('hidden', function onHidden(e) {
                // Ignore events propagated from interior objects, like bootstrap tooltips
                if (e.target !== e.currentTarget) {
                    return $el.one('hidden', onHidden);
                }

                if (self.options.content && self.options.content.trigger) {
                    self.options.content.trigger('hidden', self);
                }

                self.trigger('hidden');

                self.close();
            });

            $el.modal('hide');
        }
        , 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

            //rendering as soon as getting data in the model
            //this.listenTo(this.model, "change", this.render);
        }

        , close: function () {
            this._stopAutoRefresh();
            this.remove();
            this.unbind();
        }

        , preRender: function () {
        }

        , reRender: function () {
        }
    });

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

});
