jui.define("chart.widget.tooltip", [ "util.base", "util.color" ], function(_, ColorUtil) {
    var PADDING = 7, ANCHOR = 7, RATIO = 1.2;

    /**
     * @class chart.widget.tooltip
     * @extends chart.widget.core
     * @alias TooltipWidget
     * @requires jquery
     *
     */
    var TooltipWidget = function(chart, axis, widget) {
        var self = this,
            tooltips = {},
            lineHeight = 0;

        function getFormat(k, d) {
            var key = null,
                value = null;

            if(_.typeCheck("function", widget.format)) {
                var obj = self.format(d, k);

                if(_.typeCheck("object", obj)) {
                    key = obj.key;
                    value = obj.value;
                } else {
                    value = obj;
                }
            } else {
                if(k && !d) {
                    value = k;
                }

                if(k && d) {
                    key = k;
                    value = self.format(d[k]);
                }
            }

            return {
                key: key,
                value: value
            }
        }

        function printTooltip(obj) {
            var tooltip = tooltips[obj.brush.index],
                texts = tooltip.get(1).get(1),
                width = 0,
                height = 0,
                onlyValue = false;

            if(obj.dataKey && widget.all === false) {
                setTextInTooltip([ obj.dataKey ]);
            } else {
                setTextInTooltip(obj.brush.target);
            }

            function setTextInTooltip(targets) {
                for(var i = 0; i < targets.length; i++) {
                    var key = targets[i],
                        msg = getFormat(key, obj.data);

                    texts.get(i).attr({ x: PADDING });

                    if(msg.key) {
                        texts.get(i).get(0).text(msg.key);
                    } else {
                        texts.get(i).get(1).attr({ "text-anchor": "middle" });
                        onlyValue = true;
                    }

                    if(!_.typeCheck([ "null", "undefined" ], msg.value)) {
                        texts.get(i).get(1).attr({ x: 0 }).text(msg.value);
                    }

                    width = Math.max(width, texts.get(i).size().width);
                }

                height = targets.length * lineHeight;
            }

            return {
                width: width + PADDING * 3,
                height: height + PADDING,
                onlyValue: onlyValue
            };
        }

        function existBrush(index) {
            var list = self.getIndexArray(self.widget.brush);

            return (_.inArray(index, list) == -1) ? false : true;
        }

        function getColorByKey(obj) {
            var targets = obj.brush.target;

            for(var i = 0; i < targets.length; i++) {
                if(targets[i] == obj.dataKey) {
                    return ColorUtil.lighten(self.chart.color(i, obj.brush.colors));
                }
            }

            return null;
        }

        function getTooltipXY(e, size, orient) {
            var x = e.bgX - (size.width / 2),
                y = e.bgY - size.height - ANCHOR - (PADDING / 2),
                lineX = 2;

            if(orient == "left" || orient == "right") {
                y = e.bgY - (size.height / 2) - (PADDING / 2);
            }

            if(orient == "left") {
                x = e.bgX - size.width - ANCHOR;
            } else if(orient == "right") {
                x = e.bgX + ANCHOR;
                lineX = -2;
            } else if(orient == "bottom") {
                y = e.bgY + (ANCHOR * 2);
            }

            return {
                x: x,
                y: y,
                c: lineX
            }
        }

        function setTooltipEvent() {
            var isActive = false,
                size = null,
                orient = null,
                axis = null;

            self.on("mouseover", function(obj, e) {
                if(isActive || !existBrush(obj.brush.index)) return;
                if(!obj.dataKey && !obj.data) return;

                // 툴팁 크기 가져오기
                size = printTooltip(obj);
                orient = widget.orient;
                axis = chart.axis(obj.brush.axis);

                // 툴팁 좌표 가져오기
                var xy = getTooltipXY(e, size, orient),
                    x = xy.x - chart.padding("left"),
                    y = xy.y - chart.padding("top");

                // 엑시스 범위를 넘었을 경우 처리
                if(widget.flip) {
                    if (orient == "left" && x < 0) {
                        orient = "right";
                    } else if (orient == "right" && x + size.width > axis.area("width")) {
                        orient = "left";
                    } else if (orient == "top" && y < 0) {
                        orient = "bottom";
                    } else if (orient == "bottom" && y + size.height > axis.area("height")) {
                        orient = "top";
                    }
                }

                // 툴팁 엘리먼트 가져오기
                var tooltip = tooltips[obj.brush.index],
                    line = tooltip.get(0),
                    rect = tooltip.get(1).get(0),
                    text = tooltip.get(1).get(1).translate(0, (orient != "bottom") ? lineHeight : lineHeight + ANCHOR),
                    borderColor = chart.theme("tooltipBorderColor") || getColorByKey(obj),
                    lineColor = chart.theme("tooltipLineColor") || getColorByKey(obj);

                rect.attr({
                    points: self.balloonPoints(orient, size.width, size.height, (widget.anchor) ? ANCHOR : null),
                    stroke: borderColor
                });
                line.attr({ stroke: lineColor });
                text.each(function(i, elem) {
                    elem.get(1).attr({ x: (size.onlyValue) ? size.width / 2 : size.width - PADDING });
                });
                tooltip.attr({ visibility: "visible" });

                isActive = true;
            });

            self.on("mousemove", function(obj, e) {
                if(!isActive) return;

                var tooltip = tooltips[obj.brush.index],
                    line = tooltip.get(0),
                    target = tooltip.get(1),
                    xy = getTooltipXY(e, size, orient);

                line.attr({
                    x1: e.bgX + xy.c,
                    y1: chart.padding("top") + axis.area("y"),
                    x2: e.bgX + xy.c,
                    y2: chart.padding("top") + axis.area("y2")
                });

                target.translate(xy.x, xy.y);
            });

            self.on("mouseout", function(obj, e) {
                if(!isActive) return;

                var tooltip = tooltips[obj.brush.index];
                tooltip.attr({ visibility: "hidden" });

                isActive = false;
            });
        }

        this.drawBefore = function() {
            lineHeight = chart.theme("tooltipFontSize") * RATIO;
        }

        this.draw = function() {
            var group = chart.svg.group(),
                list = this.getIndexArray(this.widget.brush);

            for(var i = 0; i < list.length; i++) {
                var brush = chart.get("brush", list[i]),
                    words = [ "" ];

                // 모든 타겟을 툴팁에 보여주는 옵션일 경우
                if(widget.all && brush.target.length > 1) {
                    for (var j = 1; j < brush.target.length; j++) {
                        words.push("");
                    }
                }

                tooltips[brush.index] = chart.svg.group({ visibility: "hidden" }, function() {
                    chart.svg.line({
                        "stroke-width": chart.theme("tooltipLineWidth"),
                        visibility: (widget.line) ? "visible" : "hidden"
                    });

                    chart.svg.group({}, function () {
                        chart.svg.polygon({
                            fill: chart.theme("tooltipBackgroundColor"),
                            "fill-opacity": chart.theme("tooltipBackgroundOpacity"),
                            "stroke-width": chart.theme("tooltipBorderWidth")
                        });

                        var text = chart.texts({
                            "font-size": chart.theme("tooltipFontSize"),
                            "fill": chart.theme("tooltipFontColor")
                        }, words, RATIO);

                        for(var i = 0; i < words.length; i++) {
                            text.get(i).append(chart.svg.tspan({ "text-anchor": "start", "font-weight": "bold", "x": PADDING }));
                            text.get(i).append(chart.svg.tspan({ "text-anchor": "end" }));
                        }
                    });
                });

                group.append(tooltips[brush.index]);
            }

            setTooltipEvent();

            return group;
        }
    }

    TooltipWidget.setup = function() {
        return {
            /** @cfg {"bottom"/"top"/"left"/"right"} Determines the side on which the tool tip is displayed (top, bottom, left, right). */
            orient: "top",
            /** @cfg {Boolean} [anchor=true] Remove tooltip's anchor */
            anchor: true,
            /** @cfg {Boolean} [all=false] Determines whether to show all values of row data.*/
            all: false,
            /** @cfg {Boolean} [line=false] Visible Guidelines. */
            line: false,
            /** @cfg {Boolean} [flip=false] When I went out of the area, reversing the tooltip. */
            flip: false,
            /** @cfg {Function} [format=null] Sets the format of the value that is displayed on the tool tip. */
            format: null,
            /** @cfg {Number} [brush=0] Specifies a brush index for which a widget is used. */
            brush: 0
        };
    }

    return TooltipWidget;
}, "chart.widget.core");