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

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

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

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

  "modules/modal",

  "backgrid",

  "moment",

  'js/jquery.timepicker/jquery.timepicker',
],

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

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

    Recipes.Views.RecipesList = Backbone.View.extend({
        template: "recipes"
        , id: "recipes-list"
        , title: "Recipes"
        //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 Recipes.Models.RecipesList();

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

            this.model = model;

            this.startDownloadedRecipesAutoRefresh();

            this.options.MYREFERENCES.subviews.subnavbarControls = new Recipes.Views.SubnavBarControls({
                parent: this
                , container: app.views.subnavbar.getSectionContainer(1, 12)
                , events: {
                    "click .add-item": _.bind(this.addNew, this),
                    "click .btn-download-all-recipes": _.bind(this.downloadAllRecipes, this), 
                }
            });

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

        downloadedRecipesChanged: function (a, b, c, d) {
            var that = this;
            var model = this.model.get("downloadedRecipes");
            var listmodel = this.model.get("recipes"); 
            var list = this.model.get("recipes").toJSON(); 
            _.each(list, function(t){
                t.originalName = t.name; 
                t.name = (_.isString(t.name)) ? t.name.toUpperCase() : null; 
            }); 

            listmodel.forEach(function (t) { t.set("status", null) });

            if (!model.findWhere({ id: -1 })) {
                model.forEach(function (t) {
                    var inList = _.findWhere(list, { name: t.get("name") });
                    if (inList) {
                        var inModel = listmodel.findWhere({ name: inList.originalName });
                        inModel.set("status", "DOWNLOADING");
                    }
                });
            } else {
                listmodel.where({active: true}).forEach(function (t) { t.set("status", "DOWNLOADING"); });
            }
        }, 

        startDownloadedRecipesAutoRefresh: function () {
            if (this.options.MYREFERENCES.downloadedRecipes.toid) {
                clearTimeout(this.options.MYREFERENCES.downloadedRecipes.toid);
                this.options.MYREFERENCES.downloadedRecipes.toid = null;
            }

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

            this.downloadedRecipesAutoRefresh();
        }, 

        downloadedRecipesAutoRefresh: function () {
            this.model.get("downloadedRecipes").fetch(); 

            if (this.options.MYREFERENCES.downloadedRecipes.enabled = true) {
                this.options.MYREFERENCES.downloadedRecipes.toid = setTimeout(_.bind(this.downloadedRecipesAutoRefresh, this), 3000);
            }
        }, 

        stopDownloadedRecipesAutoRefresh: function(){
            this.options.MYREFERENCES.downloadedRecipes.enabled = false; 
            
            if (this.options.MYREFERENCES.downloadedRecipes.toid){
                clearTimeout(this.options.MYREFERENCES.downloadedRecipes.toid); 
                this.options.MYREFERENCES.downloadedRecipes.toid = null; 
            }
        }, 

        events: {
        },

        render: function (container) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.options.container;
            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = "/app/custom-screens/scrapyard/recipes/";

            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;

                    var ctx = {
                        editable: (($.inArray("AdminUserRole", app.models.user.get("roles")) != -1
                            || $.inArray("SupervisorUserRole", app.models.user.get("roles")) != -1) ? true : false),
                        permissions: {
                            edit: (($.inArray("scrapyard_recipes_item_edit", app.models.user.get("roles")) != -1) ? true : null),
                            download_all: (($.inArray("scrapyard_recipes_download_all", app.models.user.get("roles")) != -1) ? true : null),
                            download_recipe: (($.inArray("scrapyard_recipes_download", app.models.user.get("roles")) != -1) ? true : null),
                        },
                    };


                    that.$el.html(tmp(_.extend({}, ctx, (that.model) ? that.model.toJSON() : {})));

                    var columns = [
                        {
                            name: "name",
                            label: app.translate(that, "name_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell",
                            })
                        },
                        {
                            name: "gradeName",
                            label: app.translate(that, "grade_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell",
                            })
                        },
                        {
                            name: "chargesQty",
                            label: app.translate(that, "chargesQty_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell",
                            })
                        },
                        {
                            name: "active",
                            label: app.translate(that, "active_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.Cell.extend({
                                className: "align-center-cell",
                                initialize: function () {
                                    Backgrid.Cell.prototype.initialize.apply(this, arguments);
                                    this.listenTo(this.model, "change:status", this.render); 
                                }, 
                                render: function () {
                                    if (this.model.get("status") == "DOWNLOADING") {
                                        this.$el.html("<span>" + app.translate(that, "downloading_status_label") + "</span>"); 
                                    } else {
                                        if (this.model.get("active")) {
                                            this.$el.html('<i style="font-size:16px;margin-left:1px;top:2px;position:relative;" class="fw-icon-check"></i>');
                                        } else {
                                            this.$el.html('<i style="font-size:16px;top:2px;position:relative;" class="fw-icon-check-empty"></i>');
                                        }
                                    }
                                    return this; 
                                }, 
                            })
                        },
                        //{
                        //    name: "status",
                        //    label: "",
                        //    editable: false,
                        //    sortable: false,
                        //    cell: Backgrid.StringCell.extend({
                        //        orderSeparator: '',
                        //        className: "string-cell align-center-cell",
                        //    })
                        //},
                    ];

                    var CustomRow = Backgrid.Row.extend({
                        events: {
                            "click": "onClick"
                        },
                        className: "clickeable-row",
                        render: function () {
                            Backgrid.Row.prototype.render.apply(this, arguments);
                            this.$el[(this.model.get("active")) ? "removeClass" : "addClass"]("disabled");
                            return this; 
                        }, 
                        onClick: function (e) {
                            var t_that = this; 
                            var target = $(e.target);
                            var data_prevent = (target.closest("[data-preventclick]").length > 0) ? target.closest("[data-preventclick]").data("preventclick") : false;

                                var continue_fn = function () {
                                    app.router.navigate(app.router.resolveURL(app.router.currentModule, {
                                        action: "edit",
                                        recipeId: t_that.model.get("id"),
                                    }, false), { trigger: true });
                                }; 

                                that.getRecipesBeingDownloaded(function (ref, status, data) {
                                    if (status == "success") {
                                        var all = (_.findWhere(data, { id: -1 })) ? true : false;
                                        var thisRecipe = (_.findWhere(data, { name: t_that.model.get("name").toUpperCase() })) ? true : false;

                                        if (all || thisRecipe) {
                                            app.views.topMessages.showMessage(
                                                app.translate(ref, "RECIPE_BEING_DOWNLOADED_RECIPE_STATUS"), { stay: 3000 }
                                            );
                                        } else {
                                            continue_fn(); 
                                        }
                                    } else {
                                        continue_fn(); 
                                    }
                                });
                        }
                    });

                    // Initialize a new Grid instance
                    var recipes_grid;
                    recipes_grid = new Backgrid.Grid({
                        row: CustomRow, 
                        className: "backgrid table table-hover",
                        columns: columns,
                        collection: that.model.get("recipes"),
                    });

                    that.$el.find(".recipes-grid-container").append(recipes_grid.render().el);

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

                    that.options.MYREFERENCES.subviews.subnavbarControls.render();

                    that._startAutoRefresh({});
                }, true, customPath);
            }, customPath, "recipe_list_template");
        }

        , getRecipesBeingDownloaded: function(callback){
            var that = this; 

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

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetRecipesBeingDownloaded", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table; 

                        var recipes = []; 
                        for (var i = 0, len = data.length; i < len; i++) {
                            recipes.push({
                                id: data[i].Id,
                                name: data[i].Name && _.isString(data[i].Name) ? data[i].Name.toUpperCase() : null, 
                            }); 
                        }

                        if (callback && _.isFunction(callback))
                            callback.call(that, that, "success", recipes);
                    } else {
                        if (callback && _.isFunction(callback))
                            callback.call(that, that, "error", data);
                    }
                },
                onError: function (data) {
                    if (callback && _.isFunction(callback))
                        callback.call(that, that, "error", data);
                },
                Secured: true,
            }, app.ConnectionStrings.app);
        }

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

            var continue_fn = function () {
                app.router.navigate(app.router.resolveURL(app.router.currentModule, {
                    action: "new",
                }, false), { trigger: true });
            };

            that.getRecipesBeingDownloaded(function (ref, status, data) {
                if (status == "success") {
                    if (data.length > 0) {
                        app.views.topMessages.showMessage(
                            app.translate(ref, "RECIPES_BEING_DOWNLOADED_RECIPE_STATUS"), { stay: 3000 }
                        );
                    } else {
                        continue_fn(); 
                    }
                } else {
                    continue_fn(); 
                }
            });
        }

        , downloadAllRecipes: function () {
            var that = this;
            var modal = new Modal.Views.Main({
                id: "download-all-recipes",
                title: app.translate(that, "download_all_recipes_title"),
                message: app.translate(that, "continue_download_all_recipes_body"),
                allowCancel: true,
                buttons_type: "CONTINUE-CANCEL"
            });

            //var modal_loading = new Modal.Views.Main({
            //    id: "downloading-all-recipes",
            //    content: '<span>hola</span>',
            //    className: "modal hide", 
            //    allowCancel: false,
            //    buttons_type: "CUSTOM-BUTTONS"
            //});

            modal.on("continue", function () {
                that.downloadRecipes({
                    ids: null, 
                    callback: function (ref, status, data) {
                        that.downloadRecipesCallback(ref, status, data);
                    }
                }); 
            });

            modal.show();
        }
        , downloadRecipes: function (e) {
            var that = this;
            var QP = new Core.Database.QueryParameters();
            QP.Add("Ids", "VARCHAR", e && e.ids ? e.ids : null);

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.DownloadRecipes", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table[0];

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, "success", data);
                    }
                },
                onError: function (data) {
                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error", data);
                },
                Secured: true,
            }, app.ConnectionStrings.app);
        }
        , downloadRecipesCallback: function(ref, status, data){
            if (status == "success") {
                if (data && data.Status) {
                    app.views.topMessages.showMessage(
                        app.translate(this, data.Status.toUpperCase() + "_DOWNLOAD_STATUS"), { stay: 3000 }
                    );
                } else {
                    app.views.topMessages.showMessage(
                        app.translate(this, "download_recipe_generic_error"), { stay: 3000 }
                    );
                }
            } else {
                app.views.topMessages.showMessage(
                    app.translate(this, "download_recipe_generic_error"), { stay: 3000 }
                );
            }
        }
        , recipeCreated: function (that, res) {
            if (res != "error") {
                var id = res;
            }
        }
        , _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) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }

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

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

        , filtersChanged: _.debounce(function () {
            this._autoRefresh({ });
        }, 500)
 

        , refresh: function (opt) {
            try {
                var that = this;
                var subnavbarModel = this.options.MYREFERENCES.subviews.subnavbarControls.model;

                subnavbarModel.get("grades").getOrFetch(function () {
                    var gradeGroupId = subnavbarModel.get("gradeGroupId");
                    var gradeId = subnavbarModel.get("gradeId");
                    var gradesList = subnavbarModel.get("gradesList");
                    var activeFilter = subnavbarModel.get("activeFilter");
                    var chargesQty = subnavbarModel.get("chargesQty");

                    //var groupId = (gradeGroupId == -1) ? null : (gradeId == -1) ? gradeGroupId : null;
                    //var gradeIds = (gradeId == -1 && gradeGroupId == -1) ? null : (gradeId == -1) ? _.pluck(gradesList, "value").join(',') : gradeId;

                    var groupId = null;
                    var gradeIds = null; 

                    that.model.get("grades").getOrFetch(function () {
                        that.model.get("recipes").fetch({
                            data: {
                                grades: that.model.get("grades"),
                            },
                            params: {
                                groupId: groupId,
                                gradeIds: gradeIds,
                                active: activeFilter,
                                chargesQty: chargesQty, 
                            },
                            callback: function () {
                                if (opt && opt.callback && _.isFunction(opt.callback))
                                    opt.callback.call(that, that);
                            },
                        });
                    }, (_.isBoolean(opt.forceFetchGrades)) ? opt.forceFetchGrades : false);
                }, (_.isBoolean(opt.forceFetchGrades)) ? opt.forceFetchGrades : false); 
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }

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

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }

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

            this.listenTo(that.options.MYREFERENCES.subviews.subnavbarControls.model, "change:gradeGroupId", this.filtersChanged);
            this.listenTo(that.options.MYREFERENCES.subviews.subnavbarControls.model, "change:gradeId", this.filtersChanged);
            this.listenTo(that.options.MYREFERENCES.subviews.subnavbarControls.model, "change:activeFilter", this.filtersChanged);
            this.listenTo(that.options.MYREFERENCES.subviews.subnavbarControls.model, "change:chargesQty", this.filtersChanged);

            this.listenTo(this.model.get("downloadedRecipes"), "add", _.debounce(this.downloadedRecipesChanged, 100));
            this.listenTo(this.model.get("downloadedRecipes"), "remove", _.debounce(this.downloadedRecipesChanged, 100));
            this.listenTo(this.model.get("downloadedRecipes"), "change", _.debounce(this.downloadedRecipesChanged, 100));
            this.listenTo(this.model.get("downloadedRecipes"), "reset", _.debounce(this.downloadedRecipesChanged, 100));
        }

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

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

        , 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.stopDownloadedRecipesAutoRefresh(); 
            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 () {
            this.startDownloadedRecipesAutoRefresh();
            this._startAutoRefresh({
                forceFetchGrades: true, 
            });
        }
    });

    Recipes.Models.ChargeDetail = Backbone.Model.extend({
        defaults: {
            id: null,
            scrapTypeId: null,
            cost: null,
            weight: null,
            order: null, 
        }, 
    }); 

    Recipes.Collections.ChargeDetails = Backbone.Collection.extend({
        model: Recipes.Models.ChargeDetail,
        initialize: function () {
            this.bindEvents(); 
        },
        bindEvents: function () {
            this.listenTo(this, "add", _.debounce(this.checkOrder));
            this.listenTo(this, "remove", _.debounce(this.checkOrder));
            this.listenTo(this, "reset", _.debounce(this.checkOrder));
            //this.listenTo(this, "change", _.debounce(this.checkOrder));
        },
        checkOrder: function () {
            this.each(function (m, n) {
                m.set("order", n + 1); 
            }); 
        }, 
    }); 

    Recipes.Models.Charge = Backbone.Model.extend({
        defaults: {
            number: null, 
            details: null,
            total: null, 
        },
        initialize: function () {
            this.attributes.details = new Recipes.Collections.ChargeDetails();

            this.listenTo(this.get("details"), "add", this.checkTotalWeight);
            this.listenTo(this.get("details"), "remove", this.checkTotalWeight);
            this.listenTo(this.get("details"), "change", this.checkTotalWeight);
            this.listenTo(this.get("details"), "reset", this.checkTotalWeight);

            this.checkTotalWeight(); 
        },
        checkTotalWeight: function () {
            var total = this.get("details").reduce(function(memo, m){
                return memo + m.get("weight"); 
            }, 0); 
            this.set("total", total); 
        }, 
    });

    Recipes.Models.Grade = Backbone.Model.extend({
        defaults: {
            id: null,
            groupId: null,
            groupName: null, 
            name: null,
        },
    });

    Recipes.Collections.Grades = Backbone.Collection.extend({
        model: Recipes.Models.Grade,
        initialize: function () {
            this.options = _.extend({}, this.options, {
                fetched: false,
            });
        }, 
        fetch: function (opt) {
            var that = this;
            var QP = new Core.Database.QueryParameters();

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetGrades", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table;

                        var items = [];
                        _.each(data, function (t) {
                            var item = {
                                id: t["Id"],
                                name: t["Name"],
                            };

                            items.push(item);
                        });

                        that.set(items);

                        that.options.fetched = true;

                        if (opt && opt.callback && _.isFunction(opt.callback))
                            opt.callback.call(that, that);
                    }
                },
                onError: function (data) {
                    console.error("Failed while trying to fetch grades data.");
                },
                Secured: true, 
            }, app.ConnectionStrings.app);
        },
        getOrFetch: function (callback, forceFetch) {
            var that = this;
            if (this.options.fetched && !forceFetch) {
                callback.call(this, this);
            } else {
                this.fetch({
                    callback: function (m) {
                        callback.call(that, m);
                    }
                });
            }
        }
    });

    Recipes.Models.ScrapType = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null, 
        }, 
    });

    Recipes.Collections.ScrapTypes = Backbone.Collection.extend({
        model: Recipes.Models.ScrapType,
        fetch: function (opt) {
            var that = this;
            var QP = new Core.Database.QueryParameters();

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetScrapMaterials", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table;

                        var items = [];
                        _.each(data, function (t) {
                            var item = {
                                id: t.Id,
                                name: t.Name, 
                            };

                            items.push(item);
                        });

                        that.set(items);

                        if (opt && opt.callback && _.isFunction(opt.callback))
                            opt.callback.call(that, that);
                    }
                },
                onError: function (data) {
                    console.error("Failed while trying to fetch scrap types data.");
                },
                Secured: true, 
                //UseDefaultConnectionString: true,
            }, app.ConnectionStrings.app);
        }
    }); 

    Recipes.Collections.Charges = Backbone.Collection.extend({
        model: Recipes.Models.Charge,
    }); 

    Recipes.Models.RecipesCreateEdit = Backbone.Epoxy.Model.extend({
        defaults: {
            id: null, 
            name: null,
            gradeId: null,
            isGradeGroup: false,
            chargesQty: null,
            active: true,
            used: false, 

            charges: null,

            //behind the scenes
            grades: null,
            scrapTypes: null, 

            gradesList: [],
            chargesQtyList: [{ value: 1, label: '1' }, { value: 2, label: '2' }, { value: 3, label: '3' }, { value: 4, label: '4' }],

            mode: "EDIT",
            wasChanged: false,
        },
        computeds: {
            grade: {
                get: function () {
                    return this.get("isGradeGroup") ? (this.get("gradeId")) ? "g-" + this.get("gradeId") : null : this.get("gradeId"); 
                },
                set: function (val) {
                    var isGradeGroup = val.indexOf("g-") != -1; 
                    var gradeId = parseInt(val.replace("g-", ""), 10); 

                    return {
                        gradeId: gradeId,
                        isGradeGroup: isGradeGroup, 
                    }; 
                }
            },
            deleteTitle: {
                get: function () {
                    var msg = "";
                    if (this.get("used")) {
                        msg = app.translate(this, "recipe_in_use_title"); 
                    } 
                    return msg;
                }, 
            }
        }, 
        reset: function () {
            this.set({
                id: null,
                name: null,
                gradeId: null,
                isGradeGroup: false,
                chargesQty: null,
                active: true,
                used: false, 

                wasChanged: false, 
            });

            this.get("charges").reset(); 
        }, 
        initialize: function () {
            var that = this; 
            this.attributes.charges = new Recipes.Collections.Charges();
            this.attributes.grades = new Recipes.Collections.Grades();
            this.attributes.scrapTypes = new Recipes.Collections.ScrapTypes();

            this.options = _.extend({}, this.options); 
            this.options.scraptypes = []; 
            this.options.catalogsLoaded = false; 

            this.checkCharges(); 
            this.bindEvents();

            var catalogs_cb = _.after(2, function () {
                that.options.catalogsLoaded = true; 
            }); 

            this.get("grades").fetch({
                callback: catalogs_cb, 
            });
            this.get("scrapTypes").fetch({
                callback: catalogs_cb,
            });
        },
        bindEvents: function () {
            this.listenTo(this.get("grades"), "add", _.debounce(this.parseGradesList, 100));
            this.listenTo(this.get("grades"), "remove", _.debounce(this.parseGradesList, 100));
            this.listenTo(this.get("grades"), "change", _.debounce(this.parseGradesList, 100));
            this.listenTo(this.get("grades"), "reset", _.debounce(this.parseGradesList, 100));

            this.listenTo(this.get("scrapTypes"), "add", _.debounce(this.parseScrapTypesSelectOptions, 100));
            this.listenTo(this.get("scrapTypes"), "remove", _.debounce(this.parseScrapTypesSelectOptions, 100));
            this.listenTo(this.get("scrapTypes"), "change", _.debounce(this.parseScrapTypesSelectOptions, 100));
            this.listenTo(this.get("scrapTypes"), "reset", _.debounce(this.parseScrapTypesSelectOptions, 100));
            
            this.listenTo(this, "change:chargesQty", this.checkCharges); 
        },
        parseScrapTypesSelectOptions: function () {
            var scraptypes = this.get("scrapTypes"); 
            this.options.scraptypes = scraptypes.map(function (m) { return [m.get("name"), m.get("id").toString()]; });
        }, 
        parseGradesList: function () {
            var grades = this.get("grades");
            var groups = [];
            //var groups = _.uniq(grades.pluck("groupName"));

            //var groups = _.map(groups, function (gn) {
            //    if (gn != null) {
            //        var gr = grades.findWhere({ groupName: gn });
            //        return {
            //            value: "g-" + gr.get("groupId"),
            //            label: "GRUPO: " + gr.get("groupName"),
            //        };
            //    }
            //}); 

            this.set({
                gradesList: groups.concat(grades.map(function (m) {
                    return { value: m.get("id"), label: m.get("name"), };
                }))
            });
        },
        checkCharges: function () {
            var charges = this.get("charges");
            var chargesQty = this.get("chargesQty"); 

            if (chargesQty != -1) {
                if (charges.length < chargesQty) {
                    var newCharges = _.times(Math.abs(charges.length - chargesQty), function (n) {
                        return new Recipes.Models.Charge({
                            number: n + charges.length + 1,
                        });
                    });
                    charges.add(newCharges);
                } else if (charges.length > chargesQty) {
                    var chargesToRemove = charges.slice(charges.length - Math.abs(charges.length - chargesQty), charges.length);
                    charges.remove(chargesToRemove);
                }
            } else {
                charges.reset(); 
            }
        }, 
        fetch: function (e) {
            var that = this;
            var QP = new Core.Database.QueryParameters();

            var data = (e.data) ? e.data : {};

            QP.Add("id", "INT", data.id); 

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetRecipeEdit", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {

                        var t = {
                            id: data.Table[0].Id, 
                            name: data.Table[0].Name,
                            gradeId: data.Table[0].GradeId,
                            isGradeGroup: data.Table[0].IsGradeGroup, 
                            chargesQty: data.Table[0].ChargesQty,
                            active: data.Table[0].Active,
                            used: data.Table[0].Used, 
                        }; 
                        
                        var chargeModels = [];
                        _.times(t.chargesQty, function (n) {
                            chargeModels.push(new Recipes.Models.Charge({
                                number: n + 1
                            }));
                        });

                        //_.each(data.Table1, function (f) {
                        //    var c = {
                        //        number: f.ChargeNumber,
                        //        total: f.Total
                        //    };

                        //    chargeModels.push(new Recipes.Models.Charge(c)); 
                        //}); 

                        var chargeDetails = {}
                        _.each(data.Table2, function (f) {
                            if (!chargeDetails[f.ChargeNumber]) {
                                chargeDetails[f.ChargeNumber] = []; 
                            }

                            var cds = chargeDetails[f.ChargeNumber].push({
                                scrapTypeId: f.ScrapTypeId,
                                cost: f.Cost,
                                weight: f.Weight,
                                order: f.Order,
                            }); 
                        }); 

                        _.each(chargeModels, function (f) {
                            f.get("details").set(chargeDetails[f.get("number")]); 
                        }); 

                        that.set(t, { from: "fetch" });
                        that.get("charges").set(chargeModels);

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, data);
                    }
                },
                onError: function () {
                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error");
                },
		        Secured: true,
            }, app.ConnectionStrings.app);
        }, 
    });

    Recipes.Views.RecipeCreateEditTable = Backbone.Epoxy.View.extend({
        template: "recipes"
        , id: "recipes-create-edit-table"
        , title: ""
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: false
        , initialize: function (a, b, c, d) {
            this.render(); 
        }
        , events: {
            "click .btn-add-layer": "addLayer", 
        }
        , render: function () {
            var that = this;
            //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/scrapyard/recipes/";
            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;

                    var ctx = {
                        editable: (($.inArray("AdminUserRole", app.models.user.get("roles")) != -1
                            || $.inArray("SupervisorUserRole", app.models.user.get("roles")) != -1) ? true : false),
                        permissions: {
                            edit: (($.inArray("scrapyard_recipes_item_edit", app.models.user.get("roles")) != -1) ? true : null),
                            download_all: (($.inArray("scrapyard_recipes_download_all", app.models.user.get("roles")) != -1) ? true : null),
                            download_recipe: (($.inArray("scrapyard_recipes_download", app.models.user.get("roles")) != -1) ? true : null),
                        },
                    };


                    if (ctx.permissions.edit === true ) {
                        $(".name-input").prop("disabled", false);
                        $(".charges-select").prop("disabled", false);
                        $(".grade-select").prop("disabled", false);
                        $(".input-medium").prop("disabled", false);
                    } else {
                        $(".charges-select").prop("disabled", "disabled");
                        $(".grade-select").prop("disabled", "disabled");
                        $(".name-input").prop("disabled", "disabled");
                        $(".input-medium").prop("disabled", "disabled");
                        $(".btn-save-recipe").hide();
                        $(".btn-delete-recipe").hide();
                    }


                   

                    that.$el.html(tmp(_.extend({}, ctx, (that.model) ? that.model.toJSON() : {})));
                    that.applyBindings();

                    var SelectCell = Backgrid.SelectCell.extend({
                        initialize: function () {
                            Backgrid.SelectCell.prototype.initialize.apply(this, arguments);
                        },
                        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;
                                }
                            },
                        }),
                    });

                    var used = that.options.collectionView.model.get("used"); 
                    that.$el.find(".btn-add-layer").attr("disabled", used);

                    var ActionsCell = Backgrid.Cell.extend({
                        template: Handlebars.compile(that.$el.find("#actions_cell_template").html()),
                        className: "actions-cell",
                        initialize: function () {
                            Backgrid.Cell.prototype.initialize.apply(this, arguments);
                        },
                        events: {
                            "click .btn-remove-layer": "removeLayer",
                            "click .btn-move-up-layer": "moveUp",
                            "click .btn-move-down-layer": "moveDown",
                        },
                        removeLayer: function () {
                            that.removeLayer(this.model); 
                        },
                        moveUp: function () {
                            this.moveLayer("UP"); 
                        },
                        moveDown: function () {
                            this.moveLayer("DOWN"); 
                        }, 
                        moveLayer: function (direction) {
                            var collection = this.model.collection;
                            var currentIndex = collection.indexOf(this.model); 
                            var swapIndex = null; 
                            var modelToSwapWith = null; 

                            modelToSwapWith = collection.at((direction == "UP") ? currentIndex - 1 : currentIndex + 1);
                            if (modelToSwapWith) {
                                swapIndex = collection.indexOf(modelToSwapWith);  
                                var removed = collection.remove([this.model, modelToSwapWith]);
                                if (direction == "UP") {
                                    collection.add(this.model, { at: swapIndex });
                                    collection.add(modelToSwapWith, { at: currentIndex });
                                } else {
                                    collection.add(modelToSwapWith, { at: currentIndex });
                                    collection.add(this.model, { at: swapIndex });
                                }
                            }
                        }, 
                        render: function () {
                            this.$el.html(this.template());
                            this.$el.find(".btn-remove-layer").attr("disabled", used); 

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

                    var editable_permission = ($.inArray("scrapyard_recipes_item_edit", app.models.user.get("roles")) != -1) ? true : false;

                    var LayerPercentageCell = Backgrid.Cell.extend({
                        className: "percentage-cell align-center-cell",
                        totalCharge : that.model.get('total'),

                        render: function () {
                            this.$el.empty();

                            var weight = this.model.get('weight');
                            if (weight) {
                                var percentage = (weight / this.totalCharge) * 100;
                                this.$el.text(percentage.toFixed(2) + '%');
                            } else {
                                this.$el.text('0%');
                            }

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

                    var columns = [
                        {
                            name: "order",
                            label: app.translate(that, "order_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.StringCell.extend({
                                orderSeparator: '',
                                className: "string-cell align-center-cell order-cell",
                            })
                        },
                        {
                            name: "scrapTypeId",
                            label: app.translate(that, "scrapType_label"),
                            editable: editable_permission,
                            sortable: false,
                            cell: SelectCell.extend({
                                optionValues: function () {
                                    var defaults = [["Choose ...", "-1"]];
                                    return _.union(defaults, that.options.collectionView.model.options.scraptypes); 
                                },
                            })
                        },
                        {
                            name: "cost",
                            label: app.translate(that, "cost_label"),
                            editable: false,
                            sortable: false,
                            cell: Backgrid.NumberCell.extend({
                                className: "number-cell align-center-cell cost-cell"
                            })
                        },
                        {
                            name: "",
                            label: app.translate(that, "layer_label"),
                            editable: false,
                            sortable: false,
                            cell: LayerPercentageCell,
                        },
                        {
                            name: "weight",
                            label: app.translate(that, "weight_label"),
                            editable: editable_permission,
                            sortable: false,
                            cell: Backgrid.IntegerCell.extend({
                                className: "integer-cell align-center-cell weight-cell"
                            })
                        },
                        {
                            name: "actions",
                            label: '',
                            editable: false,
                            sortable: false,
                            cell: ActionsCell, 
                        },
                    ];

                    // Initialize a new Grid instance
                    var charge_grid;
                    charge_grid = new Backgrid.Grid({
                        className: "backgrid table-bordered table table-hover",
                        columns: columns,
                        collection: that.model.get("details"),
                    });

                    that.$el.find(".charge-grid-container").append(charge_grid.render().el);

                }, true, customPath);
            }, customPath, "recipe_create_edit_table_view");
        },
        addLayer: function () {
            var chargeDetails = this.model.get("details");
            chargeDetails.add(new Recipes.Models.ChargeDetail({              
            }));
        },
        removeLayer: function (m) {
            var chargeDetails = this.model.get("details");
            chargeDetails.remove(m); 
        },
    });

    Recipes.Views.RecipesCreateEdit = Backbone.Epoxy.View.extend({
        template: "recipes"
        , id: "recipes-edit"
        , title: "Recipes"
        //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
        , recipeCreateEditTableView: Recipes.Views.RecipeCreateEditTable
        , 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 Recipes.Models.RecipesCreateEdit({
                mode: this.options.mode, 
            });

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

            this.model = model;

            this.bindingSources = {
                charges: function () {
                    return model.get('charges');
                },
            };

            this.bindEvents();
        },

        events: {
            "click .btn-save-recipe": "saveRecipe",
            "click .btn-delete-recipe": "deleteRecipe",
            "click .btn-back-to-list": "backToList",
            "click .btn-download-recipe": "downloadCurrentRecipe",
        },

        render: function (container, viewParams) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.options.container;
            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = "/app/custom-screens/scrapyard/recipes/";

            
            if (this.model.options.catalogsLoaded) {
                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;

                        var ctx = {
                            editable: (($.inArray("AdminUserRole", app.models.user.get("roles")) != -1
                                || $.inArray("SupervisorUserRole", app.models.user.get("roles")) != -1) ? true : false),
                            permissions: {
                                edit: (($.inArray("scrapyard_recipes_item_edit", app.models.user.get("roles")) != -1) ? true : null),
                                download_all: (($.inArray("scrapyard_recipes_download_all", app.models.user.get("roles")) != -1) ? true : null),
                                download_recipe: (($.inArray("scrapyard_recipes_download", app.models.user.get("roles")) != -1) ? true : null),
                            },
                        };


                        that.$el.html(tmp(_.extend({}, ctx, (that.model) ? that.model.toJSON() : {})));
                        that.applyBindings();

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

                        that.refresh(viewParams);
                    }, true, customPath);
                }, customPath, "recipe_create_edit_template");
            } else {
                setTimeout(function () {
                    that.render(container, viewParams); 
                }, 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) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }

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

        , _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 (viewParams) {
            try {
                var that = this;
                var mode = this.model.get("mode"); 

                if (mode == "EDIT") this.refreshEditMode(viewParams)
                else this.refreshNewMode(viewParams); 
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }
        , refreshEditMode: function (viewParams) {
            var that = this; 
            var id = null;
            if (viewParams && viewParams.recipeId) {
                id = parseInt(viewParams.recipeId, 10);
            }

            //if (this.model.options.catalogsLoaded) {
            this.model.fetch({
                data: { id: id, },
                callback: function (e) {
                },
            })
            //} else {
            //    setTimeout(function () {
            //        that.refreshEditMode(viewParams); 
            //    }, 100); 
            //}
        }
        , refreshNewMode: function (viewParams) {
            this.model.reset(); 
        }
        , saveRecipe: function (success, error) {
            var that = this;

            var valid = this.validateRecipe();
            if (!valid.valid) {
                this.showCodedMessage(valid.msgcode);
                return; 
            }

            var charges = this.model.get("charges");
            var chargeDetails = []; 

            charges.each(function (m) {
                m.get("details").each(function (e) {
                    chargeDetails.push({
                        chargeNumber: m.get("number"),
                        scrapTypeId: e.get("scrapTypeId"),
                        weight: e.get("weight"),
                        order: e.get("order"), 
                    }); 
                }); 
            }); 

            var chargeDetailsXML = this.getXML(chargeDetails, ["chargeNumber", "scrapTypeId", "weight", "order"]);

            var QP = new Core.Database.QueryParameters();
            QP.Add("RecipeId", "INT", this.model.get("id"));
            QP.Add("Name", "VARCHAR", this.model.get("name"));
            QP.Add("GradeId", "INT", this.model.get("gradeId"));
            QP.Add("IsGradeGroup", "BIT", this.model.get("isGradeGroup"));
            QP.Add("ChargesQty", "INT", this.model.get("chargesQty"));
            QP.Add("Active", "BIT", this.model.get("active"));
            QP.Add("Charges", "XML", chargeDetailsXML); 

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.UpsertRecipe", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table[0];

                        if (data && data.Status == "OK") {
                            if (_.isFunction(success)){
                                success.call(that, that, "success", data); 
                            }else{
                                that.recipeSaved(data);
                            }
                        } else {
                            if (_.isFunction(error)){
                                error.call(that, that, "error", data); 
                            }else{
                                that.recipeSaveFailed(data); 
                            }
                        }

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, data);
                    }
                },
                onError: function (data) {
                    if (_.isFunction(error)){
                        error.call(that, that, "error", data); 
                    }else{
                        that.recipeSaveFailed(data); 
                    }

                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error");
                },
		        Secured: true,
            }, app.ConnectionStrings.app);
        }
        , validateRecipe: function () {
            var ret = {
                valid: true,
                msgcode: null, 
            };

            if (!(this.model.get("name") && this.model.get("name").trim().length > 0)) {
                ret.valid = false;
                ret.msgcode = "INVALID_NAME"; 
            //} else if (!(this.model.get("gradeId") && this.model.get("gradeId") > -1)) {
            //    ret.valid = false;
            //    ret.msgcode = "INVALID_GRADE";
            } else if (!(this.model.get("chargesQty") && this.model.get("chargesQty") > 0)) {
                ret.valid = false;
                ret.msgcode = "INVALID_CHARGESQTY";
            } else if (
                this.model.get("charges").some(function (a, b) {
                    var b = a.get("details").some(function (a, b) {
                        return !(a.get("scrapTypeId") != null && a.get("scrapTypeId") != undefined);
                    });
                    return b; 
                })
            ) {
                ret.valid = false;
                ret.msgcode = "CHARGE_INVALID_SCRAPTYPE"; 
            }

            return ret; 
        }
        , recipeSaved: function (data) {
            var mode = this.model.get("mode");
            var name = this.model.get("name");

            var msg = ""; 
            if (mode == "NEW") {
                msg = app.translate(this, "recipe_created", [name]); 
            } else {
                msg = app.translate(this, "recipe_updated", [name]);
            }

            app.views.topMessages.showMessage(msg, { stay: 3000 });
            this.backToList(); 
        }
        , recipeSaveFailed: function (data) {
            var msgcode = (data && data["Message"]) ? data["Message"].toUpperCase() : "UNKNOWN";
            this.showCodedMessage(msgcode); 
        }
        , showCodedMessage: function (msgcode) {
            msgcode = (msgcode) ? msgcode : "UNKNOWN"; 
            var msg = "";

            msg = app.translate(this, msgcode + "_RECIPE_STATUS"); 

            app.views.topMessages.showMessage(msg, { stay: 2500 });
        }
        , deleteRecipe: function () {
            var that = this;
            var name = this.model.get("name"); 
            var modal = new Modal.Views.Main({
                id: "delete-recipe",
                title: app.translate(that, "delete_recipe_title"),
                message: app.translate(that, "delete_recipe_body", [name]),
                allowCancel: true,
                buttons_type: "CONTINUE-CANCEL"
            });

            modal.on("continue", function () {
                that.doDeleteRecipe(function () {
                    app.views.topMessages.showMessage(
                        app.translate(that, "recipe_deleted_msg", [name]), 
                        { stay: 3000 }
                    );
                    that.backToList(); 
                }); 
            });

            modal.show(); 
        }
        , doDeleteRecipe: function (callback) {
            var that = this;
            var QP = new Core.Database.QueryParameters();
            var id = this.model.get("id"); 

            QP.Add("RecipeId", "INT", id);

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.DeleteRecipe", QP, {
                onSuccess: function (data) {
                    if (data && data.Table && data.Table[0] && data.Table[0].Status == 'OK') {
                        if (callback && _.isFunction(callback))
                            callback.call(that, that, id);
                    } else {
                        if (data && data.Table && data.Table[0] && data.Table[0].Status == "FAILED") {
                            app.views.topMessages.showMessage(
                                app.translate(that, data.Table[0].Message + "_RECIPE_STATUS"), { stay: 3000 }
                            );
                        } else {
                            app.views.topMessages.showMessage(
                                app.translate(that, "UNKNOWN_RECIPE_STATUS"), { stay: 3000 }
                            );
                        }
                    }
                },
                onError: function () {
                    if (callback && _.isFunction(callback))
                        callback.call(that, that, "error");
                },
		Secured: true,
            }, app.ConnectionStrings.app);
        }
        , backToList: function () {
            app.router.navigate(app.router.resolveURL(app.router.currentModule, {}, false), { trigger: true });
        }
        , downloadCurrentRecipe: function () {
            var that = this;
            var modal = new Modal.Views.Main({
                id: "download-recipe",
                title: app.translate(that, "download_recipe_title"),
                message: app.translate(that, "continue_download_recipe_body", [that.model.get("name")]),
                allowCancel: true,
                buttons_type: "CONTINUE-CANCEL"
            });

            modal.on("continue", function () {
                that.saveRecipe(function (data) {
                    that.downloadRecipe({
                        callback: function (ref, status, data) {
                            that.downloadCurrentRecipeCallback(ref, status, data);
                        }
                    });
                });
            });

            modal.show();
        }
        , downloadCurrentRecipeCallback: function (ref, status, data) {
            var that = this; 
            if (status == "success") {
                if (data && data.Status) {
                    app.views.topMessages.showMessage(
                        app.translate(this, data.Status.toUpperCase() + "_DOWNLOAD_STATUS"), { stay: 3000 }
                    );

                    if (data.Status.toUpperCase() == "OK") {
                        this.backToList();
                    }
                } else {
                    app.views.topMessages.showMessage(
                        app.translate(this, "download_recipe_generic_error"), { stay: 3000 }
                    );
                }
            } else {
                app.views.topMessages.showMessage(
                    app.translate(this, "download_recipe_generic_error"), { stay: 3000 }
                );
            }
        }
        , downloadRecipe: function (e) {
            var that = this; 
            var QP = new Core.Database.QueryParameters();
            QP.Add("Names", "VARCHAR", this.model.get("name"));

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.DownloadRecipes", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table[0];

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, "success", data);
                    }
                },
                onError: function (data) {
                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error", data);
                },
                Secured: true,
            }, app.ConnectionStrings.app);
        }
        , getXML: function (data, cols) {
            function _toString(val) {
                return (val == null) ? "" : val.toString(); 
            }

            cols = (_.isArray(cols)) ? cols : [];
            cols = _.invoke(cols, "toUpperCase");

            var xml = null;
            data = (_.isArray(data)) ? data : [data];

            try {
                xml = '<XMLRoot>';
                for (var r = 0; r < data.length; r++) {
                    rowObj = data[r];
                    var row = '<Row ';
                    for (var c in rowObj) {
                        if ((cols.length == 0) || (cols.length > 0 && _.indexOf(cols, c.toString().toUpperCase()) != -1)) {
                            row += ((Trim(c).replace(' ', '')).replace('[', '')).replace(']', '') + '="' + _toString(rowObj[c]) + '" ';
                        }
                    }
                    row += '/>';
                    row = row.replace(/#/g, '');
                    xml += row;
                }
                xml += '</XMLRoot>';
            } catch (Error) {
            }
            return xml;
        }
        , append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }

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

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

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

        , closeSubviews: function () {
            _.each(this.options.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.model.reset(); 

            this.options.state = app.view_states.hidden;

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

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

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

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

        , reRender: function (viewParams) {
            this.model.set("mode", viewParams.action.toUpperCase());

            this.model.get("grades").fetch();
            this.model.get("scrapTypes").fetch();

            this._startAutoRefresh(viewParams);
        }
    });

    Recipes.Models.Main = Backbone.Model.extend({
        defaults: {
            screenModules: {
                "createEditRecipe": Recipes.Views.RecipesCreateEdit,
                "recipesList": Recipes.Views.RecipesList,
            },
        }
    });

    Recipes.Models.RecipesList = Backbone.Model.extend({
        defaults: {
            recipes: null,

            //behind the scenes
            grades: null,
            downloadedRecipes: null, 
        },
        initialize: function () {
            this.attributes.recipes = new Recipes.Collections.Recipes();
            this.attributes.grades = new Recipes.Collections.Grades();
            this.attributes.downloadedRecipes = new Recipes.Collections.DownloadedRecipes(); 
        }, 
    });

    //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.
    Recipes.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return "recipes"; 
        } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
    }

    Recipes.Models.DownloadedRecipe = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
        }
    });

    Recipes.Collections.DownloadedRecipes = Backbone.Collection.extend({
        model: Recipes.Models.DownloadedRecipe,
        fetch: function (e) {
            var that = this;
            var QP = new Core.Database.QueryParameters();

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetRecipesBeingDownloaded", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table;

                        var recipesModels = [];
                        for (var i = 0, len = data.length; i < len; i++) {
                            recipesModels.push({
                                id: data[i].Id,
                                name: data[i].Name && _.isString(data[i].Name) ? data[i].Name.toUpperCase() : null,
                            }); 
                        }

                        that.set(recipesModels, { from: "fetch" });

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, data);
                    }
                },
                onError: function () {
                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error");
                },
                Secured: true,
            }, app.ConnectionStrings.app);
        },
    }); 

    Recipes.Models.Recipe = Backbone.Epoxy.Model.extend({
        defaults: {
            id: null,
            name: null,
            gradeId: null,
            gradeName: null, 
            isGradeGroup: false, 
            chargesQty: null,
            active: null,

            status: null, 
        },
    });

    Recipes.Collections.Recipes = Backbone.Collection.extend({
        model: Recipes.Models.Recipe,
        initialize: function () {
        },
        comparator: function (a, b) {
            var activeA = a.get("active");
            var activeB = b.get("active");
            var gradeNameA = a.get("gradeName");
            var gradeNameB = b.get("gradeName");
            var nameA = a.get("name");
            var nameB = b.get("name"); 

            if (activeA > activeB) return -1; 
            else if (activeA < activeB) return 1; 
            else {
                if (gradeNameA > gradeNameB) return 1;
                else if (gradeNameA < gradeNameB) return -1;
                else {
                    if (nameA > nameB) return 1;
                    else if (nameA < nameB) return -1;
                }
            }

            //if none of the conditions are met, then the items are exactly the same.
            return 0;
        },
        fetch: function (e) {
            var that = this;
            var QP = new Core.Database.QueryParameters();

            var data = (e.data) ? e.data : {};
            var grades = data.grades ? data.grades : null; 
            
            var options = {
                params: {
                    groupId: null,
                    gradeIds: null,
                    active: null, 
                }, 
            }; 

            options.params = _.extend(options.params, (e && e.params) ? e.params : {}); 

            var fixedParams = [
                { Name: "groupId", Type: "INT", Value: options.params.groupId }, 
                { Name: "gradeIds", Type: "VARCHAR", Value: options.params.gradeIds }, 
                { Name: "active", Type: "INT", Value: options.params.active },
                { Name: "chargesQty", Type: "INT", Value: options.params.chargesQty },
            ]; 

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

            Core.Json.CallProcedure(app.DatabaseNames.Scrapyard + ".SCRAP.GetRecipesCatalog", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        data = data.Table;

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

                            var recipe = data[i];
                            var gradeName = "???";
                            if (grades) {
                                var gr; 
                                if (!recipe.IsGradeGroup) {
                                    gr = grades.findWhere({ id: recipe.GradeId });
                                    gradeName = (gr) ? gr.get("name") : gradeName;
                                } else {
                                    gr = grades.findWhere({ groupId: recipe.GradeId });
                                    gradeName = (gr) ? app.translate(that, "group_label") + ": " + gr.get("groupName") : gradeName; 
                                }
                            }

                            var oldModel = that.findWhere({ name: recipe.Name }); 
                            var recipeModel = new Recipes.Models.Recipe({
                                id: recipe.Id,
                                name: recipe.Name,
                                gradeName: gradeName,  
                                gradeId: recipe.GradeId,
                                isGradeGroup: recipe.IsGradeGroup, 
                                chargesQty: recipe.ChargesQty,
                                active: recipe.Active,
                                status: (oldModel) ? oldModel.get("status") : null, 
                            });

                            recipesModels.push(recipeModel);
                        }

                        that.set(recipesModels, { from: "fetch" });

                        if (e && e.callback && _.isFunction(e.callback))
                            e.callback.call(that, that, data);

                    }
                },
                onError: function(){
                    if (e && e.callback && _.isFunction(e.callback))
                        e.callback.call(that, that, "error");
                }, 
		Secured: true,
            }, app.ConnectionStrings.app);
        },
    });

    Recipes.Views.Main = Backbone.View.extend({
        template: "recipes"
        , id: "recipes"
        , title: "Recipes"
        //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 Recipes.Models.Main(); 

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

            this.model = model;

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

        events: {
        }, 

        render: function (container, viewParams) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.options.container;
            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = "/app/custom-screens/scrapyard/recipes/";

            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;

                    //start: before the view is visible, but the template was already loaded (not instanced nor appended)

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

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

                    that.refresh(viewParams);

                    //end:

                }, true, customPath);
            }, customPath, "main_template");
        }

        , _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) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }

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

        , _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 (viewParams) {
            try {
                for (var view in this.options.MYREFERENCES.subviews) {
                    this.options.MYREFERENCES.subviews[view].hide();
                }

                //default action
                var actionParam = "LIST";
                var action = "recipesList"; 

                if (viewParams && viewParams.action && viewParams.action != null && _.isString(viewParams.action)){
                    actionParam = _.indexOf(["EDIT", "NEW"], viewParams.action.trim().toUpperCase()) != -1 ? viewParams.action.trim().toUpperCase() : actionParam; 
                }

                var advOpt = {}; 
                switch (actionParam) {
                    case "EDIT":
                    case "NEW":
                        advOpt.mode = actionParam; 
                        action = "createEditRecipe"; 
                        break;
                    case "LIST":
                        action = "recipesList"; 
                        break;
                }

                //if (viewParams && viewParams.recipeId != null && viewParams.recipeId != undefined
                //    && _.isFinite(parseInt(viewParams.recipeId, 10))) {
                //    action = "editRecipe"; 
                //}

                if (!this.options.MYREFERENCES.subviews[action]) {
                    var module = this.model.get("screenModules")[action];
                    if (module != null && module != undefined) {
                        this.options.MYREFERENCES.subviews[action] = new module(_.extend({
                            parent: this,
                            container: this.$el.find("#recipes_screen_container"),
                            viewParams: viewParams,
                        }, advOpt));

                        this.options.MYREFERENCES.subviews[action].preRender(viewParams);
                        this.options.MYREFERENCES.subviews[action].render(null, viewParams);
                    }
                } else {
                    var screen = this.options.MYREFERENCES.subviews[action];

                    screen.show();
                    screen.preRender(); 
                    screen.reRender(viewParams);
                }

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

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

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }

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

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

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

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

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

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

        , reRender: function () {
            this.refresh(viewParams);
        }
    });

    Recipes.Models.SubnavBarControls = Backbone.Epoxy.Model.extend({
        defaults: {
            gradeGroupId: null,
            gradeId: null,
            activeFilter: -1,
            chargesQty: -1, 

            grades: null,
            gradesInternal: [], 
            gradeGroups: [],
        },
        computeds: {
            gradesList: {
                //deps: ["gradeGroupId"],
                get: function () {
                    var grades = this.get("gradesInternal");
                    return _.map(grades, function (m) {
                        return {
                            label: m["name"],
                            value: m["id"], 
                        }; 
                    });
                    //var groupId = this.get("gradeGroupId");
                    //var grades = this.get("gradesInternal");

                    //return _.map(_.filter(grades, function (m) {
                    //    if (m["groupId"]) {
                    //        return (m["groupId"] == groupId || groupId == -1); 
                    //    }
                    //    return false; 
                    //}), function(m){
                    //    return {
                    //        label: m["name"],
                    //        value: m["id"], 
                    //    }; 
                    //});
                }, 
            }, 
        }, 
        initialize: function () {
            this.attributes.grades = new Recipes.Collections.Grades();

            this.listenTo(this.get("grades"), "add", this.gradesChanged);
            this.listenTo(this.get("grades"), "remove", this.gradesChanged);
            this.listenTo(this.get("grades"), "change", this.gradesChanged);
            this.listenTo(this.get("grades"), "reset", this.gradesChanged);

            this.get("grades").fetch(); 
        },
        gradesChanged: _.debounce(function () {
            var grades = this.get("grades");
            var groups = _.uniq(grades.pluck("groupName"));

            var groups = _.map(groups, function (gn) {
                var gr = grades.findWhere({ groupName: gn });
                return {
                    value: gr.get("groupId"),
                    label: gr.get("groupName"),
                };
            });

            var gradesInternal = grades.toJSON(); 

            this.set("gradeGroups", groups);
            this.set("gradesInternal", gradesInternal); 
        }, 300),
    }); 

    //subview for the subnavbar controls
    Recipes.Views.SubnavBarControls = Backbone.Epoxy.View.extend({
        id: "recipes-subnavbar-controls"
        , title: ""
        , template: "recipes"
        , 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 Recipes.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/custom-screens/scrapyard/recipes/";

            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),
                        permissions: {
                            edit: (($.inArray("scrapyard_recipes_item_edit", app.models.user.get("roles")) != -1) ? true : null),
                            download_all: (($.inArray("scrapyard_recipes_download_all", app.models.user.get("roles")) != -1) ? true : null),
                            download_recipe: (($.inArray("scrapyard_recipes_download", app.models.user.get("roles")) != -1) ? true : null),
                        },
                    };



                    //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) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        }

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

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

});

