jui.define("chart.brush.scatter", [ "util.base" ], function(_) {

    /**
     * @class chart.brush.scatter
     * @extends chart.brush.core
     */
    var ScatterBrush = function() {

        this.getSymbolType = function(key, value) {
            var symbol = this.brush.symbol,
                target = this.brush.target[key];

            if(_.typeCheck("function", symbol)) {
                var res = symbol.apply(this.chart, [ target, value ]);

                if (res == "triangle" || res == "cross" || res == "rectangle" || res == "rect" || res == "circle") {
                    return {
                        type : "default",
                        uri : res
                    };
                } else {
                    return {
                        type : "image",
                        uri : res
                    };
                }
            }

            return {
                type : "default",
                uri : symbol
            };
        }

        this.createScatter = function(pos, dataIndex, targetIndex, symbol) {
            var self = this,
                elem = null,
                w = h = this.brush.size;

            var color = this.color(dataIndex, targetIndex),
                borderColor = this.chart.theme("scatterBorderColor"),
                borderWidth = this.chart.theme("scatterBorderWidth"),
                bgOpacity = this.brush.opacity;

            if(symbol.type == "image") {
                elem = this.chart.svg.image({
                    "xlink:href": symbol.uri,
                    width: w + borderWidth,
                    height: h + borderWidth,
                    x: pos.x - (w / 2) - borderWidth,
                    y: pos.y - (h / 2)
                });
            } else {
                if(symbol.uri == "triangle" || symbol.uri == "cross") {
                    elem = this.chart.svg.group({
                        width: w,
                        height: h,
                        opacity: bgOpacity,
                    }, function() {
                        if(symbol.uri == "triangle") {
                            var poly = self.chart.svg.polygon();

                            poly.point(0, h)
                                .point(w, h)
                                .point(w / 2, 0);
                        } else {
                            self.chart.svg.line({ stroke: color, "stroke-width": borderWidth * 2, x1: 0, y1: 0, x2: w, y2: h });
                            self.chart.svg.line({ stroke: color, "stroke-width": borderWidth * 2, x1: 0, y1: w, x2: h, y2: 0 });
                        }
                    }).translate(pos.x - (w / 2), pos.y - (h / 2));
                } else {
                    if(symbol.uri == "rectangle" || symbol.uri == "rect") {
                        elem = this.chart.svg.rect({
                            width: w,
                            height: h,
                            x: pos.x - (w / 2),
                            y: pos.y - (h / 2),
                            opacity: bgOpacity
                        });
                    } else {
                        elem = this.chart.svg.ellipse({
                            rx: w / 2,
                            ry: h / 2,
                            cx: pos.x,
                            cy: pos.y,
                            opacity: bgOpacity
                        });
                    }
                }

                if(symbol.uri != "cross") {
                    elem.attr({
                        fill: color,
                        stroke: borderColor,
                        "stroke-width": borderWidth
                    })
                    .hover(function () {
                        if(elem == self.activeScatter) return;

                        var opts = {
                            fill: self.chart.theme("scatterHoverColor"),
                            stroke: color,
                            "stroke-width": borderWidth * 2,
                            opacity: bgOpacity
                        };

                        if(self.brush.hoverSync) {
                            for(var i = 0; i < self.cachedSymbol[dataIndex].length; i++) {
                                opts.stroke = self.color(dataIndex, i);
                                self.cachedSymbol[dataIndex][i].attr(opts);
                            }
                        } else {
                            elem.attr(opts);
                        }
                    }, function () {
                        if(elem == self.activeScatter) return;

                        var opts = {
                            fill: color,
                            stroke: borderColor,
                            "stroke-width": borderWidth,
                            opacity: (self.brush.hide) ? 0 : bgOpacity
                        };

                        if(self.brush.hoverSync) {
                            for(var i = 0; i < self.cachedSymbol[dataIndex].length; i++) {
                                opts.fill = self.color(dataIndex, i);
                                self.cachedSymbol[dataIndex][i].attr(opts);
                            }
                        } else {
                            elem.attr(opts);
                        }
                    });
                }
            }

            return elem;
        }

        this.drawScatter = function(points) {
            // hoverSync 옵션 처리를 위한 캐싱 처리
            this.cachedSymbol = {};

            var self = this,
                g = this.chart.svg.group(),
                borderColor = this.chart.theme("scatterBorderColor"),
                borderWidth = this.chart.theme("scatterBorderWidth"),
                bgOpacity = this.brush.opacity,
                isTooltipDraw = false;

            for(var i = 0; i < points.length; i++) {
                for(var j = 0; j < points[i].length; j++) {
                    if(!this.cachedSymbol[j]) {
                        this.cachedSymbol[j] = [];
                    }

                    if(this.brush.hideZero && points[i].value[j] === 0) {
                        continue;
                    }

                    var data = {
                        x: points[i].x[j],
                        y: points[i].y[j],
                        max: points[i].max[j],
                        min: points[i].min[j],
                        value: points[i].value[j]
                    };

                    // 값이 null이나 undefined일 때, 그리지 않음
                    if(_.typeCheck([ "undefined", "null" ], data.value))
                        continue;

                    var symbol = this.getSymbolType(i, data.value),
                        p = this.createScatter(data, j, i, symbol),
                        d = this.brush.display;

                    // hoverSync 옵션을 위한 엘리먼트 캐싱
                    if(symbol.type == "default" && symbol.uri != "cross") {
                        this.cachedSymbol[j].push(p);
                    }

                    // Max & Min & All 툴팁 생성
                    if((d == "max" && data.max) || (d == "min" && data.min) || d == "all") {
                        // 최소/최대 값은 무조건 한개만 보여야 함.
                        if(d == "all" || !isTooltipDraw) {
                            g.append(this.drawTooltip(data.x, data.y, this.format(data.value)));
                            isTooltipDraw = true;
                        }
                    }

                    // 컬럼 및 기본 브러쉬 이벤트 설정
                    if(this.brush.activeEvent != null) {
                        (function(scatter, data, color, symbol) {
                            var x = data.x,
                                y = data.y,
                                text = self.format(data.value);

                            scatter.on(self.brush.activeEvent, function(e) {
                                if(symbol.type == "default" && symbol.uri != "cross") {
                                    if (self.activeScatter != null) {
                                        self.activeScatter.attr({
                                            fill: self.activeScatter.attributes["stroke"],
                                            stroke: borderColor,
                                            "stroke-width": borderWidth,
                                            opacity: (self.brush.hide) ? 0 : bgOpacity
                                        });
                                    }

                                    self.activeScatter = scatter;
                                    self.activeScatter.attr({
                                        fill: self.chart.theme("scatterHoverColor"),
                                        stroke: color,
                                        "stroke-width": borderWidth * 2,
                                        opacity: bgOpacity
                                    });
                                }

                                self.activeTooltip.html(text);
                                self.activeTooltip.translate(x, y);
                            });

                            scatter.attr({ cursor: "pointer" });
                        })(p, data, this.color(j, i), this.getSymbolType(i, data.value));
                    }

                    if(this.brush.hide) {
                        p.attr({ opacity: 0 });
                    }

                    this.addEvent(p, j, i);
                    g.append(p);
                }
            }

            // 액티브 툴팁
            this.activeTooltip = this.drawTooltip(0, 0, "");
            g.append(this.activeTooltip);

            return g;
        }

        this.drawTooltip = function(x, y, text) {
            return this.chart.text({
                y: -this.brush.size,
                "text-anchor" : "middle",
                fill : this.chart.theme("tooltipPointFontColor"),
                "font-size" : this.chart.theme("tooltipPointFontSize"),
                "font-weight" : this.chart.theme("tooltipPointFontWeight"),
                opacity : this.brush.opacity
            }, text).translate(x, y);
        }

        this.draw = function() {
            return this.drawScatter(this.getXY());
        }

        this.drawAnimate = function() {
            var area = this.chart.area();

            return this.chart.svg.animateTransform({
                attributeName: "transform",
                type: "translate",
                from: area.x + " " + area.height,
                to: area.x + " " + area.y,
                begin: "0s" ,
                dur: "0.4s",
                repeatCount: "1"
            });
        }
    }

    ScatterBrush.setup = function() {
        return {
            /** @cfg {"circle"/"triangle"/"rectangle"/"cross"/"callback"} [symbol="circle"] Determines the shape of a (circle, rectangle, cross, triangle).  */
            symbol: "circle",
            /** @cfg {Number} [size=7]  Determines the size of a starter. */
            size: 7,
            /** @cfg {Boolean} [hide=false]  Hide the scatter, will be displayed only when the mouse is over. */
            hide: false,
            /** @cfg {Boolean} [hideZero=false]  When scatter value is zero, will be hidden. */
            hideZero: false,
            /** @cfg {Boolean} [hoverSync=false]  Over effect synchronization of all the target's symbol. */
            hoverSync: false,
            /** @cfg {String} [activeEvent=null]  Activates the scatter in question when a configured event occurs (click, mouseover, etc). */
            activeEvent: null,
            /** @cfg {"max"/"min"/"all"} [display=null]  Shows a tooltip on the scatter for the minimum/maximum value.  */
            display: null,
            /** @cfg {Number} [opacity=1]  Stroke opacity.  */
            opacity: 1,
            /** @cfg {Boolean} [clip=false] If the brush is drawn outside of the chart, cut the area. */
            clip: false
        };
    }

    return ScatterBrush;
}, "chart.brush.core");