//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',
  'moment',
  'Chart',
  'js/d3v4/d3.v4',

  'backgrid/moment-cell',
  'js/jquery.clearsearch/jquery.clearsearch',
  'js/dashboard-assets/chartjs/Chart.StackedBar',
],
function (app, T, Backgrid, moment, Chart, d3) {
    var Screen = { Models: {}, Views: {}, Collections: {},};

    Screen.Models.Main = Backbone.Epoxy.Model.extend({
        defaults: {

            from: new moment().subtract(1, 'days').format('MM/DD/YYYY'),
            to: new moment().format('MM/DD/YYYY'),

            hasData_TimeAccounts: false,
            isLoading_TimeAccounts: true,

            crews: [
                { value: "1", label: "A" },
                { value: "2", label: "B" },
                { value: "3", label: "C" },
                { value: "4", label: "D" }
            ],

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

            lines: [],
            machinesInternal: [],
            products: [],
            shifts: [
                { value: 1, label: 'D' },
                { value: 2, label: 'N' },
            ],
            delayCategories: [],

            hasData_delayCategoriesStackedInfo: false,
            isLoading_delayCategoriesStackedInfo: true,
            hasData_delayCategoriesStackedData: false,
            isLoading_delayCategoriesStackedData: true,
            hasData_categoriesData: false,
            isLoading_categoriesData: true,

        },

        initialize: function(){
            this.timeAccounts = new Screen.Collections.TimeAccounts();
            this.delayCategoriesStackedInfo = new Screen.Collections.DelayCategoriesStackedInfo();
            this.delayCategoriesStackedData = new Screen.Collections.DelayCategoriesStackedData();
            this.categoriesData = new Screen.Collections.CategoriesData();

            this.fetchDelayCategories({ async: false });
        },

        computeds: {
            hasData: {
                deps: ['hasData_TimeAccounts'],
                get: function (timeAcc) {
                    return timeAcc;
                },
            },
            isLoading: {
                deps: ['isLoading_TimeAccounts'],
                get: function (timeAcc) {
                    return timeAcc;
                }
            },
            hasDataCanvas: {
                deps: ['hasData_categoriesData', 'hasData_delayCategoriesStackedData', 'hasData_delayCategoriesStackedInfo'],
                get: function (cat, data, info) {
                    return cat && data && info;
                },
            },
            isLoadingCanvas: {
                deps: ['isLoading_categoriesData', 'isLoading_delayCategoriesStackedData', 'isLoading_delayCategoriesStackedInfo'],
                get: function (cat, data, info) {
                    if (!cat && !data && !info) return false;
                    else return true;
                },
            },
            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, };
                    });
                },
            },
        },
        
        fetchDelayCategories: function () {
            var that = this;
            Core.Json.CallProcedure(app.DatabaseNames.MES + ".CAS.GetDelayCategories", null, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var items = data.Table;

                        that.set({
                            delayCategories: _.map(items, function (m) {
                                return { value: m.Id, label: m.Name, color: m.Color, description: m.Description,};
                            }),
                        });
                        that.trigger('delay-categories-fetched');
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },


        fetchCategoriesData: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();
            this.fixedParameters = [
                { Name: "@From", Type: "DATETIME",       Value: params.from, },
                { Name: "@To", Type: "DATETIME",         Value: params.to, },
                { Name: "@ShiftId", Type: "INT",         Value: params.shiftId },
                { Name: "@delayCategoryId", Type: "INT", Value: params.delayCategoryId },
                { Name: '@Timezone', Type: 'VARCHAR', Value: 'EDTIND', },
            ];

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

            Core.Json.CallProcedure(
                app.DatabaseNames.MES + '.CAS.GetDelayCategoriesStacked',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp) {
                                if (resp.Table) {
                                    that.delayCategoriesStackedInfo.setDataColl(resp.Table); 
                                };
                                if (resp.Table1) {
                                    that.delayCategoriesStackedData.setDataColl(resp.Table1);
                                };
                                if (resp.Table2) {
                                    that.categoriesData.setDataColl(resp.Table2);
                                };

                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(new Error(resp.Message).stack);
                                else
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );

            return this;

        },
        fetchGridData: function (params) {
            var that = this,
                crew = null,
                qp = new Core.Database.QueryParameters();

            if (params.crewId) {
                if (params.crewId == '1') crew = 'A';
                if (params.crewId == '2') crew = 'B';
                if (params.crewId == '3') crew = 'C';
                if (params.crewId == '4') crew = 'D';
            }

            this.fixedParameters = [
                { Name: '@From', Type: 'DATETIME',       Value: params.from, },
                { Name: '@To', Type: 'DATETIME',         Value: params.to, },
                //{ Name: '@ShiftId', Type: "INT",         Value: params.shiftId },
                //{ Name: '@delayCategoryId', Type: "INT", Value: params.delayCategoryId },
                //{ Name: '@CrewId', Type: "CHAR", Value: params.crewId ? crew : null },
                //{ Name: '@Timezone', Type: 'VARCHAR', Value: 'EDTIND', },

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


            Core.Json.CallProcedure(
                app.DatabaseNames.MES + '.CAS.GetDelaysTimeSummary',
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if (resp) {
                                if (resp.Table) {
                                    console.log("resp.Table", resp.Table);
                                    that.timeAccounts.setDataColl(resp.Table);
                                };

                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(new Error(resp.Message).stack);
                                else
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );

            return this;
        },


    });

    Screen.Models.DelayCategoriesStackedInfo = Backbone.Epoxy.Model.extend({
        parse: function (obj) {
            var result = {
                timestamp: obj.Timestamp.toString(),
                totalseconds: new moment.duration(obj.TotalSeconds, 'seconds'),
            };
            return result;
        },
    });
    Screen.Collections.DelayCategoriesStackedInfo = Backbone.Collection.extend({
        model: Screen.Models.DelayCategoriesStackedInfo,

        setDataColl: function (data) {
            var newColl = [],
                that = this;
            newColl = _.map(data, that.model.prototype.parse);
            that.set(newColl).trigger('fetch', that, data);

        },
    });

    Screen.Models.DelayCategoriesStackedData = Backbone.Epoxy.Model.extend({
        parse: function (obj) {
            var result = {
                id: obj.Timestamp.toString() + '&' + ((obj.CategoryId) ? obj.CategoryId.toString() : "ND"),
                timestamp: obj.Timestamp,
                categoryId: obj.CategoryId,
                name: obj.Category,
                duration: (_.isNumber(obj.Duration)) ? Math.round(obj.Duration * 100) / 100 : 0,
            };
            return result;
        },
    });
    Screen.Collections.DelayCategoriesStackedData = Backbone.Collection.extend({
        model: Screen.Models.DelayCategoriesStackedData,

        setDataColl: function (data) {
            var newColl = [],
                that = this;
            newColl = _.map(data, that.model.prototype.parse);
            that.set(newColl).trigger('fetch', that, data);

        },
    });

    Screen.Models.CategoriesData = Backbone.Epoxy.Model.extend({
        parse: function (obj) {
            var result = {
                id: obj.Id,
                name: obj.Name,
                description: obj.Description,
                color: obj.Color,
            };
            return result;
        },
    });
    Screen.Collections.CategoriesData = Backbone.Collection.extend({
        model: Screen.Models.CategoriesData,

        setDataColl: function (data) {
            var newColl = [],
                that = this;
            var categoriesItems = [
                {
                    id: null,
                    name: "NOTDECLARED",
                    description: "Not Declared",
                    color: '#f84e4e',
                },
            ];
            newColl = _.map(data, that.model.prototype.parse);
            _.each(newColl, function (obj) {

                categoriesItems.push(obj);
            });
            that.set(categoriesItems).trigger('fetch', that, data);

        },
    });

    Screen.Models.TimeAccount = Backbone.Epoxy.Model.extend({
        parse: function (obj) {
            var result = {
                Id: obj.Id,
                Code: obj.Code,
                Category: obj.Category,
                Description: obj.Description,
                Color: obj.Color,
                //Duration: obj.Duration ? moment.utc(moment.duration(obj.Duration, "seconds").asMilliseconds()).format("HH:mm:ss") : '00:00:00',
                Duration: obj.DurationDaysAndTime ? obj.DurationDaysAndTime : '0:00:00:00',
                SecondsDuration: obj.Duration,
                Count: obj.Count,
                ProductionItem: obj.ProductionItem
            };
            return result;
        },
    });
    Screen.Collections.TimeAccounts = Backbone.Collection.extend({
        model: Screen.Models.TimeAccount,
        totalDuration: 0,
        totalCount: 0,
        formattedDuration: '0 00:00:00',
        data: [],
        divWidth: 300,
        setDataColl: function (data) {
            var newColl = [],
                that = this;
            newColl = _.map(data, that.model.prototype.parse);
            that.totalDuration = _.reduce(newColl, function (memo, m) {
                return memo + m.SecondsDuration;
            }, 0);
            that.totalCount = _.reduce(newColl, function (memo, m) {
                return memo + m.Count;
            }, 0);
            that.setDataChart(newColl);

            var parsedTotalDuration = moment.duration(that.totalDuration, "seconds");

            that.formattedDuration = parsedTotalDuration.get('days') + " " + moment.utc(moment.duration(that.totalDuration, "seconds").asMilliseconds()).format("HH:mm:ss");
            newColl.push({
                Category: null,
                Code: "Total",
                Color: null,
                Count: that.totalCount,
                Description: null,
                Duration: that.formattedDuration,
                Id: -2,
                SecondsDuration: that.totalDuration,
                ProductionItem: null,
            })

            that.set(newColl).trigger('fetch', that, data);

        },

        setDataChart: function (coll) {
            // Group by category, summarize duration
            const groupedData = coll.reduce((accumulator, currentItem) => {
                const foundIndex = accumulator.findIndex(item => item.Category === currentItem.Category);

                if (foundIndex !== -1) {
                    accumulator[foundIndex].SecondsDuration += currentItem.SecondsDuration;
                } else {
                    accumulator.push({
                        Category: currentItem.Category,
                        SecondsDuration: currentItem.SecondsDuration,
                        Color: currentItem.Color
                    });
                }

                return accumulator;
            }, []);

            var that = this,
                progress = 0,
                delay = [],
                width = 0;
            _.each(groupedData, function (obj, i) {
                width = that.getPercent(obj.SecondsDuration);
                delay = { x: progress, y: 0, width: width, height: 16, fill: obj.Color };
                progress = progress + width;
                that.data.push(delay);
            });
        },

        getDataChart: function () {
            return this.data;
        },

        getPercent: function (val) {
            var percent = ((this.totalDuration != 0) ? val * 100 / this.totalDuration : 0)/100;
            return percent * this.divWidth;
        },
    })

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

    Screen.Views.Main = Backbone.Epoxy.View.extend({
        template: 'caster-delays-pareto'
        , id: 'caster-delays-pareto'
        , title: 'Delays Pareto'

        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a _refresh method to reset the view without erasing the DOM.
        , isCacheable: false
        , events: function () {
            return {
                'click #refreshBtn': this.refreshBtn_click,
                'click #searchViewBtn': this.searchViewBtn_click,
                "click .btn-export-to-excel": this.exportToExcel,
            };
        }

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

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

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

            this.bindEvents();
        }
        ,exportToExcel: function () {
            var that = this,
                params = this.model.toJSON();

            var crew = null;
            if (params.crewId) {
                if (params.crewId == '1') crew = 'A';
                if (params.crewId == '2') crew = 'B';
                if (params.crewId == '3') crew = 'C';
                if (params.crewId == '4') crew = 'D';
            }
                        
            var params = [
                { Name: '@From', Type: 'DATETIME', Value: new moment(params.from,'MM/DD/YYYY').format('YYYY-MM-DD'), },
                { Name: '@To', Type: 'DATETIME', Value: new moment(params.to, 'MM/DD/YYYY').format('YYYY-MM-DD'), },
                //{ Name: '@ProductionItemId', Type: "INT", Value: params.lineProductionItemId },
                //{ Name: '@ProductId', Type: "INT", Value: params.productId },
                { Name: '@ShiftId', Type: "INT", Value: params.shiftId === '-1' ? null : params.shiftId },
                { Name: '@delayCategoryId', Type: "INT", Value: params.delayCategoryId === "-1" ? null : params.delayCategoryId },
                { Name: '@CrewId', Type: "CHAR", Value: params.crewId ? crew : null },
                { Name: '@Timezone', Type: 'VARCHAR', Value: 'EDTIND', },

            ];
            var QP = new QueryParameters();

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


            var data = {
                Data: [],
                ConnectionStringName: 'APP',
                ExportMethod: 3,
                FileName: 'CAS-Delays-Pareto',
                TemplateFileFullPath: 'generic.xls',
                SQLDataSources: [
                    {
                        Name: 'data',
                        DatabaseParameters: {
                            DBEngine: 'SQLSERVER',
                            Procedure: app.DatabaseNames.MES + '.CAS.GetDelaysTimeSummary',
                            QueryParameters: QP,
                        },
                    },
                ]
            };

            /* -------------------------------------------------------- 1st Table ------------------------------------------------------------ */
            data.Data.push({
                SheetName: 'Data',
                RowsData: [{
                    CellsData:
                        [
                            { Column: 'A', Value: 'Name' },
                            { Column: 'B', Value: 'Furnace' },
                            { Column: 'C', Value: 'Category' },
                            { Column: 'D', Value: 'Duration' },
                            { Column: 'E', Value: 'Count' },
                            { Column: 'F', Value: 'Description' },                       


                        ],
                }],
                StartRowIndex: 1,
            });

            data.Data.push({
                SheetName: 'Data',
                RowsData: [],
                StartRowIndex: 2,
                DataSourceName: 'data',
                DataSourceTableIndex: 0,
                SQLCellsData:
                    [
                        { ExcelColumnName: 'A', SQLDataColumnName: 'Code', DataType: 'String' },
                        { ExcelColumnName: 'B', SQLDataColumnName: 'ProductionItem', DataType: 'String' },
                        { ExcelColumnName: 'C', SQLDataColumnName: 'Category', DataType: 'String' },
                        { ExcelColumnName: 'D', SQLDataColumnName: 'DurationDaysAndTime', DataType: 'String' },
                        { ExcelColumnName: 'E', SQLDataColumnName: 'Count', DataType: 'String' },
                        { ExcelColumnName: 'F', SQLDataColumnName: 'Description', DataType: 'String' }, 
                    ],
            });

            Core.Export.Excel(
                data,
                function (resp) {
                    try {
                        if ((resp) && (resp.Success == true) && (resp.Data)) {
                            location.href = app.foldersRoot + '/excel/' + resp.Data;

                        }
                        else {
                            if ((resp) && (resp.Message))
                                console.error(resp.Message);
                            else
                                console.error('Server response not valid.');
                        }
                    }
                    catch (Error) { console.error(Error); }
                    that.model.setExportButtonExporting(false);
                },
                function (resp) {
                    that.model.refreshProcesses();
                    that.model.setExportButtonExporting(false);
                    console.error(resp);
                }
            );
        }
        , render: function (container, viewParams) {
            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/custom-screens/' + this.template + '/';

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

                            var grid = new Backgrid.Grid({
                                className: 'backgrid table table-hover table-condensed',
                                columns: [
                                     {
                                        name: 'Code',
                                        label: app.translate(that, 'item_name_col_label'),
                                        editable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: 'string-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'ProductionItem',
                                        label: app.translate(that, 'prod_item_col_label'),
                                        editable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: 'string-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'Category',
                                        label: app.translate(that, 'item_category_col_label'),
                                        editable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: 'string-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'Duration',
                                        label: app.translate(that, 'item_duration_col_label'),
                                        editable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: 'string-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'Count',
                                        label: app.translate(that, 'item_count_col_label'),
                                        editable: false,
                                        cell: Backgrid.StringCell.extend({
                                            className: 'string-cell align-center-cell',
                                        }),
                                    },
                                    {
                                        name: 'actions',
                                        label: '',
                                        editable: false,
                                        sortable: false,
                                        cell: Backgrid.Cell.extend({
                                            className: 'color-cell',
                                            template: function () {
                                                if (this.model.toJSON().Code != 'Total')
                                                    return Handlebars.compile(that.$el.find('#progress_bar_template').html());
                                                else
                                                    return Handlebars.compile(that.$el.find('#progress_bar_template_2').html());
                                            },
                                            initialize: function () {
                                                Backgrid.Cell.prototype.initialize.apply(this, arguments);

                                            },
                                            render: function () {
                                                var that = this;
                                                this.$el.html(this.template());
                                                var percent = this.getPercent(that.model.collection.totalDuration, that.model.toJSON().SecondsDuration);

                                                if (that.model.toJSON().Code != 'Total') {
                                                    this.$el.find('svg .rect').attr("style", "fill: " + that.model.toJSON().Color);
                                                    this.$el.find('svg').attr("width", percent + '%');
                                                };

                                                return this;
                                            },
                                            getPercent: function (total, val) {
                                                return (total != 0) ? val*100/total : 0;
                                            },
                                        }),
                                    },

                                ],
                                collection: that.model.timeAccounts,
                                header: Backgrid.Header.extend({
                                    initialize: function (options) {
                                        Backgrid.Header.prototype.initialize.apply(this, arguments);
                                        this.listenTo(this.collection, 'backgrid:sort', this.collection_backgrid_sort);
                                    },

                                }),
                            });
                            that.$el.find('.items-grid-container').append(grid.render().el);
                            that.$el.find('.input-date').datepicker();

                            // refresh collection
                            that.refresh(); 
                        },
                        true,
                        customPath
                    );
                },
                customPath
            );
        }
        , referencesChart: function () {
            try {
                var that = this;
                setTimeout(
                    function () {
                        var svgCategoriesC1 = d3.select("#refs-screen-categories-c1").append("svg").attr("width", 550).attr("height", 30)
                        var svgCategoriesC2 = d3.select("#refs-screen-categories-c2").append("svg").attr("width", 550).attr("height", 30)
                        var categories = that.model.get('delayCategories').sort((a, b) => a.label.localeCompare(b.label));
                        var c1Categories = categories.filter(x => x.label.startsWith('C1'));
                        var c2Categories = categories.filter(x => x.label.startsWith('C2'));
                        var xRect = 62;
                        var xText = 60;

                        svgCategoriesC1.append("text")
                            .attr('y', 15)
                            .attr("x", 0)
                            .attr("font-size", 12)
                            .attr("fill", "#505050")
                            .attr("font-family", "Helvetica Neue,Helvetica,Arial,sans-serif")
                            .text('Caster 1:');

                        svgCategoriesC2.append("text")
                            .attr('y', 15)
                            .attr("x", 0)
                            .attr("font-size", 12)
                            .attr("fill", "#505050")
                            .attr("font-family", "Helvetica Neue,Helvetica,Arial,sans-serif")
                            .text('Caster 2:');
                        _.each(c1Categories, function (param) {
                            if (param.label == 'NOTDECLARED') {
                                param.description = 'N/D'
                            }
                            if (param.label == 'C1OperatingPlanned') {
                                param.description = 'Op. Planned'
                            }
                            if (param.label == 'C1OperatingUnplanned') {
                                param.description = 'Op. Unplanned'
                            }
                            svgCategoriesC1.append('rect')
                                .attr('x', xRect)
                                .attr('y', 0)
                                .attr('width', 15)
                                .attr('height', 15)
                                .attr('stroke', 'rgb(80, 80, 80)')
                                .attr('fill', param.color);

                            svgCategoriesC1.append("text")
                                .attr('y', 25)
                                .attr("x", xText)
                                .attr("font-size", 10)
                                .attr("fill", "#505050")
                                .attr("font-family", "Helvetica Neue,Helvetica,Arial,sans-serif")
                                .text(param.description);

                            xRect = xRect + 70;
                            xText = xText + 70;
                        });

                        var xRect = 62;
                        var xText = 60;
                        _.each(c2Categories, function (param) {
                            if (param.label == 'NOTDECLARED') {
                                param.description = 'N/D'
                            }
                            if (param.label == 'C2OperatingPlanned') {
                                param.description = 'Op. Planned'
                            }
                            if (param.label == 'C2OperatingUnplanned') {
                                param.description = 'Op. Unplanned'
                            }
                            svgCategoriesC2.append('rect')
                                .attr('x', xRect)
                                .attr('y', 0)
                                .attr('width', 15)
                                .attr('height', 15)
                                .attr('stroke', 'rgb(80, 80, 80)')
                                .attr('fill', param.color);

                            svgCategoriesC2.append("text")
                                .attr('y', 25)
                                .attr("x", xText)
                                .attr("font-size", 10)
                                .attr("fill", "#505050")
                                .attr("font-family", "Helvetica Neue,Helvetica,Arial,sans-serif")
                                .text(param.description);

                            xRect = xRect + 70;
                            xText = xText + 70;
                        });
                    },
                    100
                );
            }
            
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
        , refresh: function () {
            try {

                var params = this.model.toJSON();

                this.model.set({
                    hasData_TimeAccounts: false,
                    hasData_categoriesData: false,
                    hasData_delayCategoriesStackedData: false,
                    hasData_delayCategoriesStackedInfo: false,
                    isLoading_TimeAccounts: true,
                    isLoading_categoriesData: true,
                    isLoading_delayCategoriesStackedData: true,
                    isLoading_delayCategoriesStackedInfo: true,
                });


                var lineId = params.lineProductionItemId;
                var machineId = params.machineProductionItemId;
                var productionItemIdFilter = (lineId != -1) ? (machineId != -1) ? machineId : lineId : (machineId != -1) ? machineId : null;

                var productId = params.productId;
                productId = (productId != -1) ? productId : null;

                var shiftId = params.shiftId;
                shiftId = (shiftId != -1) ? shiftId : null;

                var crewId = params.crewId;
                crewId = (crewId != -1) ? crewId : null;
                
                var delayCategoryId = params.delayCategoryId;
                delayCategoryId = (delayCategoryId != -1) ? delayCategoryId : null;


                var fromMoment = moment(params.from, 'MM/DD/YYYY');
                var toMoment = moment(params.to, 'MM/DD/YYYY');
                if (params.from == params.to) toMoment.add(1, "d");
                

                this.model.fetchCategoriesData({
                    from:fromMoment.format("YYYY-MM-DD HH:mm:ss"),
                    to: toMoment.format("YYYY-MM-DD HH:mm:ss"),
                    productionItemIdFilter: productionItemIdFilter,
                    productId: productId,
                    shiftId: shiftId,
                    delayCategoryId: delayCategoryId,
                });


                this.model.fetchGridData({
                    from: fromMoment.format("YYYY-MM-DD HH:mm:ss"),
                    to: toMoment.format("YYYY-MM-DD HH:mm:ss"),
                    productionItemIdFilter: productionItemIdFilter,
                    productId: productId,
                    shiftId: shiftId,
                    crewId: crewId,
                    delayCategoryId: delayCategoryId,
                });

            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }

        , drawDelaysChart: function () {
            var that = this,
                delayCategoryStacks = [], 
                delayCatId = parseInt(this.model.get('delayCategoryId')),
                categories = [];

            _.each(this.model.delayCategoriesStackedData.models, function (obj) {
                delayCategoryStacks.push(obj.toJSON());
            });
            _.each(this.model.categoriesData.models, function (obj) {
                categories.push(obj.toJSON());
            });


            if (delayCatId == -1 || delayCatId == null) {
                categories;
            } else {
                var newCatId = _.findWhere(categories, { id: delayCatId }) //_.findWhere({ categories, id: delayCatId });
                categories = [];
                categories.push(newCatId);
            };
            var labels = _.uniq(_.pluck(delayCategoryStacks,"timestamp"));
            var chartData = {
                labels: labels,
                datasets: [],
            };
            
            var codes = _.uniq(_.pluck(categories,"id"));
            var datasets = []; 

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

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

            chartData.datasets = datasets;

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

        , instanceChart: function (chartData) {
            var that = this;
            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 %> %",
            });
        }

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

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

        , 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.listenTo(this.model.timeAccounts, 'fetch', this.timeAccounts_ready)
                .listenTo(this.model.categoriesData, 'fetch', this.categoriesData_ready)
                .listenTo(this.model.delayCategoriesStackedInfo, 'fetch', this.delayCategoriesStackedInfo_ready)
                .listenTo(this.model.delayCategoriesStackedData, 'fetch', this.delayCategoriesStackedData_ready)
                .listenTo(this.model,'delay-categories-fetched', this.referencesChart)
                .listenTo(this.model, 'change:isLoadingCanvas change:hasDataCanvas', this.canvas);
        }

        , setTotalBarGraph: function () {
            var data = this.model.timeAccounts.getDataChart();

            var chart = d3.select('.row-container-total')
                .attr("width", 300)
                .attr("height", 16)

            var bar = chart.selectAll("g")
                .data(data)
                .enter().append("g")

            bar.append("rect")
                .attr("width", function (d) { return d.width })
                .attr("height", function (d) { return d.height })
                .attr("transform", function (d) {
                    return "translate(" + d.x + "," + d.y + ")";
                })
                .style('fill', function (d) { return d.fill })
        }

        , canvas: function () {
            if (!this.model.get('isLoadingCanvas') && this.model.get('hasDataCanvas')) {
                this.drawDelaysChart();
            };
        }

        , delayCategoriesStackedData_ready: function () {
            try {
                var that = this;
                setTimeout(
                    function () {
                        that.model.set({
                            hasData_delayCategoriesStackedData: (that.model.delayCategoriesStackedData.length > 0),
                            isLoading_delayCategoriesStackedData: false,
                        });
                    },
                    100
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }

        , delayCategoriesStackedInfo_ready: function () {
            try {
                var that = this;
                setTimeout(
                    function () {
                        that.model.set({
                            hasData_delayCategoriesStackedInfo: (that.model.delayCategoriesStackedInfo.length > 0),
                            isLoading_delayCategoriesStackedInfo: false,
                        });
                    },
                    100
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }

        , timeAccounts_ready: function () {
            try {
                var that = this;
                setTimeout(
                    function () {
                        that.model.set({
                            hasData_TimeAccounts: (that.model.timeAccounts.length > 0),
                            isLoading_TimeAccounts: false,
                        });
                        if (that.model.get('hasData_TimeAccounts')) that.setTotalBarGraph();
                    },
                    100
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }

        , categoriesData_ready: function () {
            try {
                var that = this;
                setTimeout(
                    function () {
                        that.model.set({
                            hasData_categoriesData: (that.model.categoriesData.length > 0),
                            isLoading_categoriesData: false,
                        });
                    },
                    100
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
                       
        , UpdateURL: function () {
            try {
                var params = this.model.toJSON();
                app.router.navigate(
                    app.router.resolveURL(
                        app.router.currentModule,
                        _.extend(
                            {},
                            params,
                            {
                                start: new moment(params.from, "MM/DD/YYYY").format("YYYYMMDD"),
                                end: new moment(params.to, "MM/DD/YYYY").format("YYYYMMDD"),
                            }
                        ),
                        false
                    ),
                    { trigger: false, }
                );
            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
        , refreshBtn_click: function (model) {
            this.UpdateURL();
            this.refresh();
        }

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

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

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

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

            this.$el.hide();
            this.unbind();
            this.stopListening();
        },
        preRender: function () {
            app.models.subnavbar.set('subnavbar', false);
        },
        reRender: function (viewParams) {
            try {
                this.refresh();
            } catch (Error) { }
        },


    });

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

});