/**
 * echarts组件： 类目轴
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */
define(function (require) {
    var Base = require('./base');
    
    // 图形依赖
    var TextShape = require('zrender/shape/Text');
    var LineShape = require('zrender/shape/Line');
    var RectangleShape = require('zrender/shape/Rectangle');
    
    var ecConfig = require('../config');
    // 类目轴
    ecConfig.categoryAxis =  {
        zlevel: 0,                  // 一级层叠
        z: 0,                       // 二级层叠
        show: true,
        position: 'bottom',    // 位置
        name: '',              // 坐标轴名字，默认为空
        nameLocation: 'end',   // 坐标轴名字位置，支持'start' | 'end'
        nameTextStyle: {},     // 坐标轴文字样式，默认取全局样式
        boundaryGap: true,     // 类目起始和结束两端空白策略
        axisLine: {            // 坐标轴线
            show: true,        // 默认显示，属性show控制显示与否
            onZero: true,
            lineStyle: {       // 属性lineStyle控制线条样式
                color: '#48b',
                width: 2,
                type: 'solid'
            }
        },
        axisTick: {            // 坐标轴小标记
            show: true,        // 属性show控制显示与否，默认不显示
            interval: 'auto',
            inside: false,    // 控制小标记是否在grid里 
            // onGap: null,
            length :5,         // 属性length控制线长
            lineStyle: {       // 属性lineStyle控制线条样式
                color: '#333',
                width: 1
            }
        },
        axisLabel: {           // 坐标轴文本标签，详见axis.axisLabel
            show: true,
            interval: 'auto',
            rotate: 0,
            margin: 8,
            // clickable: false,
            // formatter: null,
            textStyle: {       // 其余属性默认使用全局文本样式，详见TEXTSTYLE
                color: '#333'
            }
        },
        splitLine: {           // 分隔线
            show: true,        // 默认显示，属性show控制显示与否
            // onGap: null,
            lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式
                color: ['#ccc'],
                width: 1,
                type: 'solid'
            }
        },
        splitArea: {           // 分隔区域
            show: false,       // 默认不显示，属性show控制显示与否
            // onGap: null,
            areaStyle: {       // 属性areaStyle（详见areaStyle）控制区域样式
                color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
            }
        }
    };

    var zrUtil = require('zrender/tool/util');
    var zrArea = require('zrender/tool/area');
    
    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} option 类目轴参数
     * @param {Grid} component 组件
     */
    function CategoryAxis(ecTheme, messageCenter, zr, option, myChart, axisBase) {
        if (option.data.length < 1) {
            console.error('option.data.length < 1.');
            return;
        }
        
        Base.call(this, ecTheme, messageCenter, zr, option, myChart);
        
        this.grid = this.component.grid;
        
        for (var method in axisBase) {
            this[method] = axisBase[method];
        }
        
        this.refresh(option);
    }
    
    CategoryAxis.prototype = {
        type : ecConfig.COMPONENT_TYPE_AXIS_CATEGORY,
        _getReformedLabel : function (idx) {
            var data = this.getDataFromOption(this.option.data[idx]);
            var formatter = this.option.data[idx].formatter 
                            || this.option.axisLabel.formatter;
            if (formatter) {
                if (typeof formatter == 'function') {
                    data = formatter.call(this.myChart, data);
                }
                else if (typeof formatter == 'string') {
                    data = formatter.replace('{value}', data);
                }
            }
            return data;
        },
        
        /**
         * 计算标签显示挑选间隔
         */
        _getInterval : function () {
            var interval   = this.option.axisLabel.interval;
            if (interval == 'auto') {
                // 麻烦的自适应计算
                var fontSize = this.option.axisLabel.textStyle.fontSize;
                var data = this.option.data;
                var dataLength = this.option.data.length;

                if (this.isHorizontal()) {
                    // 横向
                    if (dataLength > 3) {
                        var gap = this.getGap();
                        var isEnough = false;
                        var labelSpace;
                        var labelSize;
                        var step = Math.floor(0.5 / gap);
                        step = step < 1 ? 1 : step;
                        interval = Math.floor(15 / gap);
                        while (!isEnough && interval < dataLength) {
                            interval += step;
                            isEnough = true;
                            labelSpace = Math.floor(gap * interval); // 标签左右至少间隔为3px
                            for (var i = Math.floor((dataLength - 1)/ interval) * interval; 
                                 i >= 0; i -= interval
                             ) {
                                if (this.option.axisLabel.rotate !== 0) {
                                    // 有旋转
                                    labelSize = fontSize;
                                }
                                else if (data[i].textStyle) {
                                    labelSize = zrArea.getTextWidth(
                                        this._getReformedLabel(i),
                                        this.getFont(
                                            zrUtil.merge(
                                                data[i].textStyle,
                                                this.option.axisLabel.textStyle
                                           )
                                        )
                                    );
                                }
                                else {
                                    /*
                                    labelSize = zrArea.getTextWidth(
                                        this._getReformedLabel(i),
                                        font
                                    );
                                    */
                                    // 不定义data级特殊文本样式，用fontSize优化getTextWidth
                                    var label = this._getReformedLabel(i) + '';
                                    var wLen = (label.match(/\w/g) || '').length;
                                    var oLen = label.length - wLen;
                                    labelSize = wLen * fontSize * 2 / 3 + oLen * fontSize;
                                }

                                if (labelSpace < labelSize) {
                                    // 放不下，中断循环让interval++
                                    isEnough = false;
                                    break;
                                }
                            }
                        }
                    }
                    else {
                        // 少于3个则全部显示
                        interval = 1;
                    }
                }
                else {
                    // 纵向
                    if (dataLength > 3) {
                        var gap = this.getGap();
                        interval = Math.floor(11 / gap);
                        // 标签上下至少间隔为3px
                        while ((gap * interval - 6) < fontSize
                                && interval < dataLength
                        ) {
                            interval++;
                        }
                    }
                    else {
                        // 少于3个则全部显示
                        interval = 1;
                    }
                }
            }
            else {
                // 用户自定义间隔，支持funtion
                interval = typeof interval == 'function' ? 1 : (interval - 0 + 1);
            }

            return interval;
        },
        
        /**
         * 绘制图形
         */
        _buildShape : function () {
            // 标签显示的挑选间隔
            this._interval = this._getInterval();
            if (!this.option.show) {
                return;
            }
            this.option.splitArea.show && this._buildSplitArea();
            this.option.splitLine.show && this._buildSplitLine();
            this.option.axisLine.show && this._buildAxisLine();
            this.option.axisTick.show && this._buildAxisTick();
            this.option.axisLabel.show && this._buildAxisLabel();

            for (var i = 0, l = this.shapeList.length; i < l; i++) {
                this.zr.addShape(this.shapeList[i]);
            }
        },

        // 小标记
        _buildAxisTick : function () {
            var axShape;
            var data       = this.option.data;
            var dataLength = this.option.data.length;
            var tickOption = this.option.axisTick;
            var length     = tickOption.length;
            var color      = tickOption.lineStyle.color;
            var lineWidth  = tickOption.lineStyle.width;
            var intervalFunction = typeof tickOption.interval == 'function'
                                   ? tickOption.interval 
                                   : tickOption.interval == 'auto'
                                     ? typeof this.option.axisLabel.interval == 'function'
                                       ? this.option.axisLabel.interval : false
                                     : false;
            var interval   = intervalFunction
                             ? 1
                             : tickOption.interval == 'auto' 
                               ? this._interval
                               : (tickOption.interval - 0 + 1);
            var onGap      = tickOption.onGap;
            var optGap     = onGap 
                             ? (this.getGap() / 2) 
                             : typeof onGap == 'undefined'
                                   ? (this.option.boundaryGap ? (this.getGap() / 2) : 0)
                                   : 0;
            var startIndex = optGap > 0 ? -interval : 0;                       
            if (this.isHorizontal()) {
                // 横向
                var yPosition = this.option.position == 'bottom'
                        ? (tickOption.inside 
                           ? (this.grid.getYend() - length - 1) : (this.grid.getYend() + 1))
                        : (tickOption.inside 
                           ? (this.grid.getY() + 1) : (this.grid.getY() - length - 1));
                var x;
                for (var i = startIndex; i < dataLength; i += interval) {
                    if (intervalFunction && !intervalFunction(i, data[i])) {
                        // 回调并且回调返回false则跳过渲染
                        continue;
                    }
                    // 亚像素优化
                    x = this.subPixelOptimize(
                        this.getCoordByIndex(i) + (i >= 0 ? optGap : 0), lineWidth
                    );
                    axShape = {
                        _axisShape : 'axisTick',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable : false,
                        style : {
                            xStart : x,
                            yStart : yPosition,
                            xEnd : x,
                            yEnd : yPosition + length,
                            strokeColor : color,
                            lineWidth : lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
            else {
                // 纵向
                var xPosition = this.option.position == 'left'
                    ? (tickOption.inside 
                       ? (this.grid.getX() + 1) : (this.grid.getX() - length - 1))
                    : (tickOption.inside 
                       ? (this.grid.getXend() - length - 1) : (this.grid.getXend() + 1));
                        
                var y;
                for (var i = startIndex; i < dataLength; i += interval) {
                    if (intervalFunction && !intervalFunction(i, data[i])) {
                        // 回调并且回调返回false则中断渲染
                        continue;
                    }
                    // 亚像素优化
                    y = this.subPixelOptimize(
                        this.getCoordByIndex(i) - (i >= 0 ? optGap : 0), lineWidth
                    );
                    axShape = {
                        _axisShape : 'axisTick',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable : false,
                        style : {
                            xStart : xPosition,
                            yStart : y,
                            xEnd : xPosition + length,
                            yEnd : y,
                            strokeColor : color,
                            lineWidth : lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
        },

        // 坐标轴文本
        _buildAxisLabel : function () {
            var axShape;
            var data       = this.option.data;
            var dataLength = this.option.data.length;
            var labelOption = this.option.axisLabel;
            var rotate     = labelOption.rotate;
            var margin     = labelOption.margin;
            var clickable  = labelOption.clickable;
            var textStyle  = labelOption.textStyle;
            var intervalFunction = typeof labelOption.interval == 'function'
                                   ? labelOption.interval : false;
            var dataTextStyle;

            if (this.isHorizontal()) {
                // 横向
                var yPosition;
                var baseLine;
                if (this.option.position == 'bottom') {
                    yPosition = this.grid.getYend() + margin;
                    baseLine = 'top';
                }
                else {
                    yPosition = this.grid.getY() - margin;
                    baseLine = 'bottom';
                }

                for (var i = 0; i < dataLength; i += this._interval) {
                    if ((intervalFunction && !intervalFunction(i, data[i])) 
                        // 回调并且回调返回false则中断渲染
                        || this._getReformedLabel(i) === '' // 空文本优化
                    ) {
                        continue;
                    }
                    dataTextStyle = zrUtil.merge(
                        data[i].textStyle || {},
                        textStyle
                    );
                    axShape = {
                        // shape : 'text',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase() + 3,
                        hoverable : false,
                        style : {
                            x : this.getCoordByIndex(i),
                            y : yPosition,
                            color : dataTextStyle.color,
                            text : this._getReformedLabel(i),
                            textFont : this.getFont(dataTextStyle),
                            textAlign : dataTextStyle.align || 'center',
                            textBaseline : dataTextStyle.baseline || baseLine
                        }
                    };
                    if (rotate) {
                        axShape.style.textAlign = rotate > 0
                                                  ? (this.option.position == 'bottom'
                                                    ? 'right' : 'left')
                                                  : (this.option.position == 'bottom'
                                                    ? 'left' : 'right');
                        axShape.rotation = [
                            rotate * Math.PI / 180,
                            axShape.style.x,
                            axShape.style.y
                        ];
                    }
                    this.shapeList.push(new TextShape(
                        this._axisLabelClickable(clickable, axShape)
                    ));
                }
            }
            else {
                // 纵向
                var xPosition;
                var align;
                if (this.option.position == 'left') {
                    xPosition = this.grid.getX() - margin;
                    align = 'right';
                }
                else {
                    xPosition = this.grid.getXend() + margin;
                    align = 'left';
                }

                for (var i = 0; i < dataLength; i += this._interval) {
                    if ((intervalFunction && !intervalFunction(i, data[i])) 
                        // 回调并且回调返回false则中断渲染
                        || this._getReformedLabel(i) === '' // 空文本优化
                    ) {
                        continue;
                    }
                    dataTextStyle = zrUtil.merge(
                        data[i].textStyle || {},
                        textStyle
                    );
                    axShape = {
                        // shape : 'text',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase() + 3,
                        hoverable : false,
                        style : {
                            x : xPosition,
                            y : this.getCoordByIndex(i),
                            color : dataTextStyle.color,
                            text : this._getReformedLabel(i),
                            textFont : this.getFont(dataTextStyle),
                            textAlign : dataTextStyle.align || align,
                            textBaseline : dataTextStyle.baseline 
                                           || (i === 0 && this.option.name !== '')
                                               ? 'bottom'
                                               : (i == (dataLength - 1) 
                                                  && this.option.name !== '')
                                                 ? 'top'
                                                 : 'middle'
                        }
                    };
                    
                    if (rotate) {
                        axShape.rotation = [
                            rotate * Math.PI / 180,
                            axShape.style.x,
                            axShape.style.y
                        ];
                    }
                    this.shapeList.push(new TextShape(
                        this._axisLabelClickable(clickable, axShape)
                    ));
                }
            }
        },
        
        _buildSplitLine : function () {
            var axShape;
            var data        = this.option.data;
            var dataLength  = this.option.data.length;
            var sLineOption = this.option.splitLine;
            var lineType    = sLineOption.lineStyle.type;
            var lineWidth   = sLineOption.lineStyle.width;
            var color       = sLineOption.lineStyle.color;
            color = color instanceof Array ? color : [color];
            var colorLength = color.length;
            
            // splitLine随axisLable
            var intervalFunction = typeof this.option.axisLabel.interval == 'function'
                                   ? this.option.axisLabel.interval : false;

            var onGap      = sLineOption.onGap;
            var optGap     = onGap 
                             ? (this.getGap() / 2) 
                             : typeof onGap == 'undefined'
                                   ? (this.option.boundaryGap ? (this.getGap() / 2) : 0)
                                   : 0;
            dataLength -= (onGap || (typeof onGap == 'undefined' && this.option.boundaryGap)) 
                          ? 1 : 0;
            if (this.isHorizontal()) {
                // 横向
                var sy = this.grid.getY();
                var ey = this.grid.getYend();
                var x;

                for (var i = 0; i < dataLength; i += this._interval) {
                    if (intervalFunction && !intervalFunction(i, data[i])) {
                        // 回调并且回调返回false则跳过渲染
                        continue;
                    }
                    // 亚像素优化
                    x = this.subPixelOptimize(
                        this.getCoordByIndex(i) + optGap, lineWidth
                    );
                    axShape = {
                        // shape : 'line',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable : false,
                        style : {
                            xStart : x,
                            yStart : sy,
                            xEnd : x,
                            yEnd : ey,
                            strokeColor : color[(i / this._interval) % colorLength],
                            lineType : lineType,
                            lineWidth : lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }

            }
            else {
                // 纵向
                var sx = this.grid.getX();
                var ex = this.grid.getXend();
                var y;

                for (var i = 0; i < dataLength; i += this._interval) {
                    if (intervalFunction && !intervalFunction(i, data[i])) {
                        // 回调并且回调返回false则跳过渲染
                        continue;
                    }
                    // 亚像素优化
                    y = this.subPixelOptimize(
                        this.getCoordByIndex(i) - optGap, lineWidth
                    );
                    axShape = {
                        // shape : 'line',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable : false,
                        style : {
                            xStart : sx,
                            yStart : y,
                            xEnd : ex,
                            yEnd : y,
                            strokeColor : color[(i / this._interval) % colorLength],
                            lineType : lineType,
                            lineWidth : lineWidth
                        }
                    };
                    this.shapeList.push(new LineShape(axShape));
                }
            }
        },

        _buildSplitArea : function () {
            var axShape;
            var data        = this.option.data;
            var sAreaOption = this.option.splitArea;
            var color = sAreaOption.areaStyle.color;
            if (!(color instanceof Array)) {
                // 非数组一律认为是单一颜色的字符串，单一颜色则用一个背景，颜色错误不负责啊！！！
                axShape = {
                    // shape : 'rectangle',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable : false,
                    style : {
                        x : this.grid.getX(),
                        y : this.grid.getY(),
                        width : this.grid.getWidth(),
                        height : this.grid.getHeight(),
                        color : color
                        // type : this.option.splitArea.areaStyle.type,
                    }
                };
                this.shapeList.push(new RectangleShape(axShape));
            }
            else {
                // 多颜色
                var colorLength = color.length;
                var dataLength  = this.option.data.length;

                // splitArea随axisLable
                var intervalFunction = typeof this.option.axisLabel.interval == 'function'
                                       ? this.option.axisLabel.interval : false;
        
                var onGap      = sAreaOption.onGap;
                var optGap     = onGap 
                                 ? (this.getGap() / 2) 
                                 : typeof onGap == 'undefined'
                                       ? (this.option.boundaryGap ? (this.getGap() / 2) : 0)
                                       : 0;
                if (this.isHorizontal()) {
                    // 横向
                    var y = this.grid.getY();
                    var height = this.grid.getHeight();
                    var lastX = this.grid.getX();
                    var curX;
    
                    for (var i = 0; i <= dataLength; i += this._interval) {
                        if (intervalFunction && !intervalFunction(i, data[i]) && i < dataLength) {
                            // 回调并且回调返回false则跳过渲染
                            continue;
                        }
                        curX = i < dataLength
                               ? (this.getCoordByIndex(i) + optGap)
                               : this.grid.getXend();
                        axShape = {
                            // shape : 'rectangle',
                            zlevel: this.getZlevelBase(),
                            z: this.getZBase(),
                            hoverable : false,
                            style : {
                                x : lastX,
                                y : y,
                                width : curX - lastX,
                                height : height,
                                color : color[(i / this._interval) % colorLength]
                                // type : this.option.splitArea.areaStyle.type,
                            }
                        };
                        this.shapeList.push(new RectangleShape(axShape));
                        lastX = curX;
                    }
                }
                else {
                    // 纵向
                    var x = this.grid.getX();
                    var width = this.grid.getWidth();
                    var lastYend = this.grid.getYend();
                    var curY;
    
                    for (var i = 0; i <= dataLength; i += this._interval) {
                        if (intervalFunction && !intervalFunction(i, data[i]) && i < dataLength) {
                            // 回调并且回调返回false则跳过渲染
                            continue;
                        }
                        curY = i < dataLength
                               ? (this.getCoordByIndex(i) - optGap)
                               : this.grid.getY();
                        axShape = {
                            // shape : 'rectangle',
                            zlevel: this.getZlevelBase(),
                            z: this.getZBase(),
                            hoverable : false,
                            style : {
                                x : x,
                                y : curY,
                                width : width,
                                height : lastYend - curY,
                                color : color[(i / this._interval) % colorLength]
                                // type : this.option.splitArea.areaStyle.type
                            }
                        };
                        this.shapeList.push(new RectangleShape(axShape));
                        lastYend = curY;
                    }
                }
            }
        },

        /**
         * 刷新
         */
        refresh : function (newOption) {
            if (newOption) {
                this.option = this.reformOption(newOption);
                // 通用字体设置
                this.option.axisLabel.textStyle = this.getTextStyle(
                    this.option.axisLabel.textStyle
                );
            }
            this.clear();
            this._buildShape();
        },

        /**
         * 返回间隔
         */
        getGap : function () {
            var dataLength = this.option.data.length;
            var total = this.isHorizontal()
                        ? this.grid.getWidth()
                        : this.grid.getHeight();
            if (this.option.boundaryGap) {              // 留空
                return total / dataLength;
            }
            else {                                      // 顶头
                return total / (dataLength > 1 ? (dataLength - 1) : 1);
            }
        },

        // 根据值换算位置
        getCoord : function (value) {
            var data = this.option.data;
            var dataLength = data.length;
            var gap = this.getGap();
            var position = this.option.boundaryGap ? (gap / 2) : 0;

            for (var i = 0; i < dataLength; i++) {
                if (this.getDataFromOption(data[i]) == value) {
                    if (this.isHorizontal()) {
                        // 横向
                        position = this.grid.getX() + position;
                    }
                    else {
                        // 纵向
                        position = this.grid.getYend() - position;
                    }
                    
                    return position;
                    // Math.floor可能引起一些偏差，但性能会更好
                    /* 准确更重要
                    return (i === 0 || i == dataLength - 1)
                           ? position
                           : Math.floor(position);
                    */
                }
                position += gap;
            }
        },

        // 根据类目轴数据索引换算位置
        getCoordByIndex : function (dataIndex) {
            if (dataIndex < 0) {
                if (this.isHorizontal()) {
                    return this.grid.getX();
                }
                else {
                    return this.grid.getYend();
                }
            }
            else if (dataIndex > this.option.data.length - 1) {
                if (this.isHorizontal()) {
                    return this.grid.getXend();
                }
                else {
                    return this.grid.getY();
                }
            }
            else {
                var gap = this.getGap();
                var position = this.option.boundaryGap ? (gap / 2) : 0;
                position += dataIndex * gap;
                
                if (this.isHorizontal()) {
                    // 横向
                    position = this.grid.getX() + position;
                }
                else {
                    // 纵向
                    position = this.grid.getYend() - position;
                }
                
                return position;
                /* 准确更重要
                return (dataIndex === 0 || dataIndex == this.option.data.length - 1)
                       ? position
                       : Math.floor(position);
                */
            }
        },

        // 根据类目轴数据索引换算类目轴名称
        getNameByIndex : function (dataIndex) {
            return this.getDataFromOption(this.option.data[dataIndex]);
        },
        
        // 根据类目轴名称换算类目轴数据索引
        getIndexByName : function (name) {
            var data = this.option.data;
            var dataLength = data.length;

            for (var i = 0; i < dataLength; i++) {
                if (this.getDataFromOption(data[i]) == name) {
                    return i;
                }
            }
            
            return -1;
        },
        
        // 根据位置换算值
        getValueFromCoord : function() {
            return '';
        },

        /**
         * 根据类目轴数据索引返回是否为主轴线
         * @param {number} dataIndex 类目轴数据索引
         * @return {boolean} 是否为主轴
         */
        isMainAxis : function (dataIndex) {
            return dataIndex % this._interval === 0;
        }
    };
    
    zrUtil.inherits(CategoryAxis, Base);
    
    require('../component').define('categoryAxis', CategoryAxis);
    
    return CategoryAxis;
});