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

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

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

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

  "modules/modal",

  "backgrid",

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

  "oee-module-assets/dashboard-assets/jquery-circle-progress/circle-progress",

],

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

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

    OEEOverview.Models.Main = Backbone.Model.extend({
        defaults: {
            productionItem: null,
        }, 
        initialize: function () {
            _.bindAll(this); 

            this.attributes.productionItem = new OEEOverview.Models.ProductionItem();
        },
    });

    OEEOverview.Models.ProductionItem = Backbone.Model.extend({
        defaults: {
            id: null,
            parentId: null, 
            type: null,
            name: null,
            description: null,
            children: null, 

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

            setpoint: null, 

            status: null, 
        },
        initialize: function () {
            this.options = (_.isObject(this.options)) ? this.options : {}; 
            this.options.transactionts = null;
            this.options.isFetching = false; 
            //this.attributes.children = new OEEOverview.Collections.ProductionItems({}); 
        }, 
        fetch: function (opt) {
            this.options.isFetching = true;
            var ttimestamp = this.options.transactionts = new Date().getTime(); 
            var id = _.isObject(opt) ? opt.id : opt;
            id = (id) ? id : null;
            var callback = (_.isObject(opt) && _.isFunction(opt.callback)) ? opt.callback : null;

            //console.log("fetching data for: " + id); 

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

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

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetOEEOverview", QP, {
                onSuccess: function (data) {
                    if (ttimestamp != that.options.transactionts) {
                        that.options.isFetching = false;
                        return;
                    }

                    if (data && data.Table) {
                        var productionItem = data.Table[0];
                        var children = data.Table1;

                        var productionItemModel = {
                            id: productionItem.Id,
                            parentId: productionItem.ParentId,
                            type: productionItem.ProductionItemType,
                            name: productionItem.Name,
                            description: productionItem.Description,

                            oee: null,
                            availability: null,
                            quality: null,
                            performance: null,
                        };

                        var childrenProductionItems = [];
                        for (var i = 0, len = children.length; i < len; i++) {
                            var pitem = children[i];
                            childrenProductionItems.push(new OEEOverview.Models.ProductionItem({
                                id: pitem.Id,
                                parentId: pitem.ParentId,
                                type: pitem.ProductionItemType,
                                name: pitem.Name,
                                description: pitem.Description,

                                oee: pitem.OEE,
                                availability: pitem.Availability,
                                quality: pitem.Quality,
                                performance: pitem.Performance,
                                setpoint: pitem.SetpointOEE, 

                                status: pitem.Status,
                            }));
                        }

                        if (ttimestamp != that.options.transactionts) {
                            that.options.isFetching = false;
                            return;
                        }

                        var collection = that.get("children");
                        if (collection == null) {
                            that.set("children", new OEEOverview.Collections.ProductionItems());
                            collection = that.get("children");
                        }

                        //console.log("settting data for: " + id);
                        collection.set(childrenProductionItems, { from: "fetch", silent: false });
                        that.set(productionItemModel, { from: "fetch" });

                        that.options.isFetching = false;

                        if (callback && _.isFunction(callback)) {
                            callback.call(that, that);
                        }
                    } else {
                        //console.log("error in data"); 
                    }
                },
                Secured: true,
                Cache: true, 
            }, app.ConnectionStrings.app);
        }, 
    });

    OEEOverview.Collections.ProductionItems = Backbone.Collection.extend({
        model: OEEOverview.Models.ProductionItem,
    }); 

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

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

            var productionItemId = null;

            if (this.options.viewParams) {
                productionItemId = (this.options.viewParams.id != null && this.options.viewParams.id != undefined)
                    ? this.options.viewParams.id : null;
            }

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

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

            this.options.displayType = null; 
            this.options.isRendered = false; 

            this.options.graph = {
                circles: {}, 
            }; 

            this.model = model;

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

            this.model.get("productionItem").fetch({
                id: productionItemId
            });
        },

        events: {
            "click .production-item-container": "productionItem_click", 
        }, 

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

            var thatContainer = (this.options.container) ? this.options.container : container; 
            this.options.container = thatContainer; 
            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = app.oeeModule.screensPath + "oee-overview/";
            if (this.model.get("productionItem").get("id")) {
                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
                        //console.log("rendering..."); 
                        that.options.i18n[that.template] = i18nJED;

                        var model = that.model.get("productionItem");

                        var productItemTitle = model.get("name");
                        productItemTitle = (productItemTitle) ? productItemTitle : app.translate(that, 'plant_label');

                        var nofcols = (!model.get("type")) ? 4 : 3;
                        var display_type = (!model.get("type")) ? "lines-oee" : "3cols";
                        that.options.displayType = display_type; 

                        var data = {
                            id: model.get("id"),
                            mainRoute: app.router.resolveURL("/!/oeeOverview", { }, true, true),
                            title: productItemTitle,
                            display: display_type,
                            rows: []
                        };

                        var children = model.get("children");
                        var row = null;

                        if (children) {
                            model.get("children").forEach(function (m) {
                                row = (row == null) ? { columns: [] } : row;
                                var child = {
                                    title: m.get("name"),
                                    type: m.get("type"),
                                    productionItemId: m.get("id"),
                                };

                                _.extend(child, m.toJSON());

                                //translating type
                                child.type = app.translate(that, child.type.toUpperCase() + '_type_label'); 

                                row.columns.push(child);
                                if (row.columns.length == nofcols) {
                                    data.rows.push(row);
                                    row = null;
                                }
                            });

                            if (row && row.columns.length < nofcols) {
                                data.rows.push(row);
                                row = null;
                            }
                        }

                        that.$el.fadeOut("fast", function () {
                            that.options.loadingScreen = false;
                            that.$el.html(tmp(data));
                            that.append(thatContainer, that.$el);

                            that.$el.fadeIn("fast", function () {
                                if (children) {
                                    that.drawCircles();
                                    that.updateStatusLights(); 
                                }
                            });
                        });

                        that.options.isRendered = true;
                    }, true, customPath);
                }, customPath, "main_template");
            } else {
                this.options.loadingScreen = true; 
                this.$el.html('<div style="text-align:center;margin-top:10px;font-size:24px;"><i class="fa fa-5x fa-cog fa-spin"></i><br />Loading ...</div>');
                this.append(thatContainer, this.$el);
            }

            if (!this.options.isRendered)
                this._startAutoRefresh(); 
        }
        , _getPercent: function (val, opt){
            return (Math.round((val * 100) / opt.total)) / 100;
        }
        , _sign: function (num) {
            // IE does not support method sign here
            if (typeof Math.sign === 'undefined') {
                if (num > 0) {
                    return 1;
                }
                if (num < 0) {
                    return -1;
                }
                return 0;
            }
            return Math.sign(num);
        }
        , precise_round: function (num, decimals) {
            var t = Math.pow(10, decimals);
            return (Math.round((num * t) + (decimals > 0 ? 1 : 0) * (this._sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
        }
        , _getValue: function (perc, opt) {
            var val = this.precise_round((perc * opt.total) / 100, 2);
            val = parseFloat(val);
            val = (val > 1) ? Math.round(val) : val;
            return (val * 100).toFixed(0);
        }
        , drawCircles: function () {
            var that = this; 

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

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

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

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

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

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

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

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

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

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

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

            this.options.graph.circles = {}; 

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

                if (!that.options.graph.circles[circle_productionitemid]) that.options.graph.circles[circle_productionitemid] = {}; 
                that.options.graph.circles[circle_productionitemid][circle_name] = $circle; 

                var size = circle_container.width() - 20;

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

                if ($circle.siblings('.set-point').length) {
                    that.options.graph.circles[circle_productionitemid]["setpoint"] = $circle.siblings('.set-point');
                    var setpoint = that.options.graph.circles[circle_productionitemid]["setpoint"].data("setpoint-value");
                    setpoint = (_.isNumber(setpoint)) ? setpoint : 0; 

                    var minusSize = 0;
                    var minusThickness = 0; 
                    switch (that.options.displayType) {
                        case "lines-oee":
                            minusSize = 20;
                            minusThickness = 5; 
                            break;
                        case "3cols":
                            minusSize = 30;
                            minusThickness = 12; 
                            break; 
                    }

                    that.options.graph.circles[circle_productionitemid]["setpoint"].circleProgress({
                        value: setpoint / 100,
                        size: size - minusSize,
                        startAngle: -Math.PI / 4 * 2,
                        thickness: circle_thickness - minusThickness,
                        fill: { gradient: ['#1300ff', '#006cff'] },
                        emptyFill: "transparent",
                    }).on("circle-animation-progress", function (event, progress, stepValue) {
                        var progress_display = $circle.find(".setpoint-text");
                        if (progress_display.length > 0) {
                            if ($(this).circleProgress('value') > 0)
                                progress_display.text((stepValue * 100).toFixed(0) + "%");
                            else progress_display.text(""); 
                        }
                    }).on("circle-animation-end", function (event) {
                        //var progress_display = $circle.find(".progress-display");
                        //if (progress_display.length > 0) {
                        //    var actual = parseFloat(($(event.target).circleProgress('value') * 100).toFixed(2)); 
                        //    progress_display.text(_.isNumber(actual) ? actual : "-"); 
                        //}
                    });
                }
            });
        }
        , refreshGraph: function () {
            for (var piid in this.options.graph.circles) {
                var mod = this.model.get("productionItem").get("children").findWhere({ id: parseInt(piid, 10) }); 
                if (mod) {
                    for (var name in this.options.graph.circles[piid]) {
                        var circle = this.options.graph.circles[piid][name];

                        var varName = "oee";
                        switch (name) {
                            case "oee":
                                varName = "oee";
                                break;
                            case "ava":
                                varName = "availability";
                                break;
                            case "per":
                                varName = "performance";
                                break;
                            case "qua":
                                varName = "quality";
                                break; 
                            case "setpoint":
                                varName = "setpoint"; 
                                break;
                        }

                        circle.circleProgress('value', mod.get(varName) / 100);
                    }
                }
            }

            this.updateStatusLights(); 
        }
        , productionItem_click: function (e) {
            var target = $(e.target);
            if (!target.data("productionitemid")) {
                target = target.parents("[data-productionitemid]");
            }
            var id = target.data("productionitemid");

            if (!id) return;

            var childrens = this.model.get("productionItem").get("children");
            if (childrens) {
                var model = childrens.findWhere({ id: id });
                if (model) {
                    var type = model.get("type").toUpperCase();
                    switch (type) {
                        case "LINE":
                            //CHECK, 
                            //CHANGE THIS
                            app.router.navigate("!/oeeOverview" + "/" + id, { trigger: true });
                            break;
                        case "MACHINE":
                            //CHECK, 
                            //CHANGE THIS
                            app.router.navigate("!/oee" + "/" + id, { trigger: true });
                            break; 
                    }
                }
            }
        }
        , updateStatusLights: function () {
            var that = this; 
            var lights = this.$el.find(".status-lights-container"); 
            lights.each(function (inx, obj) {
                var o = $(obj);
                var piid = o.data("pidlights"); 

                var mod = that.model.get("productionItem").get("children").findWhere({ id: parseInt(piid, 10) });
                var currentStatus = mod.get("status");
                currentStatus = (_.isString(currentStatus)) ? currentStatus : 'MAINTENANCE'; 

                var lights = o.find('*[class*="light-icon-"]');
                lights.find(".lc-indicator")
                    .removeClass("lightcolor-red")
                    .removeClass("lightcolor-yellow")
                    .removeClass("lightcolor-green");

                lights.each(function (inx, obj) {
                    obj = $(obj);
                    var status = obj.data("lightstatus");
                    var color = obj.data("lightcolor");

                    if (_.isString(status) && status.toUpperCase() == currentStatus.toUpperCase()) {
                        obj.find(".lc-indicator").addClass("lightcolor-" + color);
                    }
                });
            });
        }
        , refresh: function (viewParams, opt) {
            try {
                var that = this;
                if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                    clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                    this.options.MYREFERENCES.autoRefresh.toid = null;
                }

                var that = this; 
                var options = {
                    callback: null, 
                };
                _.extend(options, opt); 

                var productionItemId = null;

                if (viewParams) {
                    this.setLoading(); 

                    productionItemId = (viewParams.id != null && viewParams.id != undefined)
                        ? viewParams.id : null;

                    if (this.model.get("productionItem"))
                        this.stopListening(this.model.get("productionItem").get("children"));

                } else {
                    productionItemId = (productionItemId) ? productionItemId : (this.model.get("productionItem")) ? this.model.get("productionItem").get("id") : null;
                    productionItemId = (productionItemId == -1) ? null : productionItemId;
                }

                var prodItems = this.model.get("productionItem"); 
                if (!prodItems.options.isFetching) {
                    prodItems.fetch({
                        id: productionItemId,
                        callback: function (that2) {
                            if (that.options.MYREFERENCES.autoRefresh.enabled == true) {
                                that.options.MYREFERENCES.autoRefresh.toid = setTimeout(that._autoRefresh, 3000);
                            }

                            if (options && options.callback && _.isFunction(options.callback)) {
                                options.callback.call(that, that2);
                            }
                        },
                    });
                } else {
                    setTimeout(function () { that.refresh(viewParams, opt); }, 100); 
                }
            } catch (Error) { }
        }

        , setLoading: function () {
            if (!this.options.loadingScreen) {
                this.options.loadingScreen = true;
                this.$el.html('<div style="text-align:center;margin-top:10px;font-size:24px;"><i class="fa fa-5x fa-cog fa-spin"></i><br />Loading ...</div>');
            }            
        }

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

        , preExecRender: function () {
            if (this.model.get("productionItem").get("id")) {
                this.listenTo(this.model.get("productionItem").get("children"), "change:oee change:availability change:quality change:performance change:status change:setpoint", this.refreshGraph);
            }

            this.render();
        }

        , _startAutoRefresh: function () {
            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();
            } catch (Error) { }
        }

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

            this.refresh(params, {
                callback: function () {
                    
                }, 
            });
        }

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

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

        , 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.$el.hide();
            this.unbind();
            this.stopListening();
        }

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

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

        , reRender: function (viewParams) {
            try {
                this._autoRefresh(viewParams); 
            } catch (Error) { }
        }
    });

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

});

