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

  "moment",

  "oee-module-assets/jquery-timepicker/jquery.timepicker",
  "backgrid/infinator",
],

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

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

    BatchSchedule.Models.Batch = Backbone.Model.extend({
        defaults: {
            id: null,
            lineProductionItemId: null,
            statusId: null,
            number: null,
            productId: null,
            shiftId: null,
            shift: null, 
            start: null,
            quantity: null,
            productionQuantity: null, 

            changed: false,
            prevAttrs: null,
            changedAttrs: [], 
            isNew: false, 
        },
    });

    BatchSchedule.Collections.Batches = Backbone.Collection.extend({
        model: BatchSchedule.Models.Batch,

        fixedcback_onFetch: null,
        fixedcback_onFetchComplete: null,

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

        initialize: function (opt) {
            this.options = _.extend({}, {
                products: [], 
            }, this.options); 

            this.fixedcback_onFetch = (opt && opt.onFetch) ? opt.onFetch : null;
            this.fixedcback_onFetchComplete = (opt && opt.onFetchComplete) ? opt.onFetchComplete : null;

            _.bindAll(this);
        },
        //comparator: function (a, b) {
        //    if (a.get("statusId") < b.get("statusId")) { return -1; }
        //    else if (a.get("statusId") > b.get("statusId")) { return 1; }
        //    else {
        //        var datea = moment(a.get("startDate") + " " + a.get("startTime"));
        //        var dateb = moment(b.get("startDate") + " " + b.get("startTime"));

        //        if (datea.isAfter(dateb)) return -1;
        //        else if (datea.isBefore(dateb)) return 1;
        //        else return 0; 
        //    }
        //}, 
        fetch: function (opt) {
            var ttimestamp = this.transaction_timestamp = new Date().getTime(),
            options = {
                //method: "set",
                async: true,
                data: {
                    productionItemId: null,
                    opened: true,
                    closed: true,
                    "new": true, 
                },
                callback: null,
                refresh: false,
            };

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

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

            this.isFetching = true;

            if (_.isFunction(this.fixedcback_onFetch))
                this.fixedcback_onFetch.call(this, this, _.extend({}, options));

            if (!options.data["new"] &&
                !options.data["closed"] &&
                !options.data["opened"]) {
                options.data["new"] = options.data["closed"] = options.data["opened"] = true;
            }

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

                this.fixedParameters = [
                    { Name: '@ProductionItemId', Type: 'INT', Value: options.data.productionItemId, },
                    { Name: '@StatusId', Type: 'INT', Value: null, },
                    { Name: '@New', Type: 'BIT', Value: options.data["new"], },
                    { Name: '@Opened', Type: 'BIT', Value: options.data.opened, },
                    { Name: '@Closed', Type: 'INT', Value: options.data.closed, },
                ];
            }

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

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

            //qp.Add("ProductionItemId", "INT", options.data.productionItemId);
            //qp.Add("StatusId", "INT", null);
            //qp.Add("New", "BIT", options.data["new"]);
            //qp.Add("Opened", "BIT", options.data.opened);
            //qp.Add("Closed", "BIT", options.data.closed);

            qp.Add("Timezone", "VARCHAR", app.models.user.get("timezoneCode"));

            var items = [];

            var ts = this.options.lastFetched = new Date().getTime();
            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetBatchSchedule", qp, {
                onSuccess: function (data) {
                    var itemsData = [];

                    if (Core.Object.Eval(data, "Table")) {
                        itemsData = data.Table;

                        var productionItems = data.Table1;
                        var statuses = data.Table2;
                        var products = data.Table3;
                        var shifts = data.Table4; 

                        for (var i = 0; i < itemsData.length; i++) {
                            var itemData = itemsData[i];
                            var batch = {
                                id: itemData.Id, 
                                lineProductionItemId: itemData.LineProductionItemId,
                                statusId: itemData.StatusId,
                                number: itemData.Number,
                                productId: itemData.ProductId,
                                shiftId: itemData.ShiftId,
                                shift: itemData.Shift, 
                                startDate: (moment(itemData.StartTime).isValid()) ? moment(itemData.StartTime).format("YYYY-MM-DD") : "",
                                startTime: (moment(itemData.StartTime).isValid()) ? moment(itemData.StartTime).format("HH:mm:ss") : "", 
                                quantity: itemData.Quantity,
                                productionQuantity: itemData.ProductionQuantity ? itemData.ProductionQuantity : 0,
                            };

                            items.push(batch);
                        }

                        that.options.productionItems = _.map(productionItems, function (m) { return [m.Name, m.Id.toString()]; });
                        that.options.statuses = _.map(statuses, function (m) { return [m.Name, m.Id.toString()]; });
                        //that.options.products = _.map(products, function (m) { return [m.Name, m.Id.toString()]; });
                        that.options.products = products; 
                        that.options.shifts = _.map(shifts, function (m) { return [m.Code, m.Id.toString()]; });
                    }

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

                    if (ttimestamp == that.transaction_timestamp) {
                        var changedItems = _.where(that.toJSON(), { changed: true });
                        var itemsList = [];

                        //keeping changes
                        _.each(items, function (m) {
                            var cm = null;
                            if (cm = _.findWhere(changedItems, { id: m.id }))
                                itemsList.push(cm);
                            else itemsList.push(m);
                        });

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

                        that[method](itemsList, { from: "fetch" });

                        that.isFetching = false;

                        if (_.isFunction(that.fixedcback_onFetchComplete))
                            that.fixedcback_onFetchComplete.call(that, that, data, options);
                    }

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

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

            return this;
        },
        getNextPage: function (options) {
            if (!this.isFetching) {
                this.currentPage++;
                options = (_.isObject(options)) ? options : {};
                this.fetch(options);
            }
        },
        resetPagination: function (force) {
            if (!this.isFetching || force == true) {
                this.currentPage = 1;
            } else {
                _.delay(this.resetPagination, 100);
            }
        },
        upsertItem: function (id, props, success, error) {
            var that = this;
            var QP = new QueryParameters();
            QP.Add("Id", "INT", id);

            for (var q in props) {
                QP.Add(props[q].name, props[q].type, props[q].value);
            }

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

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

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that, data);
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        updateItem: function (m, success, error) {
            this.upsertItem(m.get("id"), [
                { name: "ProductionItemId", type: "INT", value: m.get("lineProductionItemId") },
                { name: "Number", type: "VARCHAR", value: m.get("number") },
                { name: "ProductId", type: "INT", value: m.get("productId") },
                { name: "Quantity", type: "INT", value: m.get("quantity") },
                { name: "ShiftId", type: "INT", value: m.get("shiftId") },
                { name: "StatusId", type: "INT", value: m.get("statusId") },
                {
                    name: "StartTime", type: "DATETIME"
                    , value: moment(m.get("startDate") + " " + m.get("startTime")).format("YYYY-MM-DD HH:mm:ss")
                },
            ], success, error); 
        },
        callRemoveItem: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

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

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

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

                        if (success && _.isFunction(success))
                            success.call(this, that, ids);
                    },
                    function (ref) {
                        if (error && _.isFunction(error))
                            error.call(this, that);
                    }
                );
            }
        },
        addItem: function (m, success, error) {
            var that = this; 
            this.upsertItem(m.get("id"), [
                { name: "ProductionItemId", type: "INT", value: m.get("lineProductionItemId") },
                { name: "Number", type: "VARCHAR", value: m.get("number") },
                { name: "ProductId", type: "INT", value: m.get("productId") },
                { name: "Quantity", type: "INT", value: m.get("quantity") },
                { name: "ShiftId", type: "INT", value: m.get("shiftId") },
                {
                    name: "StartTime", type: "DATETIME"
                    , value: moment(m.get("startDate") + " " + m.get("startTime")).format("YYYY-MM-DD HH:mm:ss")
                },
            ], function (ref, ids) {
                m.set({ id: ids[0] });

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

    BatchSchedule.Models.Main = Backbone.Model.extend({
        defaults: {
            batches: null, 
        }, 
        initialize: function () {
            this.attributes.batches = new BatchSchedule.Collections.Batches({}); 
        }, 
    });

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

    BatchSchedule.Views.Main = Backbone.View.extend({
        template: "batch-schedule"
        , id: "batch-schedule"
        , title: "Batch Schedule"
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: false
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

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

            this.options.grids = {
                batches: null, 
            }; 

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

            this.model = model;

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

        events: {
            //"click .add-btn": "addRow", 
        }, 

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

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

            T.render.call(this, this.template, function (tmp) {
                if (!that.options.i18n) that.options.i18n = {};
                app.getI18NJed(that, that.template, function (i18nJED) {
                    //storing internationalization data
                    that.options.i18n[that.template] = i18nJED;
                    //start: before the view is visible, but the template was already loaded (not instanced nor appended)

                    //end:

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

                    that.options.MYREFERENCES.subviews.subnavbarControls = new BatchSchedule.Views.SubnavBarControls({
                        parent: that
                        , container: app.views.subnavbar.getSectionContainer(1, 12)
                        , events: {
                            "click .add-batch": that.addBatch, 
                        }
                    });

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

                    var datepicker_celleditor = Backgrid.CellEditor.extend({
                        tagName: "input",
                        attributes: {
                            type: "text"
                        },
                        events: {
                            //"blur": "saveOrCancel",
                            //"keydown": "saveOrCancel"
                        },
                        initialize: function (options) {
                            Backgrid.InputCellEditor.__super__.initialize.apply(this, arguments);

                            if (options.placeholder) {
                                this.$el.attr("placeholder", options.placeholder);
                            }
                        },
                        render: function () {
                            var that = this; 
                            var model = this.model;

                            this.$el.datepicker({
                                showOn: "focus"
                                , beforeShow: function () { }
                                , onClose: function () {
                                    that.edited($.Event("keydown", { keyCode: 27 }));
                                }
                                , onSelect: function () {
                                    that.save($.Event("keydown", { keyCode: 13 }));
                                }
                                , showOtherMonths: true
                                , selectOtherMonths: true
                                , dateFormat: "yy-mm-dd"
                                , minDate: 0
                            });

                            var cm = moment(this.formatter.fromRaw(model.get(this.column.get("name")), model), "YYYY-MM-DD"); 
                            if (cm.isValid()) {
                                this.$el.datepicker("setDate",
                                    cm.toDate()
                                );
                            }

                            //this.$el.val(this.formatter.fromRaw(model.get(this.column.get("name")), model));
                            return this;
                        },
                        save: function(e){
                            var formatter = this.formatter;
                            var model = this.model;
                            var column = this.column;

                            var command = new Backgrid.Command(e);
                            var blurred = e.type === "blur";

                            e.preventDefault();
                            e.stopPropagation();

                            var val = this.$el.datepicker("getDate");
                            val = moment(val).format("YYYY-MM-DD"); 
                            var newValue = formatter.toRaw(val, model);
                            if (_.isUndefined(newValue)) {
                                model.trigger("backgrid:error", model, column, val);
                            }
                            else {
                                model.set(column.get("name"), newValue);
                                //model.trigger("backgrid:edited", model, column, command);
                            }
                        },
                        edited: function (e) {
                            var model = this.model;
                            var column = this.column;

                            var command = new Backgrid.Command(e);

                            // undo
                            e.stopPropagation();
                            model.trigger("backgrid:edited", model, column, command);
                        }, 
                        postRender: function (model, column) {
                            if (column == null || column.get("name") == this.column.get("name")) {
                                // move the cursor to the end on firefox if text is right aligned
                                if (this.$el.css("text-align") === "right") {
                                    var val = this.$el.val();
                                    this.$el.focus().val(null).val(val);
                                }
                                else this.$el.focus();
                            }
                            return this;
                        }
                    });

                    var timepicker_celleditor = Backgrid.CellEditor.extend({
                        tagName: "input",
                        attributes: {
                            type: "text"
                        },
                        events: {
                            "blur": "saveOrCancel",
                            "keydown": "saveOrCancel"
                        },
                        initialize: function (options) {
                            Backgrid.InputCellEditor.__super__.initialize.apply(this, arguments);

                            if (options.placeholder) {
                                this.$el.attr("placeholder", options.placeholder);
                            }
                        },
                        render: function () {
                            var that = this;
                            var model = this.model;

                            this.$el.jqtimepicker({
                                'timeFormat': 'H:i:s',
                                'typeaheadHighlight': false,
                                'scrollDefault': 'now',
                                'disableTouchKeyboard': true,
                            });

                            this.$el.bind("change", _.bind(this.save, this));
                            this.$el.bind("hideTimepicker", _.bind(this.edited, this)); 

                            var cm = moment(this.formatter.fromRaw(model.get(this.column.get("name")), model), "HH:mm:ss");
                            if (cm.isValid()) {
                                this.$el.jqtimepicker('setTime', cm.toDate()); 
                            }

                            return this;
                        },
                        save: function (e) {
                            var formatter = this.formatter;
                            var model = this.model;
                            var column = this.column;

                            var command = new Backgrid.Command(e);
                            var blurred = e.type === "blur";

                            e.preventDefault();
                            e.stopPropagation();

                            var val = this.$el.jqtimepicker('getTime');
                            val = moment(val).format("HH:mm:ss");
                            var newValue = formatter.toRaw(val, model);
                            if (_.isUndefined(newValue)) {
                                model.trigger("backgrid:error", model, column, val);
                            }
                            else {
                                model.set(column.get("name"), newValue);
                                model.trigger("backgrid:edited", model, column, command);
                            }
                        },
                        edited: function (e) {
                            var model = this.model;
                            var column = this.column;

                            var command = new Backgrid.Command(e);

                            // undo
                            e.stopPropagation();
                            model.trigger("backgrid:edited", model, column, command);
                        },
                        postRender: function (model, column) {
                            if (column == null || column.get("name") == this.column.get("name")) {
                                // move the cursor to the end on firefox if text is right aligned
                                if (this.$el.css("text-align") === "right") {
                                    var val = this.$el.val();
                                    this.$el.focus().val(null).val(val);
                                }
                                else this.$el.focus();
                            }
                            return this;
                        }
                    });

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

                            if (changed) {
                                mode = "EDIT";
                            } else {
                                switch (status) {
                                    case 1:
                                        mode = 'NEW';
                                        break;
                                    case 2:
                                        mode = 'READONLY';
                                        break;
                                    case 3:
                                        mode = 'CLOSED';
                                        break;
                                }
                            }

                            var productionQty = this.model.get("productionQuantity");
                            //if (productionQty > 0) mode = "READONLY"; 

                            this.$el.html(this.template(
                                _.extend({
                                    mode: mode,
                                },
                                    ((mode == 'CLOSED') ? {
                                        batch_oee_href: app.router.resolveURL('!/oeeBatch(/:id)', { id: this.model.get('id') }, false, true), 
                                    } : {})
                                )
                            ));

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

                            //this.checkMode(); 
                            this.delegateEvents();
                            return this;
                        },
                        setEditMode: function (val) {
                            var mode = "NEW";
                            var status = this.model.get("statusId");

                            if (val) {
                                mode = "EDIT"
                            } else {
                                switch (status) {
                                    case 1:
                                        mode = 'NEW';
                                        break;
                                    case 2:
                                        mode = 'READONLY';
                                        break;
                                    case 3:
                                        mode = 'CLOSED';
                                        break;
                                }
                            }

                            this.$el.html(this.template(
                                _.extend({
                                    mode: mode,
                                },
                                    ((mode == 'CLOSED') ? {
                                        batch_oee_href: app.router.resolveURL('!/oeeBatch(/:id)', { id: this.model.get('id') }, false, true),
                                    } : {})
                                )
                            ));

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

                            this.delegateEvents();
                        },
                        setReadOnlyMode: function () {
                            var btnRemove = this.$el.find(".btn-remove");
                            var btnSave = this.$el.find(".btn-save-changes");
                            var btnDiscard = this.$el.find(".btn-discard-changes");

                            btnRemove.addClass("hide");
                            btnSave.addClass("hide");
                            btnDiscard.addClass("hide");
                        }, 
                        checkMode: function () {
                            var status = this.model.get("statusId");

                            if (this.model.get("isNew"))
                                this.setEditMode(true);
                        }, 
                        checkChanges: function (m, v, opt) {
                            var source = "UNKNOWN";
                            source = (opt != null && opt != undefined && opt.from) ? opt.from : source;

                            if (source == "BCHANGED") {
                                this.setEditMode(v); 
                            }
                        }, 
                        bindEvents: function () {
                            this.listenTo(this.model, "change:changed", this.checkChanges); 
                        },
                    });

                    var SelectCell_highlightChanges = Backgrid.SelectCell.extend({
                        initialize: function () {
                            Backgrid.SelectCell.prototype.initialize.apply(this, arguments);
                            this.bindEvents();
                            
                            this.checkIsNew();
                            this.highlightOnChange();
                        },
                        blueOnNew: true, 
                        formatter: _.extend({}, Backgrid.SelectFormatter.prototype, {
                            fromRaw: function (rawValue, model) {
                                return _.isArray(rawValue) ? rawValue : rawValue != null ? [rawValue.toString()] : [];
                            },
                            toRaw: function (formattedValue, model) {
                                try {
                                    var val = parseInt(formattedValue);
                                    if (val != -1) return parseInt(formattedValue);
                                    else return undefined;
                                } catch (error) {
                                    return undefined;
                                }
                            },
                        }),
                        checkIsNew: function () {
                            if (this.model.get("isNew") && this.column.get("editable") && this.blueOnNew) {
                                this.$el.css("background-color", "#D0FCFE");
                            }
                        },
                        highlightOnChange: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                if (!this.model.get("isNew"))
                                    this.$el.css("background-color", "");
                            }
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change:changedAttrs", this.highlightOnChange); 
                        }, 
                    }); 

                    var StringCell_highlightChanges = Backgrid.StringCell.extend({
                        initialize: function () {
                            Backgrid.StringCell.prototype.initialize.apply(this, arguments);
                            this.bindEvents();

                            this.checkIsNew();
                            this.highlightOnChange();
                        },
                        checkIsNew: function () {
                            if (this.model.get("isNew") && this.column.get("editable")) {
                                this.$el.css("background-color", "#D0FCFE");
                            }
                        }, 
                        highlightOnChange: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                if (!this.model.get("isNew"))
                                    this.$el.css("background-color", "");
                            }
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change:changedAttrs", this.highlightOnChange);
                        },
                    });

                    var IntegerCell_highlightChanges = Backgrid.IntegerCell.extend({
                        initialize: function () {
                            Backgrid.IntegerCell.prototype.initialize.apply(this, arguments);
                            this.bindEvents();

                            this.checkIsNew();
                            this.highlightOnChange();
                        },
                        checkIsNew: function () {
                            if (this.model.get("isNew") && this.column.get("editable")) {
                                this.$el.css("background-color", "#D0FCFE");
                            }
                        },
                        highlightOnChange: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                if (!this.model.get("isNew"))
                                    this.$el.css("background-color", "");
                            }
                        },
                        bindEvents: function () {
                            this.listenTo(this.model, "change:changedAttrs", this.highlightOnChange);
                        },
                    });

                    var columns = [
                        {
                            name: "lineProductionItemId",
                            label: app.translate(that, "line_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            cell: SelectCell_highlightChanges.extend({
                                //className: "select-cell align-center-cell description"
                                optionValues: function () {
                                    var defaults = [["Choose ...", "-1"]];
                                    return _.union(defaults, that.model.get("batches").options.productionItems);
                                },
                            })
                        },
                        {
                            name: "number",
                            label: app.translate(that, "number_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            cell: StringCell_highlightChanges.extend({
                                className: "string-cell align-center-cell number"
                            }),
                        },
                        {
                            name: "productId",
                            label: app.translate(that, "product_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            required: true, 
                            cell: SelectCell_highlightChanges.extend({
                                //className: "select-cell align-center-cell description"
                                optionValues: function () {
                                    var lineProductionItemId = this.model.get("lineProductionItemId"); 
                                    var defaults = [["Choose ...", "-1"]]; 
                                    return _.union(defaults, _.map(_.filter(that.model.get("batches").options.products, function (t) {
                                        return (t.LineProductionItemId == lineProductionItemId); 
                                    }), function (m) {
                                        return [m.Name, m.Id.toString()];
                                    }));
                                },
                            }),
                        },
                        {
                            name: "quantity",
                            label: app.translate(that, "qty_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            cell: IntegerCell_highlightChanges.extend({
                                className: "integer-cell align-center-cell quantity"
                            }),
                        },
                        {
                            name: "productionQuantity",
                            label: app.translate(that, "production_qty_label"),
                            editable: false, 
                            sortable: false,
                            cell: Backgrid.IntegerCell.extend({
                                className: "integer-cell align-center-cell productionQuantity", 
                            }), 
                        },
                        {
                            name: "startDate",
                            label: app.translate(that, "startDate_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false; 
                            },
                            sortable: false,
                            cell: StringCell_highlightChanges.extend({
                                editor: datepicker_celleditor,
                                className: "string-cell align-center-cell startDate"
                            }),
                        },
                        {
                            name: "startTime",
                            label: app.translate(that, "startTime_label"),
                            editable: function (a, b, c) {
                                if ((a.get("statusId") == 1 && (!a.get("productionQuantity") || a.get("productionQuantity") == 0)) || !a.get("statusId"))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            cell: StringCell_highlightChanges.extend({
                                editor: timepicker_celleditor,
                                className: "string-cell align-center-cell startTime", 
                            }),
                        },
                        {
                            name: "shift",
                            label: app.translate(that, "shift_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                className: "string-cell align-center-cell shift",
                            }),
                        },
                        {
                            name: "statusId",
                            label: app.translate(that, "status_label"),
                            editable: function (a, b, c) {
                                if (a.get("statusId") == 3
                                    || (a.get("statusId") == 1 && a.get("productionQuantity") > 0))
                                    return true;
                                else return false;
                            },
                            sortable: false,
                            cell: SelectCell_highlightChanges.extend({
                                //className: "select-cell align-center-cell description"
                                optionValues: function () {
                                    var that1 = this; 
                                    var defaults = [["Choose ...", "-1"]];
                                    return _.union(defaults,
                                        _.map(_.filter(that.model.get("batches").options.statuses, function (s) {
                                            if (s[0] == "OPEN" && that1.model.get("statusId") != 2)
                                                return false
                                            else return true; 
                                        }), function (s) {
                                            return [app.translate(that, (s[0] + "_status").toUpperCase()), s[1]];
                                        })
                                    );
                                },
                                blueOnNew: false, 
                            })
                        },
                        //{
                        //    name: "shiftId",
                        //    label: app.translate(that, "shift_label"),
                        //    editable: true,
                        //    sortable: false,
                        //    cell: SelectCell_highlightChanges.extend({
                        //        //className: "select-cell align-center-cell description"
                        //        optionValues: function () {
                        //            var defaults = [["Choose ...", "-1"]];
                        //            return _.union(defaults, that.model.get("batches").options.shifts);
                        //        },
                        //    }), 
                        //},
                        {
                            name: "actions",
                            label: "",
                            editable: false,
                            sortable: false,
                            cell: ActionsCell
                        },
                    ];

                    var grid = that.options.grids.batches = new Backgrid.Grid({
                        className: "backgrid table",
                        columns: columns,
                        collection: that.model.get("batches"),
                        footer: Backgrid.Extension.Infinator.extend({
                            scrollToTop: false,
                        }),
                    });

                    that.$el.find(".batch-schedule-grid-container").append(grid.render().el);
                    that.options.MYREFERENCES.subviews.subnavbarControls.render();

                    //appending view to the main container
                    that.append(thatContainer, that.$el);
                    that._startAutoRefresh({
                        showLoading: true,
                        refresh: true, 
                        callback: function () {
                            that.options.MYREFERENCES.subviews.subnavbarControls.model.set({
                                lines: _.map(that.model.get("batches").options.productionItems, function (t) {
                                    return { label: t[0], value: t[1] };
                                }),
                            });

                            that.listenTo(that.options.MYREFERENCES.subviews.subnavbarControls.model, "change", that.subnavbarChanged);
                        }, 
                    });
                }, true, customPath); 
            }, customPath, "main_template");
        }

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

        , actionOnRow: function (model, action) {
            action = action.toUpperCase(); 
            switch (action) {
                case "DELETE":
                    this.removeBatch(model); 
                    break;
                case "SAVECHANGES":
                    this.saveBatch(model); 
                    break;
                case "DISCARDCHANGES":
                    this.discardChanges(model); 
                    break; 
            }
        }

        , addBatch: function(a, b, c){
            this.model.get("batches").unshift(new BatchSchedule.Models.Batch({
                id: -1, 
                isNew: true
            })); 
        }

        , removeBatch: function (m) {
            var that = this; 
            var id = m.get("id");
            this.model.get("batches").removeItem(id,
                function () {
                    that.refresh(); 
                },
                function () {
                    that.refresh(); 
                }
            );
        }

        , saveBatch: function (m) {
            var that = this;
            var id = m.get("id");
            var isNew = m.get("isNew"); 

            if (!isNew) {
                this.model.get("batches").updateItem(m,
                    function () {
                        m.set({ changed: false, prevAttrs: null, changedAttrs: [] }, { from: "BCHANGED" });
                        that.refresh();
                    },
                    _.bind(that.handleErrors, that)
                );
            } else {
                this.model.get("batches").addItem(m,
                    function () {
                        m.set({ changed: false, prevAttrs: null, changedAttrs: [], isNew: false }, { from: "BCHANGED" }); 
                        that.refresh(); 
                    },
                    _.bind(that.handleErrors, that)
                ); 
            }
        }

        , handleErrors: function (a, b, c) {
            var that = this;

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

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

            app.views.topMessages.showMessage(error_message); 

            this.refresh(); 
        }

        , discardChanges: function (m) {
            if (m.get("isNew")) {
                m.collection.remove(m); 
            } else {
                m.set(_.extend(m.get("prevAttrs"), { prevAttrs: null, changedAttrs: [] }), { from: "BCHANGED" });
                this.refresh();
            }
        }

        , subnavbarChanged: _.debounce(function (a, b, c) {
            var that = this;
            this._autoRefresh({ showLoading: true, showLoadingDelay: 100, refresh: true });
        }, 500)

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

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

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

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

            this.refresh(_.extend({}, opt, {
                callback: function () {
                    if (that.options.MYREFERENCES.autoRefresh.enabled == true) {
                        that.options.MYREFERENCES.autoRefresh.toid = setTimeout(that._autoRefresh, 5000);
                    }

                    if (opt && opt.callback && _.isFunction(opt.callback))
                        opt.callback.call(that, that);
                },
            }));
        }

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

        , refresh: function (opt) {
            try {
                var that = this;
                var fetched = false;

                if (opt && opt.showLoading) {
                    setTimeout(function () {
                        if (!fetched) that.showLoading(true);
                    }, opt.showLoadingDelay ? opt.showLoadingDelay : 500);
                }

                var subnavbarModel = that.options.MYREFERENCES.subviews.subnavbarControls.model; 

                this.model.get("batches").fetch({
                    data: {
                        productionItemId: (subnavbarModel.get("lineProductionItemId") == -1) ? null : subnavbarModel.get("lineProductionItemId"),
                        "new": subnavbarModel.get("newBatches"),
                        opened: subnavbarModel.get("openBatches"),
                        closed: subnavbarModel.get("closedBatches"), 
                    },
                    callback: function () {
                        fetched = true;
                        that.showLoading(false);

                        if (opt && opt.callback && _.isFunction(opt.callback))
                            opt.callback.call(that, that);
                    },
                    refresh: (opt && opt.refresh) ? true : false,
                    set: true,
                });
            } catch (Error) { }
        }

        , showLoading: function (val) {
            var loadingPoster = this.$el.find(".loading-poster");
            var gridContainer = this.$el.find(".batch-schedule-grid-container");

            if (val) {
                gridContainer.addClass("hide");
                loadingPoster.removeClass("hide");
            } else {
                loadingPoster.addClass("hide");
                gridContainer.removeClass("hide");
            }
        }

        , batchChanged: function (m, opt, opt2) {
            var that = this;
            var source = "UNKNOWN";
            source = (opt != null && opt != undefined && opt.from) ? opt.from : source;

            if (source == "UNKNOWN") {
                var prevAttrs = m.get("prevAttrs");
                if (!prevAttrs) prevAttrs = _.omit(m.previousAttributes(), "prevAttrs"); 

                m.set({
                    changed: true,
                    prevAttrs: prevAttrs, 
                }, { from: "BCHANGED" });

                m.set({
                    "changedAttrs": _.union(m.get("changedAttrs"), _.keys(m.changed)), 
                }, { from: "BCHANGED" });
            }
        }

        , batchLineChanged: function (m, opt, opt2) {
            var that = this;
            var lineProductionItemId = m.get("lineProductionItemId"); 
            var currentProductId = m.get("productId"); 

            if ((_.filter(that.model.get("batches").options.products, function (t) {
                return t.LineProductionItemId == lineProductionItemId && t.Id == currentProductId
            })).length == 0) {
                m.set("productId", null);
            }
        }

        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
            this.listenTo(this.model.get("batches"), "change", this.batchChanged);
            this.listenTo(this.model.get("batches"), "change:lineProductionItemId", this.batchLineChanged); 
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
            var that = this; 
            if (that.options.grids.batches.footer &&
                that.options.grids.batches.footer.setEnabled) {
                that.options.grids.batches.footer.setEnabled(false);
            }
        }

        , 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._stopAutoRefresh();

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

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

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

        , reRender: function () {
        }
    });

    BatchSchedule.Views.BatchScheduleModal = Backbone.View.extend({
        template: "batch-schedule"
        , id: "batch-schedule"
        , title: ""
        , className: "modal hide fade modal-wider"
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: true
        , initialize: function () {

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

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

            this.options._isRendered = false;
            this.options.sliders = {};

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

                this.trigger('cancel');

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

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

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

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

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

                    that.options._isRendered = true;

                }, true, customPath);

            }, customPath, "batch_schedule_modal_template");
        }

        , refresh: function () {
            try {
            } catch (Error) { }
        }

        , show: function () {

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

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

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

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

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

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

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

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

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

            return this;

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

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

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

                self.trigger('hidden');

                self.close();
            });

            $el.modal('hide');
        }

        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily

            //rendering as soon as getting data in the model
        }

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

        , preRender: function () {
        }

        , reRender: function () {
        }
    });

    BatchSchedule.Models.SubnavBarControls = Backbone.Model.extend({
        defaults: {
            lineProductionItemId: null,
            newBatches: true,
            openBatches: true, 
            closedBatches: false,

            lines: [],
        },
    }); 

    //subview for the subnavbar controls
    BatchSchedule.Views.SubnavBarControls = Backbone.Epoxy.View.extend({
        id: "batch-schedule-subnavbar-controls"
        , title: ""
        , template: "batch-schedule"
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            this.options.MYREFERENCES = {};

            this.model = (this.model) ? this.model : new BatchSchedule.Models.SubnavBarControls(); 

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

        events: {
        },

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

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

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

                    var ctx = {
                        editable: (($.inArray("AdminUserRole", app.models.user.get("roles")) != -1
                            || $.inArray("SupervisorUserRole", app.models.user.get("roles")) != -1) ? true : false),
                    };

                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp(
                        _.extend({}, ctx, (that.model) ? that.model.toJSON() : {})
                    ));

                    that.applyBindings();

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

        }

        , append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }
        , refresh: function () {
            try {

            } catch (Error) { }
        }

        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
        }

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

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

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

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

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

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

        , reRender: function () {
        }
    });

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

});
