jui.define("chart.widget.zoom", [ "util.base" ], function(_) {

    /**
     * @class chart.widget.zoom
     * @extends chart.widget.core
     * @alias ZoomWidget
     * @requires util.base
     */
    var ZoomWidget = function() {
        var self = this,
            top = 0,
            left = 0;

        function setDragEvent(axisIndex, thumb, bg) {
            var axis = self.chart.axis(axisIndex),
                xtype = axis.get("x").type,
                startDate = null, // only date
                isMove = false,
                mouseStart = 0,
                thumbWidth = 0;

            self.on("axis.mousedown", function(e) {
                if(isMove) return;

                isMove = true;
                mouseStart = e.bgX;

                if(xtype == "date") { // x축이 date일 때
                    startDate = axis.x.invert(e.chartX);
                }

                self.chart.emit("zoom.start");
            }, axisIndex);

            self.on("axis.mousemove", function(e) {
                if(!isMove) return;

                thumbWidth = e.bgX - mouseStart;

                if(thumbWidth > 0) {
                    thumb.attr({
                        width: thumbWidth
                    });

                    thumb.translate(mouseStart, top + axis.area("y"));
                } else {
                    thumb.attr({
                        width: Math.abs(thumbWidth)
                    });

                    thumb.translate(mouseStart + thumbWidth, top + axis.area("y"));
                }
            }, axisIndex);

            self.on("axis.mouseup", endZoomAction, axisIndex);
            self.on("chart.mouseup", endZoomAction);
            self.on("bg.mouseup", endZoomAction);
            self.on("bg.mouseout", endZoomAction);

            function endZoomAction(e) {
                var args = [];

                isMove = false;
                if(thumbWidth == 0) return;

                if(xtype == "block") {
                    args = updateBlockGrid();
                } else if(xtype == "date") {
                    if(startDate != null) {
                        args = updateDateGrid(axis.x.invert(e.chartX));
                    }
                }

                resetDragStatus();
                self.chart.emit("zoom.end", args);
            }

            function updateBlockGrid() {
                var tick = axis.area("width") / (axis.end - axis.start),
                    x = ((thumbWidth > 0) ? mouseStart : mouseStart + thumbWidth) - left,
                    start = Math.floor(x / tick) + axis.start,
                    end = Math.ceil((x + Math.abs(thumbWidth)) / tick) + axis.start;

                // 차트 줌
                if(start < end) {
                    axis.zoom(start, end);
                    bg.attr({ "visibility": "visible" });

                    // 차트 렌더링이 활성화되지 않았을 경우
                    if(!self.chart.isRender()) {
                        self.chart.render();
                    }

                    return [ start, end ];
                }
            }

            function updateDateGrid(endDate) {
                var stime = startDate.getTime(),
                    etime = endDate.getTime();

                if(stime >= etime) return;

                var interval = self.widget.interval,
                    format = self.widget.format;

                // interval 콜백 옵션 설정
                if(_.typeCheck("function", interval)) {
                    interval = interval.apply(self.chart, [ stime, etime ]);
                }
                // format 콜백 옵션 설정
                if(_.typeCheck("function", format)) {
                    format = format.apply(self.chart, [ stime, etime ]);
                }

                axis.updateGrid("x", {
                    domain: [ stime, etime ],
                    interval: (interval != null) ? interval : axis.get("x").interval,
                    format: (format != null) ? format : axis.get("x").format
                });
                bg.attr({ "visibility": "visible" });

                // 차트 렌더링이 활성화되지 않았을 경우
                if(!self.chart.isRender()) {
                    self.chart.render();
                }

                return [ stime, etime ];
            }

            function resetDragStatus() { // 엘리먼트 및 데이터 초기화
                isMove = false;
                mouseStart = 0;
                thumbWidth = 0;
                startDate = null;

                thumb.attr({
                    width: 0
                });
            }
        }

        this.drawSection = function(axisIndex) {
            var axis = this.chart.axis(axisIndex),
                xtype = axis.get("x").type,
                domain = axis.get("x").domain,
                interval = axis.get("x").interval,
                format = axis.get("x").format,
                cw = axis.area("width"),
                ch = axis.area("height"),
                r = 12;

            return this.chart.svg.group({}, function() {
                var thumb = self.chart.svg.rect({
                    height: ch,
                    fill: self.chart.theme("zoomBackgroundColor"),
                    opacity: 0.3
                });

                var bg = self.chart.svg.group({
                    visibility: "hidden"
                }, function() {
                    self.chart.svg.rect({
                        width: cw,
                        height: ch,
                        fill: self.chart.theme("zoomFocusColor"),
                        opacity: 0.2
                    });

                    self.chart.svg.group({
                        cursor: "pointer"
                    }, function() {
                        self.chart.svg.circle({
                            r: r,
                            cx: cw,
                            cy: 0,
                            opacity: 0
                        });

                        self.chart.svg.path({
                            d: "M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10s10-4.5,10-10C22,6.5,17.5,2,12,2z M16.9,15.5l-1.4,1.4L12,13.4l-3.5,3.5 l-1.4-1.4l3.5-3.5L7.1,8.5l1.4-1.4l3.5,3.5l3.5-3.5l1.4,1.4L13.4,12L16.9,15.5z",
                            fill: self.chart.theme("zoomFocusColor")
                        }).translate(cw - r, -r);
                    }).on("click", function(e) {
                        bg.attr({ visibility: "hidden" });

                        if(xtype == "block") {
                            axis.screen(1);
                        } else if(xtype == "date") {
                            axis.updateGrid("x", {
                                domain: domain,
                                interval: interval,
                                format: format
                            });
                        }

                        // 차트 렌더링이 활성화되지 않았을 경우
                        if(!self.chart.isRender()) {
                            self.chart.render();
                        }

                        // 줌 종료
                        self.chart.emit("zoom.close");
                    });

                }).translate(left + axis.area("x"), top + axis.area("y"));

                setDragEvent(axisIndex, thumb, bg);
            });
        }

        this.drawBefore = function() {
            top = this.chart.padding("top");
            left = this.chart.padding("left");
        }

        this.draw = function() {
            var g = this.chart.svg.group(),
                list = (_.typeCheck("array", this.widget.axis)) ? this.widget.axis : [ this.widget.axis ];

            for (var i = 0; i < list.length; i++) {
                g.append(this.drawSection(list[i]));
            }

            return g;
        }
    }

    ZoomWidget.setup = function() {
        return {
            axis: 0,

            /** @cfg {Number} [interval=1000] Sets the interval of the scale displayed on a grid.*/
            interval: null,
            /** @cfg {Function} [format=null]  Determines whether to format the value on an axis. */
            format: null
        }
    }

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