/// <reference path="http://localhost:65492/IndustrialDashboard/Scripts/IndustrialDashboard-debug.js" />
//SCREEN-BOILERPLATE

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

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

  //templates-loader: this loads templates async.
  "js/templates-loader",

  "modules/modal",

  "backgrid",

  "js/dashboard-assets/progressbar/progressbar",

  "Chart",

  "modules/dateControl",

  "moment",

  "oee-module-screens/delays/delay-information-modal/delay-information-modal",

  "handlebars", 

  "js/dashboard-assets/chartjs/Chart.Scatter",
  "oee-module-assets/dashboard-assets/jquery-circle-progress/circle-progress",
  "js/perfect-scrollbar/js/perfect-scrollbar.jquery",
  "js/jquery.floatThead/jquery.floatThead",
],

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

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

    OEEBatch.Models.ItemCategory = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
            color: null,
        },
    });

    OEEBatch.Collections.ItemCategories = Backbone.Collection.extend({
        model: OEEBatch.Models.ItemCategory,
    });

    OEEBatch.Models.ProgressItem = Backbone.Model.extend({
        defaults: {
            duration: null,
            category: null,
            start: null,
            end: null,

            //optional
            delayId: null, 
        },
    });
    
    OEEBatch.Collections.ProgressItems = Backbone.Collection.extend({
        model: OEEBatch.Models.ProgressItem,
    });

    OEEBatch.Models.MixedDetail = Backbone.Model.extend({
        defaults: {
            start: null, 
            end: null, 
            type: null, 
            delayCodeId: null, 
            duration: null, 
        }
    });

    OEEBatch.Collections.MixedDetails = Backbone.Collection.extend({
        model: OEEBatch.Models.MixedDetail, 
    }); 

    OEEBatch.Models.Main = Backbone.Epoxy.Model.extend({
        defaults: {
            from: null,
            to: null,
            batches: null,
            lineProductionItemIdFilter: null, 

            batchId: null,
            batchNumber: null,
            start: null,
            end: null, 
            lineProductionItemId: null,
            line: null,
            mpid: null,
            machine: null,
            product: null,

            oee: null,
            availability: null,
            quality: null,
            performance: null,

            targetQty: null,
            goodQty: null,
            badQty: null,
            totalQty: null,
            ratedQty: null,
            activeSeconds: null,
            productionSeconds: null, 

            events: null,
            delayCodes: null,
            timeAccounts: null,
            series: null,
            mixedDetails: null, 

            //behind the scenes
            machines: [],
            lines: [], 
        },
        computeds: {
            machineProductionItemId: {
                get: function () {
                    return this.get("mpid");
                },
                set: function (val) {
                    return {
                        mpid: (val != -1) ? parseInt(val) : null
                    };
                }, 
            }
        }, 
        initialize: function () {
            this.attributes.batches = new OEEBatch.Collections.Batches();

            this.attributes.to = new moment();
            this.attributes.from = new moment(this.attributes.to).subtract(1, 'week');

            this.attributes.delayCodes = new OEEBatch.Collections.DelayCodes();
            this.attributes.events = new OEEBatch.Collections.Events();
            this.attributes.timeAccounts = new OEEBatch.Collections.TimeAccounts(); 
            this.attributes.series = new OEEBatch.Collections.OEEChartSeries(); 
            this.attributes.mixedDetails = new OEEBatch.Collections.MixedDetails(); 

            this.options = {
                transaction_timestamp: null,
            };

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

            from = (!_.isString(from)) ? this.get("from").format("YYYY-MM-DD") : from;
            to = (!_.isString(to)) ? this.get("to").format("YYYY-MM-DD") : 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, };
                            }),
                        });
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        fetchHistoricalBatch: function (batchId, productionItemId, 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("BatchId", "INT", batchId);

                console.log("batchId: " + batchId);

                QP.Add("ProductionItemId", "INT", productionItemId);
                QP.Add("Points", "INT", 200);

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

                var tt = this.options.transaction_timestamp = new Date().getTime(); 
                console.log((new Date()).toString() + " Starting get historical batch")
                Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetHistoricalBatch", QP, {
                    onSuccess: function (data) {

                        console.log((new Date()).toString() + " end get historical batch")

                        if (that.options.transaction_timestamp != tt)
                            return; 

                        console.log((new Date()).toString() + " starting parse and set data")

                        var binfo = data.Table[0];
                        var oeeInfo = data.Table1[0];
                        var eventsInfo = data.Table2;
                        var timeAccountsInfo = data.Table3; 
                        var seriesInfo = data.Table4;

                        var machinesInfo = data.Table5; 
                        var delayCodesInfo = data.Table6;
                        var mixedDetailsInfo = data.Table7; 

                        var screenInfo = {
                            batchId: binfo.BatchId,
                            batchNumber: binfo.BatchNumber,
                            start: new moment(binfo.BatchStart, "YYYY-MM-DD HH:mm:ss"),
                            end: new moment(binfo.BatchEnd, "YYYY-MM-DD HH:mm:ss"),  
                            lineProductionItemId: binfo.LineProductionItemId,
                            line: binfo.Line,
                            mpid: binfo.MachineProductionItemId,
                            machine: binfo.Machine,
                            product: binfo.Product,

                            oee: oeeInfo.OEE,
                            availability: oeeInfo.Availability,
                            quality: oeeInfo.Quality,
                            performance: oeeInfo.Performance,

                            targetQty: oeeInfo.TargetQuantity,
                            goodQty: oeeInfo.GoodQuantity,
                            badQty: oeeInfo.BadQuantity,
                            totalQty: oeeInfo.TotalQuantity,
                            ratedQty: oeeInfo.RatedQuantity,
                            activeSeconds: oeeInfo.ActiveSeconds,
                            productionSeconds: oeeInfo.ProductionSeconds,

                            machines: _.map(machinesInfo, function(b){
                                return { label: b['Name'], value: b['Id'] }; 
                            }),  
                        }

                        var eventItems = _.map(eventsInfo, function (b) {
                            return {
                                id: null,
                                start: b.Start,
                                end: b.End,
                                duration: b.Duration,
                                type: b.Type,

                                ///(optionals)
                                delayId: b.DelayId, 
                                delayCodeId: b.DelayCodeId,
                                delayCodeParentId: b.DelayCodeParentId,
                            };
                        });

                        var timeAccountItems = _.map(timeAccountsInfo, function (b) {
                            return {
                                id: b.Id,
                                code: b.Code,
                                description: b.Description,
                                color: b.Color,
                                duration: b.Duration,
                            };
                        });

                        var delayCodeItems = _.map(delayCodesInfo, function (b) {
                            return {
                                id: b.Id,
                                code: b.Code,
                                description: b.Description,
                                color: b.Color,
                            };
                        });

                        var serieItems = []; 
                        _.each(seriesInfo, function (b) {

                            var serie1 = {
                                machineProductionItemId: b.ProductionItemId,
                                machineName: b.Name,
                                timestamp: new moment(b.Timestamp),
                                name: ('QUA_{{id}}').replace('{{id}}', b.ProductionItemId),
                                value: b.QUA,
                            };

                            var serie2 = {
                                machineProductionItemId: b.ProductionItemId,
                                machineName: b.Name,
                                timestamp: new moment(b.Timestamp),
                                name: ('PER_{{id}}').replace('{{id}}', b.ProductionItemId),
                                value: b.PER,
                            }; 

                            serieItems.push(serie1, serie2); 
                        }); 

                        var mixedDetailItems = _.map(mixedDetailsInfo, function (md) {
                            return {
                                start: md.Start,
                                end: md.End,
                                type: md.Type,
                                delayCodeId: md.DelayCodeId,
                                duration: md.Duration,
                            }; 
                        }); 

                        if (that.options.transaction_timestamp != tt)
                            return;

                        console.log((new Date()).toString() + " end parse data")

                        console.log((new Date()).toString() + " setting delay codes")
                        that.get("delayCodes")[options.method](delayCodeItems, { from: 'fetch' });
                        console.log((new Date()).toString() + " end setting delay codes")

                        console.log((new Date()).toString() + " setting events")
                        that.get("events")[options.method](eventItems, { from: 'fetch' });
                        console.log((new Date()).toString() + " end setting events")

                        console.log((new Date()).toString() + " setting timeaccounts")
                        that.get("timeAccounts")[options.method](timeAccountItems, { from: 'fetch' });
                        console.log((new Date()).toString() + " end setting timeaccounts")

                        console.log((new Date()).toString() + " setting series")
                        that.get("series")[options.method](serieItems, { from: 'fetch' }); 
                        console.log((new Date()).toString() + " end setting series")

                        console.log((new Date()).toString() + " setting mixed details")
                        that.get("mixedDetails")[options.method](mixedDetailItems, { from: 'fetch' });
                        console.log((new Date()).toString() + " end setting mixed details")

                        console.log((new Date()).toString() + " setting screenInfo")
                        that[options.method](screenInfo, { from: "fetch" });
                        console.log((new Date()).toString() + " end setting screen info")

                        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,
                    Cache: true, 
                }, app.ConnectionStrings.app);

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

            return this;
        },
    });

    OEEBatch.Models.OEEChartSerie = Backbone.Model.extend({
        defaults: {
            machineProductionItemId: null,
            machineName: null, 
            timestamp: null,
            name: null,
            value: null, 
        }, 
    });

    OEEBatch.Collections.OEEChartSeries = Backbone.Collection.extend({
        model: OEEBatch.Models.OEEChartSerie,
    }); 

    OEEBatch.Models.DelayCode = Backbone.Model.extend({
        defaults: {
            id: null,
            code: null,
            description: null,
            color: null,
        },
    });

    OEEBatch.Collections.DelayCodes = Backbone.Collection.extend({
        model: OEEBatch.Models.DelayCode,
    });

    OEEBatch.Models.Event = Backbone.Model.extend({
        defaults: {
            id: null,
            start: null,
            end: null,
            duration: null,
            type: null,

            ///(optionals)
            delayCodeId: null,
            delayCodeParentId: null,
        },
    });

    OEEBatch.Collections.Events = Backbone.Collection.extend({
        model: OEEBatch.Models.Event,
    });

    OEEBatch.Models.TimeAccount = Backbone.Model.extend({
        defaults: {
            id: null,
            code: null,
            description: null,
            color: null,
            duration: null,
        }
    });

    OEEBatch.Collections.TimeAccounts = Backbone.Collection.extend({
        model: OEEBatch.Models.TimeAccount,
        //comparator: function (a, b) {
        //    var idA = a.get("id");
        //    var idB = b.get("id");

        //    if (idA > idB) return -1;
        //    else if (idA < idB) return 1;
        //    else return 0;
        //},
    });

    OEEBatch.Models.Batch = Backbone.Model.extend({
        id: null,
        lineProductionItemId: null,
        line: null, 
        number: null,
        productId: null,
        product: null,
        quantity: null,
        productionQuantity: null, 
        start: null,
        end: null,
        totalTime: null, 

        selected: false, 
    }); 

    OEEBatch.Collections.Batches = Backbone.Collection.extend({
        model: OEEBatch.Models.Batch,
        comparator: function (a, b) {
            var startA = a.get("start");
            var startB = b.get("start");

            if (startA > startB) return -1;
            else if (startA < startB) return 1;
            else return 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"));

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

                        var batchItems = _.map(batches, function (b) {
                            return {
                                id: b.BatchId,
                                lineProductionItemId: b.LineProductionItemId,
                                line: b.Line,
                                number: b.Number,
                                productId: b.ProductId,
                                product: b.Product,
                                quantity: b.Quantity,
                                productionQuantity: b.ProductionQuantity, 
                                start: b.Start,
                                end: b.End,
                                totalTime: b.TotalTime, 
                            };
                        });

                        that[options.method](batchItems, { 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.
    OEEBatch.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return "oee-batch"; 
        } catch (Error) { }
    }

    OEEBatch.Views.Main = Backbone.Epoxy.View.extend({
        template: "oee-batch"
        , id: "oee-batch"
        , title: "OEEBatch"
        //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 () { };

            this.model = new OEEBatch.Models.Main({
                batchId: (this.options.viewParams && this.options.viewParams.id) ? parseInt(this.options.viewParams.id) : null, 
            });

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

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

            this.options.graph = {
                productQty: {
                    progressbars: {
                        good: null,
                        target: null,
                        options: null,
                    }
                },
                oee: {
                    circleProgress: {
                        oee: null,
                        ava: null,
                        per: null,
                        qua: null,
                    },
                    chart: null, 
                },
                events: {
                    grid: null,
                    collection: null,
                    model: null,
                    col: null,
                },
                timeAccounts: {
                    grid: null,
                    collection: null,
                    model: null,
                    col: null,
                },
                loadingScreen: false, 
            };

            this.bindEvents();
            //_.bindAll(this);
        },
        events: {
        }, 
        render: function (container) {
            var that = this;

            var thatContainer = (this.options.container) ? this.options.container : container; 
            this.options.container = thatContainer; 
            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = app.oeeModule.screensPath + "oee-batch/";

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

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

                    var 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"));

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

                    that.renderBatchesGrid();

                    that.drawCircles(); 
                    setTimeout(_.bind(that.renderTimeAccountsGrid, that), 1000);
                    //setTimeout(_.bind(that.drawOEELineChart, that), 1000);
                    //setTimeout(_.bind(that.drawProgressGraph, that), 1000);

                    //highlight oee components
                    that.$el.find('.oee-component').on("mouseover", _.bind(that.onHighlightOEEComponent, that));
                    that.$el.find('.oee-component').on("mouseout", _.bind(that.unhighlightOEEComponents, that));

                    that.$el.find('.oee-component').popover({
                        trigger: 'hover',
                        placement: 'left', 
                        title: function () { return that._oeeComponentPOTitle(this, that) },
                        content: function () { return that._oeeComponentPOContent(this, that) },
                        html: true, 
                    }); 

                }, true, customPath);
            }, customPath);
        }
        , _oeeComponentPOTitle: function (t, that) {
            var elem = $(t);
            var component = elem.data("circle-name").toLowerCase();
            return app.translate(that, component + "_popup_title"); 
        }
        , _oeeComponentPOContent: function (t, that) {
            var elem = $(t);
            var component = elem.data("circle-name").toUpperCase();

            switch (component) {
                case "PER":
                    return app.translate(that, "per_popup_content", [that.model.get("totalQty"), that.model.get("ratedQty"), (that.model.get("totalQty") / that.model.get("ratedQty")).toFixed(2)]);
                    break;
                case "QUA":
                    return app.translate(that, "qua_popup_content", [that.model.get("goodQty"), that.model.get("totalQty"), (that.model.get("goodQty") / that.model.get("totalQty")).toFixed(2)]);
                    break;
                case "AVA":
                    return app.translate(that, "ava_popup_content", [that.model.get("activeSeconds"), that.model.get("productionSeconds"), (that.model.get("activeSeconds") / that.model.get("productionSeconds")).toFixed(2)]);
                    break; 
            }
        }
        , onHighlightOEEComponent: function (e) {
            var elem = $(e.target);
            elem = elem.parents(".oee-component");
            var component = elem.data("circle-name"); 

            if (component != null && _.isString(component) && component.length > 0) {
                this.highlightOEEComponent(component.toUpperCase()); 
            }
        }
        , unhighlightOEEComponents: function () {
            this.$el.find(".highlight-elem").removeClass("highlight-elem");
        }
        , highlightOEEComponent: function (component) {
            this.$el.find(".highlight-elem").removeClass("highligh-elem"); 
            this.$el.find("." + component + "-oee-component").addClass("highlight-elem"); 
        }
        , renderBatchesGrid: function () {
            var that = this; 
            var batchesGrid = this.$el.find(".batches-grid-container");

            var columns = [
                {
                    name: "line",
                    label: app.translate(that, "line_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                {
                    name: "number",
                    label: app.translate(that, "number_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                {
                    name: "product",
                    label: app.translate(that, "product_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                {
                    name: "quantity",
                    label: app.translate(that, "quantity_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                {
                    name: "productionQuantity",
                    label: app.translate(that, "prod_quantity_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                {
                    name: "start",
                    label: app.translate(that, "start_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
                //{
                //    name: "end",
                //    label: app.translate(that, "end_label"),
                //    editable: false,
                //    //sortable: false,
                //    cell: Backgrid.StringCell.extend({
                //        orderSeparator: '',
                //        className: "string-cell align-center-cell",
                //    })
                //},
                {
                    name: "totalTime",
                    label: app.translate(that, "production_time_label"),
                    editable: false,
                    //sortable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell align-center-cell",
                    })
                },
            ];

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

                    if (this.model.get("id") == that.model.get("batchId")) {
                        this.$el.addClass("selected");
                    } else {
                        this.$el.removeClass("selected");
                    }

                    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.batchRowClick(this.model);
                    }
                },
            });

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

            batchesGrid.append(grid.render().el);

            //this.$el.find(".batches-table").floatThead({
            //    zIndex: 1000,
            //});

            //this.refreshBatches(); 
        }
        , refreshBatches: function () {
            var that = this; 
            var from = this.model.get("from"),
                to = this.model.get("to"),
                lineProductionItemId = this.model.get("lineProductionItemIdFilter");

            from = new moment(from).hours(0).minutes(0).seconds(0);
            to = new moment(to).add(1, 'day').hours(0).minutes(0).seconds(0); 

            lineProductionItemId = (lineProductionItemId != -1) ? lineProductionItemId : null; 

            this.model.get("batches").fetch({
                params: [
                    { Name: "From", Type: "DATETIME", Value: from.format("YYYY-MM-DD HH:mm:ss"), },
                    { Name: "To", Type: "DATETIME", Value: to.format("YYYY-MM-DD HH:mm:ss"), },
                    { Name: "LineProductionItemId", Type: "INT", Value: lineProductionItemId },
                ],
                callback: function (c) {
                    if (that.options.firstload) {
                        that.options.firstload = false;
                        if (c.length > 0 && !that.model.get('batchId')) {
                            that.model.set("batchId", c.at(0).get("id"))
                        } else {
                            that.refresh(); 
                        }
                    }
                }, 
            }); 
        }
        , batchRowClick: function (m) {
            app.router.navigate(app.router.resolveURL('!/oeeBatch(/:id)', { id: m.get('id') }, false, true), { trigger:false });

            if (this.model.get("lineProductionItemId") != m.get("lineProductionItemId")) {
                this.model.set("mpid", null);
            }

            this.model.set({
                batchId: m.get("id"),
            });
        }
        , refreshGraph: function () {
            try {
                console.log((new Date()).toString() + " start refresh graph")
                this.setLoading(false);

                var that = this;

                this.options.graph.oee.circleProgress["oee"].circleProgress('value', this.model.get("oee") / 100.0);
                this.options.graph.oee.circleProgress["ava"].circleProgress('value', this.model.get("availability") / 100.0);
                this.options.graph.oee.circleProgress["per"].circleProgress('value', this.model.get("performance") / 100.0);
                this.options.graph.oee.circleProgress["qua"].circleProgress('value', this.model.get("quality") / 100.0);

                var goodQty = this.model.get("goodQty"), badQty = this.model.get("badQty"), targetQty = this.model.get("targetQty"); 

                var progressbar_target = this.options.graph.productQty.progressbars.target;
                var progressbar_good = this.options.graph.productQty.progressbars.good;

                var progressbarset_options = {
                    total: this.model.get("targetQty") * 1.10,
                    good: this.model.get("goodQty"),
                    target: this.model.get("targetQty"),
                };

                if (progressbarset_options.target) {
                    progressbar_target.animate(that._getPercent(progressbarset_options.target, progressbarset_options), function () {
                        progressbar_good.animate(that._getPercent(progressbarset_options.good, progressbarset_options, 1), function () {
                        });
                    });
                } else {
                    progressbar_good.animate(0, function () {
                        progressbar_target.animate(0, function () {
                        });
                    });
                }

                console.log((new Date()).toString() + " start draw oeelinechart")
                this.drawOEELineChart();
                console.log((new Date()).toString() + " end draw oeelinechart")

                console.log((new Date()).toString() + " start refresh time accounts")
                this.refreshTimeAccountsGrid();
                console.log((new Date()).toString() + " end refresh time accounts")

                console.log((new Date()).toString() + " end refresh graph")
            } catch (Error) {
            }
        }
        , fromToModelChanged: function (a, b, c) {
            var from = new moment(this.options.viewModels.fromDateControl.get("date")); 
            var to = new moment(this.options.viewModels.toDateControl.get("date"));

            if (!from.isSame(this.model.get("from"), 'day'))
                this.model.set("from", from);

            if (!to.isSame(this.model.get("to"), 'day'))
                this.model.set("to", to);

            this.model.fetchLinesMachines(); 
        }
        , drawCircles: function () {
            var that = this;

            // Arc layout
            $.circleProgress.defaults.arcCoef = 1; // default; range: 0..1
            $.circleProgress.defaults.startAngle = -1.5 * Math.PI; // default

            $.circleProgress.defaults.drawArc = function (v) {
                var ctx = this.ctx,
                    r = this.radius,
                    t = this.getThickness(),
                    c = this.arcCoef,
                    a = this.startAngle + (1 - c) * Math.PI;

                v = Math.max(0, Math.min(1, v));

                ctx.save();
                ctx.beginPath();

                if (!this.reverse) {
                    ctx.arc(r, r, r - t / 2, a, a + 2 * c * Math.PI * v);
                } else {
                    ctx.arc(r, r, r - t / 2, a + 2 * c * Math.PI, a + 2 * c * (1 - v) * Math.PI, a);
                }

                ctx.lineWidth = t;
                ctx.lineCap = this.lineCap;
                ctx.strokeStyle = this.arcFill;
                ctx.stroke();
                ctx.restore();
            };

            $.circleProgress.defaults.drawEmptyArc = function (v) {
                var ctx = this.ctx,
                    r = this.radius,
                    t = this.getThickness(),
                    c = this.arcCoef,
                    a = this.startAngle + (1 - c) * Math.PI;

                v = Math.max(0, Math.min(1, v));

                if (v < 1) {
                    ctx.save();
                    ctx.beginPath();

                    if (v <= 0) {
                        ctx.arc(r, r, r - t / 2, a, a + 2 * c * Math.PI);
                    } else {
                        if (!this.reverse) {
                            ctx.arc(r, r, r - t / 2, a + 2 * c * Math.PI * v, a + 2 * c * Math.PI);
                        } else {
                            ctx.arc(r, r, r - t / 2, a, a + 2 * c * (1 - v) * Math.PI);
                        }
                    }

                    ctx.lineWidth = t;
                    ctx.strokeStyle = this.emptyFill;
                    ctx.stroke();
                    ctx.restore();
                }
            };

            this.$el.find(".circle").each(function () {
                var $circle = $(this);
                var val = $circle.data("circle-value");
                var circle_container = $circle.parent(".circle-container");
                var circle_gradient = ($circle.data("circle-gradient")) ? $circle.data("circle-gradient") : ['#29D65A', '#29D67D'];
                var circle_thickness = ($circle.data("circle-thickness")) ? $circle.data("circle-thickness") : 25;
                var circle_name = $circle.data("circle-name");

                that.options.graph.oee.circleProgress[circle_name] = $circle;

                that.options.graph.oee.circleProgress[circle_name].circleProgress({
                    value: (val) ? val / 100 : 0,
                    size: circle_container.width() - 20,
                    startAngle: -Math.PI / 4 * 2,
                    thickness: circle_thickness,
                    fill: {
                        gradient: circle_gradient,
                    }
                }).on("circle-animation-progress", function (event, progress, stepValue) {
                    var progress_display = $circle.find(".progress-display");
                    if (progress_display.length > 0) {
                        progress_display.text((stepValue * 100).toFixed(0) + "%");
                    }
                });
            });

            var progressbarset_options = {
                total: null,
                actual: null,
                target: null,
            };

            this.options.graph.productQty.progressbars.options = progressbarset_options;

            var progressbar_good = this.options.graph.productQty.progressbars.good = new ProgressBar.Line('.progressbar-actual', {
                color: "#858585",
                trailColor: 'transparent',
                trailWidth: 1,
                easing: 'easeInOut',
                strokeWidth: 1,
                from: { color: '#FFF' },
                to: { color: '#858585' },
                step: function (state, bar) {
                }
            });

            var progressbar_target = this.options.graph.productQty.progressbars.target = new ProgressBar.Line('.progressbar-target', {
                color: "#CCCCCC",
                trailColor: 'transparent',
                trailWidth: 1,
                easing: 'easeInOut',
                strokeWidth: 1,
                from: { color: '#FFF' },
                to: { color: '#ddd' },
                step: function (state, bar) {
                }
            });

            var pbar_container = this.$el.find(".pbar-container");
            pbar_container.find("svg").css({
                height: "25px",
                width: "100%",
                display: "block",
                "overflow-y": "hidden", 
            });
            
            //progressbar_target.animate(that._getPercent(progressbarset_options.target, progressbarset_options), function () {
            //    progressbar_good.animate(that._getPercent(progressbarset_options.actual, progressbarset_options));
            //});
            
        }
        , drawOEELineChart: function () {
            var that = this; 
            Chart.defaults.global.responsive = true;

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

            var series_names = _.uniq(series.pluck("name"));

            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 data = []; 
            _.each(series_names, function (b, inx) {
                var serie_vals = series.where({ name: b });
                if (_.some(serie_vals, function (a) { return a.get("value") != null; })) {
                    var s = b.substring(0, 3); 
                    var t = app.translate(that, s + "_label");
                    var lbl = ""; 

                    if (that.model.get("machineProductionItemId") != null) {
                        lbl = t;
                    } else {
                        if (s == "PER" || series_names.length < 3) {
                            lbl = t;
                        } else {
                            lbl = t + " " + serie_vals[0].get("machineName");
                        }
                    }

                    data.push({
                        label: lbl, 
                        strokeColor: colors[inx],
                        data: _.map(serie_vals, function(v){
                            return {
                                x: v.get("timestamp").toDate(),
                                y: v.get("value"), 
                            }; 
                        }), 
                    }); 
                }
            });

            var container = this.$el.find(".oee-line-chart-container");

            if (this.options.graph.oee.chart) {
                this.options.graph.oee.chart.destroy();
                container.empty();
                this.options.graph.oee.chart = null;
            }

            var cnv = $("<canvas></canvas>");
            cnv.width(container.width()).height(250);
            container.append(cnv); 

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

            var start = this.model.get("start"), end = this.model.get("end");

            var chart = this.options.graph.oee.chart = new Chart(ctx).Scatter(data, {
                animation: false, 
                bezierCurve: false,
                showTooltips: true,
                scaleShowHorizontalLines: true,
                scaleShowLabels: true,
                scaleType: "date",
                scaleLabel: "<%=value%>",

                scaleOverride: true,
                scaleSteps: 10,
                scaleStepWidth: 10,
                scaleStartValue: 0,

                xScaleOverride: true,
                xScaleStartValue: start.toDate().getTime(),
                xScaleEndValue: end.toDate().getTime(), 

                multiTooltipTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%=argLabel%>; <%=valueLabel%>",

                useUtc: false,
                onAnimationComplete: function () {
                }, 
            });

            that.drawProgressGraph(chart.scale.xScaleRange);
        }
        , drawProgressGraph: function (xScaleRange) {
            console.log((new Date()).toString() + " start draw progress graph")

            var that = this;

            var container = this.$el.find(".progress-bar-container");
            var pbar = container.find(".progress");
            pbar.empty();

            var pb_timeline = this.$el.find(".progress-bar-timeline");
            pb_timeline.empty();

            if (xScaleRange) {

                //total in seconds
                //var start = this.model.get("start"), end = this.model.get("end");
                var start = new moment(xScaleRange.min), end = new moment(xScaleRange.max);
                var total = Math.abs(end.diff(start, 'seconds'));
                var opt = {
                    total: total,
                };

                var itemCategories = new OEEBatch.Collections.ItemCategories([
                    { id: -3, name: app.translate(that, "mixed_label"), color: "#ffff00" },
                    { id: -2, name: app.translate(that, "active_label"), color: "#3aea3a" },
                    { id: -1, name: app.translate(that, "not_declared_label"), color: "#de2e27" }
                ]);

                itemCategories.add(
                    this.model.get("delayCodes").map(function (m) {
                        return { id: m.get("id"), name: m.get("code"), color: m.get("color") }
                    })
                );

                var progressItems = new OEEBatch.Collections.ProgressItems();
                var events = this.model.get("events"); 

                progressItems.add(
                    events.map(function (m) {
                        var t = {
                            id: m.get("id"),
                            duration: m.get("duration"),
                            start: m.get("start"),
                            end: m.get("end"),
                            category: itemCategories.findWhere({ id: m.get("delayCodeId") }),
                            delayId: m.get("delayId"),
                        };

                        if (!t["category"]) {
                            if (m.get("type") == "DELAY") {
                                t["category"] = itemCategories.findWhere({ id: -1 });
                            } else if (m.get("type") == "PRODUCTION") {
                                t["category"] = itemCategories.findWhere({ id: -2 });
                            } else if (m.get("type") == "MIXED") {
                                t["category"] = itemCategories.findWhere({ id: -3 });
                            }
                        }

                        return t;
                    })
                );

                //var lastbatch = {
                //    id: -1,
                //    start: null,
                //    end: this.model.get("start").format("YYYY-MM-DD HH:mm:ss"),
                //};

                //var batchesContainer = this.$el.find('.batch-indicators-container');
                //batchesContainer.empty();

                //_.forEach(batchesEvents, function (m, inx, arr) {
                //    if (lastbatch != null && lastbatch.end != m.start) {
                //        var nodatabar = $("<div class='batch-line'></div>");
                //        var nodataduration = Math.abs((new moment.duration(new moment(lastbatch.end).diff(new moment(m.start)))).asSeconds());
                //        var nodatawd = ((nodataduration * 100) / total);
                //        nodatabar.css("width", nodatawd + "%");
                //        batchesContainer.append(nodatabar);
                //    }

                //    var batchProps = _.findWhere(batches, { batchId: (m.id) ? m.id : -1 });
                //    var batchLine = $('<div class="batch-line ' + batchProps.color + '"></div>');

                //    var start = new moment(m.start); var end = new moment(m.end);
                //    var duration = Math.abs((new moment.duration(start.diff(end))).asSeconds());

                //    var wd = ((duration * 100) / total);
                //    batchLine.css("width", wd + "%");
                //    batchLine.css('opacity', (1 / arr.length) * (inx + 1));

                //    var popover_title = _.template('<h4 style="padding:0px;"><%= title %></h4>');
                //    var popover_content = _.template('<div><dl class="dl-horizontal">'
                //                            + '<dt style="width:80px;">' + app.translate(that, 'batch_po_batchNumber_label') + '</dt><dd style="margin-left:120px;"><%= batchNumber %></dd>'
                //                            + '<dt style="width:80px;">' + app.translate(that, 'batch_po_product_label') + '</dt><dd style="margin-left:120px;"><%= product %></dd>'
                //                            + '</dl></div>');

                //    var $po = batchLine.popover({
                //        placement: "top",
                //        html: true,
                //        trigger: "hover",
                //        title: popover_title({
                //            title: app.translate(that, 'batch_po_title'),
                //        }),
                //        content: popover_content({
                //            batchNumber: batchProps.batchNumber,
                //            product: batchProps.product,
                //        }),
                //        delay: { show: 150, hide: 0 },
                //        //container: '.progress',
                //    });

                //    batchesContainer.append(batchLine);

                //    lastbatch = m;
                //});

                var totalwd = 0;
                var lastpi = new OEEBatch.Models.ProgressItem({
                    duration: null,
                    category: null,
                    start: null,
                    end: start.format("YYYY-MM-DD HH:mm:ss.sss"),
                });

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

                var popover_title = _.template('<h4 style="color: #000;padding:0px;"><%= title %></h4>');
                var nodata_popover_content_template = Handlebars.compile($("#nodata_popover_content_template").html());

                progressItems.forEach(function (m, inx) {
                    if (lastpi != null && lastpi.get("end") != m.get("start")) {
                        var nodatabar = $("<div style='cursor:pointer;' class='bar bar-white no-data-bar'></div>");
                        var nodataduration = Math.abs((new moment.duration(new moment(lastpi.get("end")).diff(new moment(m.get("start"))))).asSeconds());
                        var nodatawd = ((nodataduration * 100) / total);
                        nodatabar.css("width", nodatawd + "%");
                        totalwd += nodatawd;

                        var $npo = nodatabar.popover({
                            placement: "top",
                            html: true,
                            trigger: "hover",
                            title: popover_title({
                                title: app.translate(that, "no_data_available_po_title"),
                            }),
                            content: nodata_popover_content_template({
                                startTime: new moment(lastpi.get("end")).format("YYYY-MM-DD HH:mm:ss"),
                                duration: that.secondsToHMS(nodataduration),
                            }),
                            delay: { show: 150, hide: 0 },
                        });

                        $npo.on("shown", function () {
                            pbar.find(".popover-title").css({
                                "background-color": "#fff"
                            });
                        });

                        pbar.append(nodatabar);
                    }

                    var mixed = (m.get("category").get("id") == -3); 

                    var bar_tmpl = Handlebars.compile(
                        "<div style='cursor:pointer;' class='bar bar-popover bar-hover {{#if mixed}}bar-mixed-striped{{else}}bar-custom-color{{/if}}'></div>"
                    );
                    var bar = $(bar_tmpl({
                        mixed: mixed,
                    }));
                    var wd = ((m.get("duration") * 100) / total);

                    totalwd += wd;

                    if (m.get("delayId") != null) {
                        bar.attr("data-delay-id", m.get("delayId")); 
                    }

                    if (!mixed) bar.css("background-color", m.get("category").get("color"));

                    var popover_content = Handlebars.compile($("#" + ((mixed) ? "mixed_" : "") + "popover_content_template").html());

                    //creating popover
                    var mod = that.model.get("events").findWhere({ id: m.get("id") });
                    var popover_content_data = {};

                    if (mixed) {
                        popover_content_data = {
                            startTime: (new moment(m.get("start"))).format("YYYY-MM-DD HH:mm:ss"), 
                            duration: that.secondsToHMS(m.get("duration")), 
                            details: _.map(mixedDetails.where({ start: m.get("start") }), function (t) {
                                var reason = ""; 
                                if (t.get("type") == "PRODUCTION"){ reason = itemCategories.findWhere({ id: -2 }).get("name"); }
                                else{
                                    var dcode = t.get("delayCodeId"); 
                                    var ic = itemCategories.findWhere({ id: (dcode != null) ? dcode : -1 }); 
                                    if (ic) reason = ic.get("name"); 
                                }

                                return {
                                    reason: reason,
                                    duration: that.secondsToHMS(t.get("duration")),
                                }; 
                            }), 
                        }; 
                    } else {
                        popover_content_data = {
                            reason: m.get("category").get("name"),
                            startTime: (new moment(m.get("start"))).format("YYYY-MM-DD HH:mm:ss"),
                            duration: that.secondsToHMS(m.get("duration")),
                        }; 
                    }

                    var content = popover_content(popover_content_data); 

                    var $po = bar.popover({
                        placement: "top",
                        html: true,
                        trigger: "hover",
                        title: popover_title({
                            title: m.get("category").get("name"),
                        }),
                        content: popover_content(popover_content_data),
                        delay: { show: 150, hide: 0 },
                    });

                    $po.on("shown", function () {
                        pbar.find(".popover-title").css({
                            "background-color": (mixed) ? "#fff" : m.get("category").get("color"),
                        });
                        pbar.find(".popover-title h4").css({
                            "color": (mixed) ? "#000" : "#fff",
                        }); 
                    });

                    bar.css("width", wd + "%");
                    
                    pbar.append(bar);

                    lastpi = m;
                });

                if ($.inArray("AdminUserRole", app.models.user.get("roles")) != -1
                        || $.inArray("SupervisorUserRole", app.models.user.get("roles")) != -1) {
                    pbar.find('[data-delay-id]').on("click", _.bind(that.showDelayInfoModal, that));
                }

                var t_divisions = 8;
                var div_duration = total / t_divisions;

                var st = start.clone();
                var arr = _.times(t_divisions, function (inx) {
                    return st.clone().add(div_duration * inx, 'seconds');
                });

                _.each(arr, function (val, inx) {
                    var lbl = $('<small style="position:absolute;top:-15px;"></small>');
                    var marker = $('<div style="position:absolute;top:-40px;height:40px;width:0px;border-left:1px dashed #ccc;"></div>');

                    lbl.text(val.format("HH:mm:ss"));
                    var left = (inx * div_duration * 100) / total;

                    lbl.css({ left: (left + 0.5) + '%' });
                    marker.css({ left: left + '%' });
                    pb_timeline.append(marker);
                    pb_timeline.append(lbl);
                });

                //end label
                var lbl = $('<small style="position:absolute;top:-15px;"></small>');
                var marker = $('<div style="position:absolute;top:-40px;height:40px;width:0px;border-left:1px dashed #ccc;"></div>');
                lbl.text(end.format("HH:mm:ss"));
                lbl.css({ left: '97.5%' });
                marker.css({ left: '100%' });
                pb_timeline.append(marker);
                pb_timeline.append(lbl);

                console.log((new Date()).toString() + " end draw progress graph")
            }
        }
        , showDelayInfoModal: _.debounce(function (e) {
            //var target = $(e.target); 
            //var delayId = target.data("delay-id"); 

            //var m = this.model.get("events").findWhere({ type: "DELAY", delayId: delayId }); 

            //if (m && !m.get("delayCodeId")) {
            //    var delayinfomodal = new OEEBatch.Views.DelayInformationModal({
            //        viewParams: {
            //            rowData: {
            //                id: delayId,
            //                //model: this.model,
            //            },
            //        }
            //    });

            //    //calling grid refresh as soon as the modal is hidden in case
            //    //any changes were made.
            //    delayinfomodal.on("hidden", _.bind(this.refresh, this));

            //    delayinfomodal.show();
            //}

            var target = $(e.target); 
            var delayId = target.data("delay-id"); 

            var m = this.model.get("events").findWhere({ type: "DELAY", delayId: delayId }); 

            if (m && !m.get("delayCodeId")) {
                var that = this;
                var delayinfomodal = new OEEBatch.Views.DelayInformationModal({
                    viewParams: {
                        rowData: {
                            id: delayId,
                            model: m,
                        },
                    }
                });

                delayinfomodal.on("delayCodeSelected", function () {
                    // Comment out remove due to the following.
                    // - Since this method is also executed from progress bar graph' items,
                    //   some items are not in the collection because not all items are loaded
                    //   for pagination.
                    // - If the declared delay is the current delay, there is a weird effect because
                    //   the delays appears again after refresh but 'disabled' (which is fine).
                    //   So to not remove it manually and wait for the refresh to prevent this effect.
                    //m.collection.remove(m);

                    that.refresh({
                        //refreshDelaysData: true,
                        //refreshCacheDelays: true,
                    });
                });

                delayinfomodal.show();
            }
        }, 500, true)
        , renderTimeAccountsGrid: function () {
            var that = this;
            var timeAccountModel = Backbone.Model.extend({
                defaults: {
                    name: null,
                    duration: null,
                    color: null,
                    code: null, 
                },
            });

            this.options.graph.timeAccounts.model = timeAccountModel;

            var timeAccountsCollection = Backbone.Collection.extend({
                model: timeAccountModel,
                comparator: function (a, b) {
                    var aduration = a.get('duration');
                    var bduration = b.get('duration');

                    //if active then at the top of the list
                    if (a.get('id') == -5) return -1;
                    if (b.get('id') == -5) return 1;

                    if (a.get('id') == -2) return -1;
                    if (b.get('id') == -2) return 1;

                    if (a.get('id') == -4) return -1;
                    if (b.get('id') == -4) return 1;

                    if (a.get('id') == -3) return 1;
                    if (b.get('id') == -3) return -1;

                    if (aduration > bduration) return -1;
                    else if (aduration < bduration) return 1;
                    else return 0; 
                }, 
            });

            this.options.graph.timeAccounts.col = timeAccountsCollection;

            var timeAccounts = new timeAccountsCollection();

            this.options.graph.timeAccounts.collection = timeAccounts;

            var columns = [
                {
                    name: "name",
                    label: app.translate(that, "name_label"),
                    editable: false,
                    formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
                        fromRaw: function (rawValue, model) {
                            return app.translate(that, rawValue);
                        }
                    }),
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell",
                        render: function () {
                            Backgrid.StringCell.prototype.render.apply(this, arguments);

                            switch (this.model.get("code")) {
                                case "PRODUCTIONTIME":
                                case "ACTIVE":
                                    this.$el.addClass("AVA-oee-component");
                                    break;
                            }

                            return this; 
                        }
                    })
                },
                {
                    name: "duration",
                    label: app.translate(that, "duration_label"),
                    editable: false,
                    cell: Backgrid.StringCell.extend({
                        orderSeparator: '',
                        className: "string-cell text-center",
                        render: function () {
                            this.$el.html(this.secondsToHHMMSS(this.model.get("duration")));
                            //this.$el.addClass(this.model.get("code") + "-duration-column"); 

                            switch (this.model.get("code")) {
                                case "PRODUCTIONTIME":
                                case "ACTIVE":
                                    this.$el.addClass("AVA-oee-component"); 
                                    break; 
                            }

                            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 > 0 ? h + ":" + (m < 10 ? "0" : "") : "") + m + ":" + (s < 10 ? "0" : "") + s);
                        },
                    })
                },
                {
                    name: "graph",
                    label: app.translate(that, "graph_label"),
                    editable: false,
                    cell: Backgrid.StringCell.extend({
                        template: _.template("<div style='height:20px;width:180px;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 () {
                            this.$el.html(this.template());
                            var pbar_container = this.$el.find(".bar-graph-container");
                            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: "15px",
                                width: "100%",
                                "overflow-y": "hidden",
                            });

                            var opt = {
                                //total: Math.abs(that.model.get("end").diff(that.model.get("start"), 'seconds')),
                                total: that.options.graph.timeAccounts.collection.reduce(function(memo, m){
                                    return memo + m.get("duration"); 
                                }, 0),  
                            };

                            setTimeout(function () {
                                pbar.animate(that._getPercent(val, opt));
                            }, 300);

                            this.delegateEvents();
                            return this;
                        },
                        refresh: function () {
                            //var opt = {
                            //    total: Math.abs(that.model.get("end").diff(that.model.get("start"), 'seconds')),
                            //};

                            var opt = {
                                //total: Math.abs(that.model.get("end").diff(that.model.get("start"), 'seconds')),
                                total: that.options.graph.timeAccounts.collection.reduce(function (memo, m) {
                                    return memo + m.get("duration");
                                }, 0),
                            };

                            var val = this.model.get("duration");
                            this.options.graph.pbar.animate(that._getPercent(val, opt));
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change", this.refresh);
                        },
                    })
                },
            ];

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

            this.options.graph.timeAccounts.grid = grid;

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

            this.refreshTimeAccountsGrid();
        }
        , refreshTimeAccountsGrid: function () {
            var timeAccounts = this.options.graph.timeAccounts.collection;

            var timeaccountsarr = [];
            this.model.get("timeAccounts").forEach(function (m) {
                timeaccountsarr.push({
                    id: m.get("id"),
                    code: m.get("code"), 
                    name: m.get("code"),
                    duration: m.get("duration"),
                    color: m.get("color"),
                });
            });

            timeAccounts.reset(timeaccountsarr);
        }
        , _getPercent: function (val, opt, topVal) {
            topVal = _.isNumber(topVal) ? topVal : null
            var val = (Math.round((val * 100) / opt.total)) / 100;
            return (topVal == null || val <= topVal) ? val : topVal;
        }
        , _sign: function (num) {
            // IE does not support method sign here
            if (typeof Math.sign === 'undefined') {
                if (num > 0) {
                    return 1;
                }
                if (num < 0) {
                    return -1;
                }
                return 0;
            }
            return Math.sign(num);
        }
        , precise_round: function (num, decimals) {
            var t = Math.pow(10, decimals);
            return (Math.round((num * t) + (decimals > 0 ? 1 : 0) * (this._sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
        }
        , _getValue: function (perc, opt, topVal) {
            topVal = _.isNumber(topVal) ? topVal : null
            var val = this.precise_round((perc * opt.total) / 100, 2);
            val = parseFloat(val);
            val = (val > 1) ? Math.round(val) : val;
            val = (val * 100).toFixed(0);
            return (topVal == null || val <= topVal) ? val : topVal;
        }
        , secondsToHMS: 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 > 0 ? h + " hs " : "") + m + " min " + s + " seg");
        }
        , refresh: _.debounce(function (viewParams) {
            try {
                if (viewParams && viewParams.id) {
                    this.model.set("mpid", null);
                    this.model.set('batchId', parseInt(viewParams.id));
                    return; 
                }

                var after_callback = _.after(1, _.bind(this.refreshGraph, this));

                if (this.model.get("batchId") != null) {
                    this.setLoading(true);

                    this.model.fetchHistoricalBatch(
                        this.model.get("batchId"),
                        this.model.get("machineProductionItemId"),
                        {
                            callback: after_callback,
                        }
                    );
                }
            } catch (Error) { }
        }, 300)
        , setLoading: function (v) {
            v = _.isBoolean(v) ? v : true;

            if (this.options.loadingScreen && v) return;

            var that = this;
            that.options.loadingScreen = v;

            var fn = function () {
                if (that.options.loadingScreen == v) {
                    that.$el.find('.hide-on-loading')[v ? 'addClass' : 'removeClass']('hide');
                    that.$el.find('.loading-poster')[v ? 'removeClass' : 'addClass']('hide');
                }
            };

            if (v) {
                setTimeout(fn, 500);
            } else {
                fn(); 
            }
        }
        , append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }
        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily

            this.listenTo(this.options.viewModels.fromDateControl, "change:date", this.fromToModelChanged);
            this.listenTo(this.options.viewModels.toDateControl, "change:date", this.fromToModelChanged);
            this.listenTo(this.model, "change:from", this.refreshBatches);
            this.listenTo(this.model, "change:to", this.refreshBatches);
            this.listenTo(this.model, "change:lineProductionItemIdFilter", this.refreshBatches);

            this.listenTo(this.model, "change:batchId", this.refresh);
            this.listenTo(this.model, "change:machineProductionItemId", this.refresh);
        }
        , bindViewScopedEvents: function () {
            var that = this; 
        }
        , 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();
            });
        }
        , hide: function () {
            this.options.state = app.view_states.hidden;

            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("subnavbar", false);
        }
        , reRender: function (viewParams) {
            try {
                this.refresh(viewParams); 
            } catch (Error) { }
        }
    });

    OEEBatch.Views.DelayInformationModal = delayInformationModal.Views.DelayInformationModal.extend({
        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"
            });


            //-----------------------------------------------------------------------
            // Comment out this code because on this screen all modals 
            // do not hide when backdrop clicked or escape key pressed.
            //-----------------------------------------------------------------------
            //$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;

        }
    });

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

});

