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

  "Chart",

  "modules/modal", 
  "moment",
  "js/dashboard-assets/progressbar/progressbar",

  "modules/dateTimeControl",
  "modules/dateControl",

  "js/dashboard-assets/chartjs/Chart.StackedBar",
],

function (app, T, Backgrid, Chart, Modal, moment, ProgressBar, DateTimeControl, DateControl) {

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

    Delays3.Models.Main = Backbone.Model.extend({
        defaults: {
            delayCategoryStacksInfo: null, 
            delayCategoryStacks: null,
            categories: null,
            timeAccounts: null,


            //
        },
        initialize: function () {
            this.attributes.delayCategoryStacksInfo = new Delays3.Collections.DelayCategoryStacksInfo(); 
            this.attributes.delayCategoryStacks = new Delays3.Collections.DelayCategoryStacks();
            this.attributes.categories = new Delays3.Collections.Categories();
            this.attributes.timeAccounts = new Delays3.Collections.TimeAccounts(); 
        },
        fetch: function (opt) {
            var that = this; 
            var options = {
                method: "set",
                async: true,
                callback: null,
                params: [],
            };

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

            try{
                var QP = new Core.Database.QueryParameters();

                _.each(options.params, function (p) {
                    try {
                        QP.Add(p["Name"], p["Type"], p["Value"]);
                    } catch (Error) { }
                });

                QP.Add("Timezone", "CHAR", app.models.user.get("timezoneCode"));

                var delayCategoriesStackedItems = [];
                var delayCategoriesStackedInfoItems = [];
                var categoriesItems = [
                    {
                        id: null,
                        name: "NOTDECLARED",
                        description: "Not Declared",
                        color: '#f84e4e',
                    }, 
                ];

                Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetDelayCategoriesStacked", QP, {
                    onSuccess: function (data) {
                        var delayCategoriesStackedInfo = data.Table; 
                        var delayCategoriesStackedData = data.Table1; 
                        var categoriesData = data.Table2;

                        for (var i = 0; i < categoriesData.length; i++) {
                            var itemData = categoriesData[i];
                            var item = {
                                id: itemData.Id,
                                name: itemData.Name,
                                description: itemData.Description,
                                color: itemData.Color,
                            };

                            categoriesItems.push(item); 
                        }

                        for (var i = 0; i < delayCategoriesStackedData.length; i++) {
                            var itemData = delayCategoriesStackedData[i];
                            var item = {
                                id: itemData.Timestamp.toString() + '&' + ((itemData.CategoryId) ? itemData.CategoryId.toString() : "ND"),
                                timestamp: itemData.Timestamp,
                                categoryId: itemData.CategoryId,
                                name: itemData.Category,
                                duration: (_.isNumber(itemData.Duration)) ? Math.round(itemData.Duration * 100) / 100 : 0,
                            };

                            delayCategoriesStackedItems.push(item);
                        }

                        for (var i = 0; i < delayCategoriesStackedInfo.length; i++) {
                            var itemData = delayCategoriesStackedInfo[i];
                            var item = {
                                timestamp: itemData.Timestamp.toString(),
                                totalseconds: new moment.duration(itemData.TotalSeconds, 'seconds'),
                            };

                            delayCategoriesStackedInfoItems.push(item);
                        }

                        that.get("categories")[options.method](categoriesItems, { from: "fetch" });
                        that.get("delayCategoryStacksInfo")[options.method](delayCategoriesStackedInfoItems, { from: "fetch" });
                        that.get("delayCategoryStacks")[options.method](delayCategoriesStackedItems, { from: "fetch" });

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

            } catch (Error) {
                if (options.callback != null && _.isFunction(options.callback))
                    options.callback.call(this, that);
            }

            return this;
        }, 
    });

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

    Delays3.Models.Category = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
            description: null,
            color: null, 
        }, 
    });

    Delays3.Collections.Categories = Backbone.Collection.extend({
        model: Delays3.Models.Category, 
    }); 

    Delays3.Models.DelayCategoryStackInfo = Backbone.Model.extend({
        defaults: {
            timestamp: null,
            totalseconds: null, 
        }, 
    }); 

    Delays3.Models.DelayCategoryStack = Backbone.Model.extend({
        defaults: {
            timestamp: null,
            id: null,
            categoryId: null, 
            name: null,
            duration: null, 
        },
    });

    Delays3.Collections.DelayCategoryStacks = Backbone.Collection.extend({
        model: Delays3.Models.DelayCategoryStack,
        comparator: 'timestamp', 
    }); 

    Delays3.Collections.DelayCategoryStacksInfo = Backbone.Collection.extend({
        model: Delays3.Models.DelayCategoryStackInfo,
        comparator: 'timestamp',
    });

    Delays3.Models.TimeAccount = Backbone.Model.extend({
        defaults: {
            id: null,
            code: null,
            category: null,
            description: null,
            color: null,
            duration: null,
            isTotal: false, 
            lastUpdate: 0,
        }
    });

    Delays3.Collections.TimeAccounts = Backbone.Collection.extend({
        model: Delays3.Models.TimeAccount,

        initialize: function () {
            this.refreshCount = 0;
            this.totalDuration = 0; 
        },
        fetch: function (opt) {
            var that = this; 
            var options = {
                method: "set",
                async: true,
                callback: null,
                params: [],
            };

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

            try {
                var QP = new Core.Database.QueryParameters();

                _.each(options.params, function (p) {
                    try {
                        QP.Add(p["Name"], p["Type"], p["Value"]);
                    } catch (Error) { }
                });

                QP.Add("Timezone", "CHAR", app.models.user.get("timezoneCode"));

                var timeAccountItems = [];

                Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetDelaysTimeSummary", QP, {
                    onSuccess: function (data) {
                        var timeAccountsData = data.Table;

                        for (var i = 0; i < timeAccountsData.length; i++) {
                            var itemData = timeAccountsData[i];
                            var item = {
                                id: itemData.Id,
                                code: itemData.Code,
                                category: itemData.Category,
                                description: itemData.Description,
                                color: itemData.Color,
                                duration: itemData.Duration,
                            };

                            timeAccountItems.push(item);
                        }

                        var totalDuration = _.reduce(timeAccountItems, function (memo, m) {
                            return memo + m.duration; 
                        }, 0);

                        timeAccountItems.push({
                            id: -2,
                            code: 'Total',
                            category: '',
                            description: '',
                            color: '',
                            duration: totalDuration,
                            isTotal: true,
                            lastUpdate: ++that.refreshCount,
                        });

                        timeAccountItems.sort(function (modelA, modelB) {
                            var a = modelA,
                                b = modelB;

                            if (a["isTotal"]) {
                                return 1;
                            }
                            if (b["isTotal"]) {
                                return -1;
                            }
                            else {
                                if (a["duration"] > b["duration"])
                                    return -1;
                                else if (a["duration"] < b["duration"])
                                    return 1;
                                else
                                    return 0;
                            }
                        }); 

                        var totalDuration_prev = that.totalDuration;
                        that.totalDuration = totalDuration;

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

                        if (that.totalDuration != totalDuration_prev)
                            that.trigger("totalDurationChanged", this);

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

            return this;
        },
    });

    Delays3.Views.Main = Backbone.View.extend({
        template: "delays-3"
        , id: "delays-3"
        , title: ""
        //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
        , 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.autorefresh = {
                enabled: true
                , toid: null
            }; 

            this.options.delaysCategoriesStackedChart = {
                chart: null,
                data: null, 
            }; 

            this.options.delaysTimeSummaryGrid = {
                grid: null,
                model: null, 
            }; 

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

            this.model = model;

            this.options.subviews = {}; 

            this.options.subviews.subnavbarControls = new Delays3.Views.SubnavBarControls({
                parent: this
                , model: new Delays3.Models.SubnavBarControls()
                , container: app.views.subnavbar.getSectionContainer(1, 12)
            });

            this.options.subviews.subnavbarControls.render();

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

        events: {
        }, 

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

            //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.oeeModule.screensPath + "delays/delays-3/";

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

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

                    //end

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

                    that.drawDelaysTimeSummary(); 

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

        , drawDelaysTimeSummary: function () {
            var that = this;

            //var modelTotal = that.model.get("timeAccounts").findWhere({ isTotal: true, });
            //var opt = {
            //    total: (modelTotal) ? modelTotal.get("duration") : that.model.get("timeAccounts").reduce(function (memo, m) {
            //        return ((!m.get("isTotal")) ? m.get("duration") : 0) + memo;
            //    }, 0), 
            //};
            var opt = { total: 0, }; 
            opt.total = that.model.get("timeAccounts").totalDuration;

            //timeAccounts.forEach(function (m) { opt.total += m.get("duration"); });
            //timeAccounts.add({ name: "Staffed Time", duration: opt.total, color: '#ccc' }); 

            var columns = [
                {
                    name: "code",
                    label: app.translate(that, "name_label"),
                    editable: false,
                    sortable: false,
                    formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
                        fromRaw: function (rawValue, model) {
                            return (rawValue) ? app.translate(that, rawValue) : rawValue;
                        }
                    }), 
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell",
                    })
                },
                {
                    name: "category",
                    label: app.translate(that, "category_label"),
                    editable: false,
                    sortable: false,
                    formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
                        fromRaw: function (rawValue, model) {
                            return (rawValue) ? app.translate(that, rawValue) : rawValue;
                        }
                    }),
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell",
                    })
                },
                {
                    name: "duration",
                    label: app.translate(that, "duration_label"),
                    editable: false,
                    sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell",
                        render: function () {
                            this.$el.html(this.secondsToHHMMSS(this.model.get("duration")));
                            this.delegateEvents();
                            return this;
                        },
                        secondsToHHMMSS: function (d) {
                            d = Number(d);
                            var h = Math.floor(d / 3600);
                            var m = Math.floor(d % 3600 / 60);
                            var s = Math.floor(d % 3600 % 60);
                            return ((h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s);
                        },
                    })
                },
                {
                    name: "graph",
                    label: app.translate(that, "graph_label"),
                    editable: false,
                    sortable: false,
                    cell: Backgrid.StringCell.extend({
                        template: _.template("<div style='height:20px;width:200px;position:relative;' class='bar-graph-container'></div>"),
                        orderSeparator: '',
                        className: "string-cell",
                        initialize: function () {
                            _.bindAll(this);
                            Backgrid.StringCell.prototype.initialize.apply(this, arguments);

                            this.options.graph = {
                                pbar: null,
                            };

                            this.bindEvents();
                        },
                        render: function () {
                            //var modelTotal = that.model.get("timeAccounts").findWhere({ isTotal: true, });
                            //opt.total = (modelTotal) ? modelTotal.get("duration") : that.model.get("timeAccounts").reduce(function (memo, m) {
                            //    return ((!m.get("isTotal")) ? m.get("duration") : 0) + memo;
                            //}, 0);

                            opt.total = that.model.get("timeAccounts").totalDuration; 

                            this.$el.html(this.template());
                            var pbar_container = this.$el.find(".bar-graph-container");

                            if (this.model.get("isTotal") == false) {
                                var val = this.model.get("duration");

                                var pbar = this.options.graph.pbar = new ProgressBar.Line(pbar_container.get(0), {
                                    color: this.model.get("color"),
                                    trailColor: 'transparent',
                                    easing: 'easeInOut',
                                    step: function (state, bar) {
                                    }
                                });

                                pbar_container.find("svg").css({
                                    height: "20px",
                                    width: "100%",
                                    "overflow-y": "hidden",
                                });

                                setTimeout(function () {
                                    var percent = (opt.total != 0) ? that._getPercent(val, _.extend({}, opt, { displayMinimum: true })) : 0;
                                    pbar.animate(percent);
                                }, 1000);
                            }
                            else {
                                var that2 = this;
                                that2.options.graph.pbar = [];

                                that.model.get("timeAccounts").each(function (timeModel, imodel) {
                                    var val = timeModel.get("duration");

                                    var pbar = new ProgressBar.Line(pbar_container.get(0), {
                                        color: timeModel.get("color"),
                                        trailColor: 'transparent',
                                        easing: 'easeInOut',
                                        step: function (state, bar) {
                                        }
                                    });

                                    that2.options.graph.pbar.push(pbar);

                                    var percent = (opt.total != 0) ? (that._getPercent(val, opt) * 100) : 0; 
                                    $(pbar_container.find("svg")[imodel]).css({
                                        height: "20px",
                                        width: percent + "%",
                                        "overflow-y": "hidden",
                                        "float": "left",
                                    });

                                    setTimeout(function () {
                                        pbar.animate(1);
                                    }, 1000);
                                });
                            }

                            this.delegateEvents();
                            return this;
                        },
                        refresh: function () {
                            //var modelTotal = that.model.get("timeAccounts").findWhere({ isTotal: true, });
                            //opt.total = (modelTotal) ? modelTotal.get("duration") : that.model.get("timeAccounts").reduce(function (memo, m) {
                            //    return ((!m.get("isTotal")) ? m.get("duration") : 0) + memo;
                            //}, 0);

                            opt.total = that.model.get("timeAccounts").totalDuration;

                            if (this.model.get("isTotal") == false) {
                                var val = this.model.get("duration");
                                var percent = (opt.total != 0) ? that._getPercent(val, _.extend({}, opt, { displayMinimum: true })) : 0;
                                this.options.graph.pbar.animate(percent);
                            }
                            else {
                                var that2 = this;
                                var graphList = this.$el.find(".bar-graph-container").find("svg");

                                that.model.get("timeAccounts").each(function (timeModel, imodel) {
                                    var val = timeModel.get("duration");
                                    var percent = (opt.total != 0) ? (that._getPercent(val, opt) * 100) : 0; 
                                    $(graphList[imodel]).css({
                                        width: percent + "%",
                                    });
                                    that2.options.graph.pbar[imodel].animate(1);
                                });
                            }
                        },
                        refreshUpdate: function () {
                            //var modelTotal = that.model.get("timeAccounts").findWhere({ isTotal: true, });
                            //opt.total = (modelTotal) ? modelTotal.get("duration") : that.model.get("timeAccounts").reduce(function (memo, m) {
                            //    return ((!m.get("isTotal")) ? m.get("duration") : 0) + memo;
                            //}, 0);

                            opt.total = that.model.get("timeAccounts").totalDuration;

                            if (this.model.get("isTotal") == true) {
                                var that2 = this;
                                var graphList = this.$el.find(".bar-graph-container").find("svg");

                                that.model.get("timeAccounts").each(function (timeModel, imodel) {
                                    var val = timeModel.get("duration");
                                    var percent = (opt.total != 0) ? (that._getPercent(val, opt) * 100) : 0; 
                                    $(graphList[imodel]).css({
                                        width: percent + "%",
                                    });

                                    setTimeout(function () {
                                        that2.options.graph.pbar[imodel].animate(1);
                                    }, 1000);

                                });
                            }
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change", _.debounce(_.bind(this.refresh, this), 500));
                            this.listenTo(that.model.get("timeAccounts"), "totalDurationChanged", _.debounce(_.bind(this.refresh, this), 500));
                            this.listenTo(this.model, "change:lastUpdate", _.debounce(_.bind(this.refreshUpdate, this), 500));
                        },
                    })
                },
            ];

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

            this.options.delaysTimeSummaryGrid.grid = grid;

            this.$el.find(".time-summary-grid-container").append(grid.render().el);
        }

        , _getPercent: function (val, opt) {
            var p = (((val * 100) / opt.total) / 100); 
            var final = Math.floor(p * 100) / 100;

            return (final == 0 && p != 0 && (opt && opt.displayMinimum)) ? 0.01 : final; 
        }

        , drawDelaysChart: function (a, b, c) {
            var that = this; 
            //var delayCategoryStacks = new Delays3.Collections.DelayCategoryStacks(this.model.get("delayCategoryStacks").sortBy(function (m) {
            //    return m.get("timestamp"); 
            //}));
            var delayCategoryStacks = this.model.get("delayCategoryStacks"); 
            var delayCategoryStacksInfo = this.model.get("delayCategoryStacksInfo"); 

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

            var labels = _.uniq(delayCategoryStacks.pluck("timestamp"));  
            //var labels = delayCategoryStacksInfo.map(function (m) {
            //    return m.get("timestamp") + " - " + m.get("totalseconds").asHours() + " hours"; 
            //});

            var chartData = {
                labels: labels,
                datasets: [], 
            };

            var codes = _.uniq(categories.pluck("id"));

            var datasets = []; 
            
            _.each(codes, function (c) {
                var cat = categories.findWhere({ id: c }); 
                var dset = {
                    categoryId: c, 
                    label: app.translate(that, cat.get("name")),
                    fillColor: cat.get("color"),
                    //strokeColor: "#D6D6D6",
                    highlightFill: cat.get("color"),
                    //highlightStroke: "#D6D6D6",
                    data: Array.apply(null, Array(labels.length)).map(Number.prototype.valueOf, 0),
                };

                var whereCode = delayCategoryStacks.where({ categoryId: c });
                _.each(whereCode, function (m) {
                    dset.data[_.indexOf(labels, m.get("timestamp"))] = m.get("duration");
                });

                datasets.push(dset); 
            }); 

            chartData.datasets = datasets;

            if (!this.options.delaysCategoriesStackedChart.chart) {
                this.instanceChart(chartData);
            } else {
                this.updateChart(chartData); 
            }
        }

        , instanceChart: function (chartData) {
            var container = this.$el.find(".delays-chart-container");

            if (this.options.delaysCategoriesStackedChart.chart != null) {
                this.options.delaysCategoriesStackedChart.chart.destroy();
                this.options.delaysCategoriesStackedChart.data = null;
                container.empty();
            }
            
            var cnv = $("<canvas></canvas>");
            cnv.width(container.width()).height(300);
            cnv.bind("mousemove touchstart touchmove", this.delaysChart_mouseMove);
            container.append(cnv);

            var ctx = cnv.get(0).getContext("2d");

            this.options.delaysCategoriesStackedChart.data = chartData;
            this.options.delaysCategoriesStackedChart.chart = new Chart(ctx).StackedBar(chartData, {
                responsive: true,
                tooltipHideZero: true,
                scaleOverride: true,
                scaleSteps: 10,
                scaleStepWidth: 10,
                scaleStartValue: 0,
                multiTooltipTemplate: "<%=datasetLabel%>: <%= value %> %",
            });
        }

        , updateChart: function (chartData) {
            var currentCategories = _.pluck(this.options.delaysCategoriesStackedChart.data.datasets, "categoryId").sort();
            var updatedCategories = _.pluck(chartData.datasets, "categoryId").sort();

            var currentLabels = this.options.delaysCategoriesStackedChart.data.labels.sort();
            var updatedLabels = chartData.labels.sort();

            var isEqual = _.isEqual(currentCategories, updatedCategories) && _.isEqual(currentLabels, updatedLabels); 

            if (isEqual) {
                _.each(this.options.delaysCategoriesStackedChart.data.datasets, function (m) {
                    var newData = _.findWhere(chartData.datasets, { categoryId: m.categoryId });
                    if (newData) {
                        _.extend(m.data, newData.data);
                    }
                });

                this.options.delaysCategoriesStackedChart.chart.update();
            } else {
                this.instanceChart(chartData); 
            }
        }

        , delaysChart_mouseMove: function (e) {
            var a = this.options.delaysCategoriesStackedChart.chart.getBarsAtEvent(e);
            var totaltspan = this.$el.find(".total-time-span");

            var text = "";
            if (a.length > 0) {
                var f = a[0];
                var timestamp = f.label;
                var m = this.model.get("delayCategoryStacksInfo").findWhere({ timestamp: timestamp }); 
                if (m) {
                    text = app.translate(this, "total_time") + ": ";
                    var d = Number(m.get("totalseconds").asSeconds());
                    var h = Math.floor(d / 3600);
                    var m = Math.floor(d % 3600 / 60);
                    var s = Math.floor(d % 3600 % 60);
                    text += ((h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s);
                }
            }

            totaltspan.text(text);
        }

        , 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;
            }
        }
        , refresh: function (opt) {
            try {
                var that = this;

                var lineId = this.options.subviews.subnavbarControls.model.get("lineProductionItemId");
                var machineId = this.options.subviews.subnavbarControls.model.get("machineProductionItemId");
                var productionItemIdFilter = (lineId != -1) ? (machineId != -1) ? machineId : lineId : (machineId != -1) ? machineId : null;

                var from = this.options.subviews.subnavbarControls.model.get("from");
                var to = this.options.subviews.subnavbarControls.model.get("to"); 

                var productId = this.options.subviews.subnavbarControls.model.get("productId");
                productId = (productId != -1) ? productId : null; 

                var shiftId = this.options.subviews.subnavbarControls.model.get("shiftId");
                shiftId = (shiftId != -1) ? shiftId : null; 

                var fromMoment = moment(from);
                var toMoment = moment(to); 
                toMoment.add(1, "d"); 

                var fetchCounts = 2; 

                var afterFetch = _.after(fetchCounts, function () {
                    if (opt && opt.callback && _.isFunction(opt.callback))
                        opt.callback.call(that, that);
                });

                this.model.fetch({
                    params: [
                        { Name: "From", Type: "DATETIME", Value: fromMoment.format("YYYY-MM-DD HH:mm:ss") },
                        { Name: "To", Type: "DATETIME", Value: toMoment.format("YYYY-MM-DD HH:mm:ss") },
                        { Name: "ProductionItemId", Type: "INT", Value: productionItemIdFilter },
                        { Name: "ProductId", Type: "INT", Value: productId },
                        { Name: "ShiftId", Type: "INT", Value: shiftId },
                    ],
                    callback: afterFetch, 
                });

                this.model.get("timeAccounts").fetch({
                    method: opt && _.isBoolean(opt.reset) && opt.reset == true ? "reset" : "set", 
                    params: [
                        { Name: "From", Type: "DATETIME", Value: fromMoment.format("YYYY-MM-DD HH:mm:ss") },
                        { Name: "To", Type: "DATETIME", Value: toMoment.format("YYYY-MM-DD HH:mm:ss") },
                        { Name: "ProductionItemId", Type: "INT", Value: productionItemIdFilter },
                        { Name: "ProductId", Type: "INT", Value: productId },
                        { Name: "ShiftId", Type: "INT", Value: shiftId },
                    ],
                    callback: afterFetch,
                });

            } catch (Error) { }
        }
        , _startAutoRefresh: function (opt) {
            try {
                if (this.options.autorefresh.toid != null) {
                    clearTimeout(this.options.autorefresh.toid);
                    this.options.autorefresh.toid = null;
                }

                this.options.autorefresh.enabled = true;

                this._autoRefresh(opt);
            } catch (Error) { }
        }
        , _autoRefresh: function (opt) {
            var that = this;
            var fetched = false;

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

            if (opt && opt.showLoading) {
                setTimeout(function () {
                    if (!fetched) that.showLoading(true);
                }, 1);
            }

            this.refresh(_.extend({}, opt, {
                callback: function () {
                    fetched = true;
                    that.showLoading(false);

                    if (that.options.autorefresh.enabled == true) {
                        that.options.autorefresh.toid = setTimeout(that._autoRefresh, 5000);
                    }

                    if (opt && opt.callback && _.isFunction(opt.callback))
                        opt.callback.call(that, that);
                },
            }));
        }
        , showLoading: function (val) {
            var loadingPoster = this.$el.find(".loading-poster");
            var mainContent = this.$el.find(".main-content");

            if (val) {
                mainContent.addClass("hide");
                loadingPoster.removeClass("hide");
            } else {
                loadingPoster.addClass("hide");
                mainContent.removeClass("hide");
            }
        }
        , _stopAutoRefresh: function () {
            if (this.options.autorefresh.toid != null) {
                clearTimeout(this.options.autorefresh.toid);
                this.options.autorefresh.toid = null;
            }
            this.options.autorefresh.enabled = false;
        }
        , filtersChanged: _.debounce(function (a, b, c) {
            this._autoRefresh({ showLoading: true, reset: true, });
        }, 500)
        , 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 drawDelaysChart_debounced = _.debounce(_.bind(this.drawDelaysChart, this), 500); 

            this.listenTo(this.model.get("delayCategoryStacks"), "change", drawDelaysChart_debounced);
            this.listenTo(this.model.get("delayCategoryStacks"), "add", drawDelaysChart_debounced);
            this.listenTo(this.model.get("delayCategoryStacks"), "remove", drawDelaysChart_debounced);

            this.listenTo(this.options.subviews.subnavbarControls.model, "change:from", this.filtersChanged);
            this.listenTo(this.options.subviews.subnavbarControls.model, "change:to", this.filtersChanged);
            this.listenTo(this.options.subviews.subnavbarControls.model, "change:lineProductionItemId", this.filtersChanged);
            this.listenTo(this.options.subviews.subnavbarControls.model, "change:machineProductionItemId", this.filtersChanged);
            this.listenTo(this.options.subviews.subnavbarControls.model, "change:productId", this.filtersChanged);
            this.listenTo(this.options.subviews.subnavbarControls.model, "change:shiftId", this.filtersChanged);
        }

        , bindViewScopedEvents: function () {
            var that = this;
        }

        , unbindViewScopedEvents: function () {
            this._stopAutoRefresh(); 
        }

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

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

        , closeSubviews: function () {
            _.each(this.options.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.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.subviews, function (sview) {
                sview.hide();
            });
        }

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

        , reRender: function () {
        }
    });

    Delays3.Models.SubnavBarControls = Backbone.Epoxy.Model.extend({
        defaults: {
            from: null,
            to: null,

            lineProductionItemId: -1,
            machineProductionItemId: -1,
            productId: -1,
            shiftId: -1, 

            lines: [],
            machinesInternal: [],
            products: [],
            shifts: [], 
        },
        computeds: {
            machines: {
                deps: ["lineProductionItemId"],
                get: function () {
                    var line = this.get("lineProductionItemId");
                    var machines = this.get("machinesInternal");

                    return _.map(_.filter(machines, function (m) {
                        if (line != -1) return m.ParentId == line;
                        else return true;
                    }), function (m) {
                        return { value: m.Id, label: m.Name, };
                    });
                },
            }
        },
        initialize: function () {
            var from = moment();
            var to = moment(from);
            //var to = moment(from).add("d", 1); 

            this.set({
                from: from.format("YYYY-MM-DD"),
                to: to.format("YYYY-MM-DD"),
            }, { silent: true });

            this.fetchLinesMachines();
            this.fetchProducts();
            this.fetchShifts(); 
        },
        fetchLinesMachines: function (from, to) {
            var that = this;

            from = (!_.isString(from)) ? this.get("from") : from;
            to = (!_.isString(to)) ? this.get("to") : to;

            var QP = new Core.Database.QueryParameters();
            QP.Add("From", "DATETIME", from);
            QP.Add("To", "DATETIME", to);
            QP.Add("Timezone", "VARCHAR", app.models.user.get("timezoneCode"));

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetProductionItems", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var items = data.Table;

                        that.set({
                            lines: _.map(_.filter(items, function (m) { return m.ProductionItemType.toUpperCase() == "LINE"; }), function (m) {
                                return { value: m.Id, label: m.Name, };
                            }),
                            machinesInternal: _.filter(items, function (m) { return m.ProductionItemType.toUpperCase() == "MACHINE"; }),
                        });
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        fetchProducts: function () {
            var that = this;
            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetProducts", null, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var items = data.Table;

                        that.set({
                            products: _.map(items, function (m) {
                                return { value: m.Id, label: m.Name, };
                            }),
                        });
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        fetchShifts: function () {
            var that = this;
            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetShifts", null, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var items = data.Table;

                        that.set({
                            shifts: _.map(items, function (m) {
                                return { value: m.Id, label: m.Name, };
                            }),
                        });
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
    });

    //subview for the subnavbar controls
    Delays3.Views.SubnavBarControls = Backbone.Epoxy.View.extend({
        id: "delays-3-subnavbar-controls"
        , title: ""
        , template: "delays-3"
        , 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 = {};

            this.options.viewModels = {
                fromDateControl: new DateControl.Model({
                    date: this.model.get("from"),
                }),
                toDateControl: new DateControl.Model({
                    date: this.model.get("to"),
                }),
            };

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

        events: {
        },

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

            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = app.oeeModule.screensPath + "delays/delays-3/";

            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());
                    that.applyBindings();

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

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

                    that.append(thatContainer, that.$el);
                }, true, customPath);
            }, customPath, "subnavbar_controls");
        }

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

        , refresh: function () {
            try {

            } 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

            this.listenTo(this.options.viewModels.fromDateControl, "change:date", this.fromToModelChanged);
            this.listenTo(this.options.viewModels.toDateControl, "change:date", this.fromToModelChanged);
        }

        , fromToModelChanged: function (a, b, c) {
            this.model.set({
                from: this.options.viewModels.fromDateControl.get("date"),
                to: this.options.viewModels.toDateControl.get("date"),
            });

            this.model.fetchLinesMachines(); 
        }

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

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

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

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

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

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

        , reRender: function () {
        }
    });

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

});
