MWF.widget = MWF.widget || {};
MWF.widget.chart = MWF.widget.chart || {};
MWF.require("MWF.widget.Common", null, false);
MWF.require("MWF.widget.chart.d3", null, false);
MWF.require("MWF.widget.UUID", null, false);
MWF.widget.chart.Dashboard = new Class({
    Implements: [Options, Events],
    Extends: MWF.widget.Common,
    options: {
        "style": "default",
        "margin": "10px",
        "sort": "ASC", //ASC, DESC
        "red":.3,
        "green":.3,
        "borderWidth": 6,
        "arcWidth": 15,
        "arcMargin": 22,
        "ticks": 7,
        "tickLong": 6,
        "miniTicks": 31,
        "miniTickLong": 3,
        "centerWidth": 6,
        "format": "",
        "formatdData": "",
        "text": "",

        "domain": []

    },
    initialize: function(node, data, options){
        this.setOptions(options);
        this.container = $(node);
        this.data = data;
        this.classId = new MWF.widget.UUID();

        this.path = MWF.defaultPath+"/widget/chart/$Dashboard/";
        this.cssPath = MWF.defaultPath+"/widget/chart/$Dashboard/"+this.options.style+"/css.wcss";
        this._loadCss();
    },
    load: function(){
        this.node = new Element("div", {"styles": this.css.node}).inject(this.container);
        this.setNodeSize();

        MWF.widget.chart.d3.load(function(){
            if (this.fireEvent("queryLoad")){
                this.svg = d3.select(this.node).append("svg");
                this.setSvgSize();

                this.showData = this.data;
                var max = d3.max(this.options.domain);
                var min = d3.min(this.options.domain);
                if (this.data>max) this.showData = max;
                if (this.data<min) this.showData = min;

                //this.group = this.svg.append("g");

                this.drawCircleOutline();

                this.drawArc();
                this.drawMiniTicks();
                this.drawTicks();
                this.drawText();
                this.drawPointer();

                //
                //this.loadScales();
                //this.loadXaes();
                //this.loadBars();
                //
                //this.setStyles();
                //this.setEvents();
            }


        }.bind(this));
        this.fireEvent("postLoad");

    },
    setNodeSize: function(){
        var margin = this.options.margin.toInt();
        var size = this.container.getSize();
        var width = size.x-(margin*2);
        var height = size.y-(margin*2);
        this.size = {"x": width, "y": height, "m": margin};
    },
    setSvgSize: function(){
        this.svg.attr("width", "100%").attr("height", "100%");
    },
    drawCircleOutline: function(){
        var r = this.size.x/2;
        var x = this.size.x/2 + this.size.m;
        this.circleBig = this.svg.append("circle")
            .attr("cx", x)
            .attr("cy", x)
            .attr("r", r);
        Object.each(this.css.circleBig, function(v,k){this.circleBig.attr(k, v);}.bind(this));

        r = r - this.options.borderWidth;
        this.circleSmall = this.svg.append("circle")
            .attr("cx", x)
            .attr("cy", x)
            .attr("r", r);
        Object.each(this.css.circleSmall, function(v,k){this.circleSmall.attr(k, v);}.bind(this));

        this.circleCenter = this.svg.append("circle")
            .attr("cx", x)
            .attr("cy", x)
            .attr("r", this.options.centerWidth);
        Object.each(this.css.circleCenter, function(v,k){this.circleCenter.attr(k, v);}.bind(this));

        this.setDefs("circleBig_defs", this.circleBig);
        this.setDefs("circleSmall_defs", this.circleSmall);
        this.setDefs("circleCenter_defs", this.circleCenter);
    },
    setDefs: function(name, selection){
        if (this.css[name]){
            var defs = this.svg.append("defs");
            this.createDefs(defs, this.css[name]);
            defs.select(function(){ return this.getFirst(); }).attr("id", this.classId+"_"+name);
            selection.attr(this.css[name].urlAttr, "url(#"+this.classId+"_"+name+")");
        }
    },
    createDefs: function(node, data){
        var svgNode = node.append(data.tag);
        Object.each(data.attrs, function(v,k){svgNode.attr(k,v);});
        if (data.subs) {
            data.subs.each(function(v){
                this.createDefs(svgNode, v);
            }.bind(this));
        }
    },

    drawArc: function(){
        //this.angleScale = d3.scaleBand().domain(this.data.map(function(d){ return d[this.item];}.bind(this)))
        //    .rangeRound(this.getXScaleRange()).paddingOuter(0.1).paddingInner(0.1);
        this.angleScale = d3.scaleLinear().domain(this.options.domain)
            .range([0-0.75*Math.PI, 0.75*Math.PI]);

        var greenAngle = this.angleScale(this.options.green*d3.max(this.options.domain));
        var redAngle = this.angleScale((1-this.options.red)*d3.max(this.options.domain));

        var green = {"startAngle": 0-0.75*Math.PI,"endAngle": greenAngle};
        var yellow = {"startAngle": greenAngle,"endAngle": redAngle};
        var red = {"startAngle": redAngle,"endAngle": 0.75*Math.PI};

        var or = this.size.x/2-this.options.arcMargin-this.options.borderWidth;
        var ir = this.size.x/2-this.options.arcMargin-this.options.arcWidth-this.options.borderWidth;
        var x = this.size.x/2 + this.size.m;

        var arcPath = d3.arc().innerRadius(ir).outerRadius(or);

        this.greenArc = this.svg.append("path").attr("d", arcPath(green)).attr("transform", "translate("+x+", "+x+")");
        this.yellowArc = this.svg.append("path").attr("d", arcPath(yellow)).attr("transform", "translate("+x+", "+x+")");
        this.redArc = this.svg.append("path").attr("d", arcPath(red)).attr("transform", "translate("+x+", "+x+")");

        Object.each(this.css.greenArc, function(v,k){this.greenArc.attr(k, v);}.bind(this));
        Object.each(this.css.yellowArc, function(v,k){this.yellowArc.attr(k, v);}.bind(this));
        Object.each(this.css.redArc, function(v,k){this.redArc.attr(k, v);}.bind(this));

        this.setDefs("greenArc_defs", this.greenArc);
        this.setDefs("yellowArc_defs", this.yellowArc);
        this.setDefs("redArc_defs", this.redArc);
    },

    drawTicks: function(){
        var per = d3.max(this.options.domain)/(this.options.ticks-1);
        var or = this.size.x/2-this.options.borderWidth;
        var ir = this.size.x/2-this.options.tickLong-this.options.borderWidth;
        var x = this.size.x/2 + this.size.m;
        var arcPath = d3.arc().innerRadius(ir).outerRadius(or);
        var arcTextPath = d3.arc().innerRadius(ir-16).outerRadius(ir);

        for (var i=0; i<this.options.ticks; i++){
            var arcAngle = this.angleScale((per*i));
            var angle = {"startAngle": arcAngle,"endAngle": arcAngle};
            var arc = this.svg.append("path").attr("d", arcPath(angle)).attr("transform", "translate("+x+", "+x+")");
            Object.each(this.css.tick, function(v,k){arc.attr(k, v);}.bind(this));

            var position = arcTextPath.centroid(angle);
            var text = Math.round(per*i);
            if (text>1000){
                text = text/1000;
                text = d3.format("0.3r")(text);
                text = text+"k";
            }

            this.svg.append("text")
                .attr("transform", "translate("+x+", "+x+") "+"translate("+position[0]+", "+position[1]+")")
                .attr("text-anchor", "middle")
                .attr("dy", "4")
                .attr("font-size", "10px")
                .text(text);
        }

    },
    drawMiniTicks: function(){
        var miniPer = d3.max(this.options.domain)/(this.options.miniTicks-1);
        var or = this.size.x/2-this.options.borderWidth;
        var ir = this.size.x/2-this.options.miniTickLong-this.options.borderWidth;
        var x = this.size.x/2 + this.size.m;
        var arcPath = d3.arc().innerRadius(ir).outerRadius(or);

        for (var i=0; i<this.options.miniTicks; i++){
            var arcAngle = this.angleScale((miniPer*i));
            var angle = {"startAngle": arcAngle,"endAngle": arcAngle};
            var arc = this.svg.append("path").attr("d", arcPath(angle)).attr("transform", "translate("+x+", "+x+")");
            Object.each(this.css.miniTick, function(v,k){arc.attr(k, v);}.bind(this));
        }
    },

    getPointerPath: function(data){
        var x = this.size.x/2 + this.size.m;
        var ir = this.size.x/2-this.options.tickLong-this.options.borderWidth;
        var arcTextPath = d3.arc().innerRadius(ir-24).outerRadius(ir);

        var arcAngle = this.angleScale(data);
        var angle = {"startAngle": arcAngle,"endAngle": arcAngle};
        var to = arcTextPath.centroid(angle);
        var lx = to[0]+x;
        var ly = to[1]+x;


        var arcAngleStart = this.angleScale(d3.min(this.options.domain));

        var x1 = 0-to[0];
        var y1 = 0-to[1];
        var l = Math.sqrt(Math.pow(x1, 2)+Math.pow(y1,2));

        var r = this.options.centerWidth-4;
        var tmpA1 = Math.asin(y1/l);
        var tmpA2 = Math.asin(r/l);
        var a1, a2;
        if (x1>=0){
            a1 = (tmpA1-tmpA2)+(Math.PI/2);
            a2 = (tmpA1+tmpA2)+(Math.PI/2);
        }else{
            a2 = (Math.PI*2) - ((tmpA1-tmpA2)+(Math.PI/2));
            a1 = (Math.PI*2) - ((tmpA1+tmpA2)+(Math.PI/2));
        }


        if (!this.arcPointerPath) this.arcPointerPath = d3.arc().innerRadius(0).outerRadius(l+10);
        var angle = {"startAngle": a1,"endAngle": a2};
        var d = this.arcPointerPath(angle);

        return {"d": d, "lx": lx, "ly": ly};
    },
    drawPointer: function(){
        //var path = this.getPointerPath(this.showData);
        var pathStart = this.getPointerPath(d3.min(this.options.domain));

        this.pointer = this.svg.append("path").attr("d", pathStart.d).attr("transform", "translate("+pathStart.lx+", "+pathStart.ly+")");
        Object.each(this.css.pointer, function(v,k){this.pointer.attr(k, v);}.bind(this));
        this.setDefs("pointer_defs", this.pointer);

        this.transition();
    },
    transition: function(){
        var pathStart = this.getPointerPath(d3.min(this.options.domain));
        var lx = pathStart.lx;
        var ly = pathStart.ly;
        this.pointer.attr("d", pathStart.d).attr("transform", "translate("+pathStart.lx+", "+pathStart.ly+")");

        this.pointer.transition().delay(200)
            .duration(3000)
            .ease(d3.easeElasticOut)
            .attrTween("d", function(d, i, v){
                return function(t){
                    var p = this.getPointerPath(this.showData*t);
                    lx = p.lx;
                    ly = p.ly
                    return p.d
                }.bind(this)
            }.bind(this))
            .attrTween("transform", function(d, i, v){
                return function(t){
                    return "translate("+lx+", "+ly+")"
                }.bind(this)
            }.bind(this));
    },

    drawText: function(){
        var r = this.size.x/2-this.options.arcMargin-this.options.borderWidth;
        var x = this.size.x/2 + this.size.m;
        var y = this.size.x/2 + this.size.m + r;

        this.dataText = this.svg.append("text")
            .attr("transform", "translate("+x+", "+y+") ")
            .attr("text-anchor", "middle")
            .attr("dy", "4")
            .attr("font-size", "10px")
            .text((this.options.formatData) ? d3.format(this.options.formatData)(this.options.text || this.data) : (this.options.text || this.data));

        Object.each(this.css.dataText, function(v,k){this.dataText.attr(k, v);}.bind(this));
        this.setDefs("dataText_defs", this.dataText);
    },

    hide: function(){
        this.node.setStyle("display", "none");
    },
    show: function(){
        this.node.setStyle("display", "block");
        this.transition();
    },
    destroy: function(){
        this.node.destroy();
        d3.interrupt(this.pointer);
        MWF.release(this);
    }

});