/**
 * echarts图表类：矩形树图
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Loutongbing (娄同兵, loutongbing@126.com)
 */

define(function (require) {
    var ChartBase = require('./base');
    // 图形依赖
    var toolArea = require('zrender/tool/area');
    // 图形依赖
    var RectangleShape = require('zrender/shape/Rectangle');
    var TextShape = require('zrender/shape/Text');
    var LineShape = require('zrender/shape/Line');
    // 布局依赖
    var TreeMapLayout = require('../layout/TreeMap');
    // 数据依赖
    var Tree = require('../data/Tree');

    var ecConfig = require('../config');
    // 维恩图默认参数
    ecConfig.treemap = {
        zlevel: 0,                  // 一级层叠
        z: 1,                       // 二级层叠
        calculable: false,
        clickable: true,
        center: ['50%', '50%'],
        size: ['80%', '80%'],
        root: '',
        itemStyle: {
            normal: {
                // color: 各异,
                label: {
                    show: true,
                    x: 5,
                    y: 12,
                    textStyle: {
                        align: 'left',
                        color: '#000',
                        fontFamily: 'Arial',
                        fontSize: 13,
                        fontStyle: 'normal',
                        fontWeight: 'normal'
                    }
                },
                breadcrumb: {
                    show: true,
                    textStyle: {}
                },
                borderWidth: 1,
                borderColor: '#ccc',
                childBorderWidth: 1,
                childBorderColor: '#ccc'
            },
            emphasis: {}
        }
    };

    var ecData = require('../util/ecData');
    var zrConfig = require('zrender/config');
    var zrEvent = require('zrender/tool/event');
    var zrUtil = require('zrender/tool/util');
    var zrColor = require('zrender/tool/color');

    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} series 数据
     * @param {Object} component 组件
     * @constructor
     * @exports Treemap
     */
    function Treemap(ecTheme, messageCenter, zr, option, myChart) {
        // 图表基类
        ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
        this.refresh(option);
        var self = this;
        self._onclick = function (params) {
            return self.__onclick(params);
        };
        self.zr.on(zrConfig.EVENT.CLICK, self._onclick);
    }
    Treemap.prototype = {
        type : ecConfig.CHART_TYPE_TREEMAP,
        /**
         * 刷新
         */
        refresh: function (newOption) {
            this.clear();

            if (newOption) {
                this.option = newOption;
                this.series = this.option.series;
            }

            // Map storing all trees of series
            this._treesMap = {};

            var series = this.series;
            var legend = this.component.legend;

            for (var i = 0; i < series.length; i++) {
                if (series[i].type === ecConfig.CHART_TYPE_TREEMAP) {
                    series[i] = this.reformOption(series[i]);

                    var seriesName = series[i].name || '';
                    this.selectedMap[seriesName] = 
                        legend ? legend.isSelected(seriesName) : true;
                    if (!this.selectedMap[seriesName]) {
                        continue;
                    }

                    this._buildSeries(series[i], i);
                }
            }
        },

        _buildSeries: function(series, seriesIndex) {
            var tree = Tree.fromOptionData(series.name, series.data);

            this._treesMap[seriesIndex] = tree;

            var treeRoot = series.root && tree.getNodeById(series.root) || tree.root;
            this._buildTreemap(treeRoot, seriesIndex);
        },

        /**
         * 构建单个
         *
         * @param {Object} data 数据
         */
        _buildTreemap : function (treeRoot, seriesIndex) {

            // 清除之前的 shapes
            var shapeList = this.shapeList;
            for (var i = 0; i < shapeList.length;) {
                var shape = shapeList[i];
                if (ecData.get(shape, 'seriesIndex') === seriesIndex) {
                    this.zr.delShape(shapeList[i]);
                    shapeList.splice(i, 1);
                }
                else {
                    i++;
                }
            }

            var currentShapeLen = shapeList.length;
            var series = this.series[seriesIndex];

            var itemStyle = series.itemStyle;
            var treemapWidth = this.parsePercent(series.size[0], this.zr.getWidth()) || 400;
            var treemapHeight = this.parsePercent(series.size[1], this.zr.getHeight()) || 500;
            var center = this.parseCenter(this.zr, series.center);
            var treemapX = center[0] -  treemapWidth * 0.5;
            var treemapY = center[1] -  treemapHeight * 0.5;

            var treemapArea = treemapWidth * treemapHeight; // 计算总面积
            // 遍历数组，通过value与area0计算实际面积area
            var sum = 0;
            var areaArr = [];

            var children = treeRoot.children;
            for (var i = 0; i < children.length; i++) {
                sum += children[i].data.value;
            }
            for (var j = 0; j < children.length; j++) {
                areaArr.push(children[j].data.value * treemapArea / sum);
            }
            var treeMapLayout = new TreeMapLayout({
                x: treemapX,
                y: treemapY,
                width: treemapWidth,
                height: treemapHeight
            });
            var locationArr = treeMapLayout.run(areaArr);

            for (var k = 0; k < locationArr.length; k++) {
                var dataItem = children[k].data;
                var rect = locationArr[k];
                var queryTarget = [dataItem.itemStyle, itemStyle];
                var itemStyleMerged = this.deepMerge(queryTarget);
                if (!itemStyleMerged.normal.color) {
                    itemStyleMerged.normal.color = this.zr.getColor(k);
                }
                if (!itemStyleMerged.emphasis.color) {
                    itemStyleMerged.emphasis.color = itemStyleMerged.normal.color;
                }
                this._buildItem(
                    dataItem,
                    itemStyleMerged,
                    rect,
                    seriesIndex,
                    k
                );
                // 绘制二级节点
                if (dataItem.children) {
                    this._buildChildrenTreemap(
                        dataItem.children,
                        itemStyleMerged,
                        rect,
                        seriesIndex
                    );
                }
            }

            if (this.query(series, 'itemStyle.normal.breadcrumb.show')) {
                this._buildBreadcrumb(
                    treeRoot, seriesIndex, treemapX, treemapY + treemapHeight
                );   
            }

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

        /**
         * 构建单个item
         */
        _buildItem : function (
            dataItem,
            itemStyle,
            rect,
            seriesIndex,
            dataIndex
        ) {
            var series = this.series;
            var rectangle = this.getRectangle(
                dataItem,
                itemStyle,
                rect
            );
            // todo
            ecData.pack(
                rectangle,
                series[seriesIndex], seriesIndex,
                dataItem, dataIndex,
                dataItem.name
            );
            this.shapeList.push(rectangle);
        },

        /**
         * 构建矩形
         * @param {Object} data 数据
         * @param {Object} itemStyle 合并后的样式
         * @param {number} x 矩形横坐标
         * @param {number} y 矩形纵坐标
         * @param {number} width 矩形宽
         * @param {number} height 矩形高
         * @return {Object} 返回一个矩形
         */
        getRectangle: function (
            dataItem,
            itemStyle,
            rect
        ) {
            var emphasis = itemStyle.emphasis;
            var normal = itemStyle.normal;
            var textShape = this.getLabel(
                itemStyle,
                rect,
                dataItem.name,
                dataItem.value
            );
            var hoverable = this.option.hoverable;
            var rectangleShape = {
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
                hoverable: hoverable,
                clickable: true,
                style: zrUtil.merge(
                    {
                        x: rect.x,
                        y: rect.y,
                        width: rect.width,
                        height: rect.height,
                        brushType: 'both',
                        color: normal.color,
                        lineWidth: normal.borderWidth,
                        strokeColor: normal.borderColor
                    },
                    textShape.style,
                    true
                ),
                highlightStyle: zrUtil.merge(
                    {
                        color: emphasis.color,
                        lineWidth: emphasis.borderWidth,
                        strokeColor: emphasis.borderColor
                    },
                    textShape.highlightStyle,
                    true
                )
            };
            return new RectangleShape(rectangleShape);
        },
        /**
         * 获取label样式
         * @param {Object} itemStyle 合并后的样式
         * @param {Object} rect 矩形信息
         * @param {string} name 数据名称
         * @param {number} value 数据值
         * @return {Object} 返回label的样式
         */
        getLabel: function (
            itemStyle,
            rect,
            name,
            value
        ) {
            var normalTextStyle = itemStyle.normal.label.textStyle;
            var queryTarget = [itemStyle.emphasis.label.textStyle, normalTextStyle];
            var emphasisTextStyle = this.deepMerge(queryTarget);

            var formatter = itemStyle.normal.label.formatter;
            var text = this.getLabelText(name, value, formatter);
            var textFont = this.getFont(normalTextStyle);
            var textWidth = toolArea.getTextWidth(text, textFont);
            var textHeight = toolArea.getTextHeight(text, textFont);

            var emphasisFormatter = this.deepQuery(
                [itemStyle.emphasis, itemStyle.normal],
                'label.formatter'
            );
            var emphasisText = this.getLabelText(name, value, emphasisFormatter);
            var emphasisTextFont = this.getFont(emphasisTextStyle);
            var emphasisTextWidth = toolArea.getTextWidth(text, emphasisTextFont);
            var emphasisTextHeight = toolArea.getTextHeight(text, emphasisTextFont);
            if (!itemStyle.normal.label.show) {
                text = '';
            }
            else if (itemStyle.normal.label.x + textWidth > rect.width
                || itemStyle.normal.label.y + textHeight > rect.height) {
                text = '';
            }

            if (!itemStyle.emphasis.label.show) {
                emphasisText = '';
            }
            else if (emphasisTextStyle.x + emphasisTextWidth > rect.width
                || emphasisTextStyle.y + emphasisTextHeight > rect.height) {
                emphasisText = '';
            }

            // 用label方法写title
            var textShape = {
                style: {
                    textX: rect.x + itemStyle.normal.label.x,
                    textY: rect.y + itemStyle.normal.label.y,
                    text: text,
                    textPosition: 'specific',
                    textColor: normalTextStyle.color,
                    textFont: textFont
                },
                highlightStyle: {
                    textX: rect.x + itemStyle.emphasis.label.x,
                    textY: rect.y + itemStyle.emphasis.label.y,
                    text: emphasisText,
                    textColor: emphasisTextStyle.color,
                    textPosition: 'specific'
                }
            };
            return textShape;
        },
        /**
         * 支持formatter
         * @param {string} name 数据名称
         * @param {number} value 数据值
         * @param {string|Object} formatter 构造器
         * @return {Object} 返回label的样式
         */
        getLabelText: function (name, value, formatter) {
            if (formatter) {
                if (typeof formatter === 'function') {
                    return formatter.call(
                        this.myChart,
                        name,
                        value
                    );
                }
                else if (typeof formatter === 'string') {
                    formatter = formatter.replace('{b}', '{b0}')
                                         .replace('{c}', '{c0}');
                    formatter = formatter.replace('{b0}', name)
                                         .replace('{c0}', value);
                    return formatter;
                }
            }
            else {
                return name;
            }
        },
        /*
         * 构建子级矩形图，这里用线表示不再画矩形
         *
         * @param {Object} data 数据
         * @param {Object} rect
         * @return
        */
        _buildChildrenTreemap: function (
            data,
            itemStyle,
            rect,
            seriesIndex
        ) {
            var treemapArea = rect.width * rect.height; // 计算总面积
            // 遍历数组，通过value与area0计算实际面积area
            var sum = 0;
            var areaArr = [];
            for (var i = 0; i < data.length; i++) {
                sum += data[i].value;
            }
            for (var j = 0; j < data.length; j++) {
                areaArr.push(data[j].value * treemapArea / sum);
            }
            var treeMapLayout = new TreeMapLayout({
                x: rect.x,
                y: rect.y,
                width: rect.width,
                height: rect.height
            });
            var locationArr = treeMapLayout.run(areaArr);
            var lineWidth = itemStyle.normal.childBorderWidth;
            var lineColor = itemStyle.normal.childBorderColor;
            for (var k = 0; k < locationArr.length; k++) {
                var item = locationArr[k];
                var lines = [];
                // 容器边框不能重复画
                // 上边
                if (rect.y.toFixed(2) !== item.y.toFixed(2)) {
                    lines.push(this._getLine(
                        item.x,
                        item.y,
                        item.x + item.width,
                        item.y,
                        lineWidth,
                        lineColor
                    ));
                }
                // 左边
                if (rect.x.toFixed(2) !== item.x.toFixed(2)) {
                    lines.push(this._getLine(
                        item.x,
                        item.y,
                        item.x,
                        item.y + item.height,
                        lineWidth,
                        lineColor
                    ));
                }
                // 下边
                if ((rect.y + rect.height).toFixed(2) !== (item.y + item.height).toFixed(2)) {
                    lines.push(this._getLine(
                        item.x,
                        item.y + item.height,
                        item.x + item.width,
                        item.y + item.height,
                        lineWidth,
                        lineColor
                    ));
                }
                // 右边
                if ((rect.x + rect.width).toFixed(2) !== (item.x + item.width).toFixed(2)) {
                    lines.push(this._getLine(
                        item.x + item.width,
                        item.y,
                        item.x + item.width,
                        item.y + item.height,
                        lineWidth,
                        lineColor
                    ));
                }
                for (var l = 0; l < lines.length; l++) {
                    ecData.set(lines[l], 'seriesIndex', seriesIndex);
                    this.shapeList.push(lines[l]);
                }
            }
        },
        /*
         * 构建线段
         * @param {number} xStart 开始坐标
         * @param {number} yStart 开始坐标
         * @param {number} xEnd 结束坐标
         * @param {number} yEnd 结束坐标
         * @param {number} lineWidth 线宽
         * @param {number} lineColor 颜色
         * @return {Object} 返回一个线段
         */
        _getLine : function (
            xStart,
            yStart,
            xEnd,
            yEnd,
            lineWidth,
            lineColor
        ) {
            var lineShape = {
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
                hoverable: false,
                style: {
                    xStart: xStart,
                    yStart: yStart,
                    xEnd: xEnd,
                    yEnd: yEnd,
                    lineWidth: lineWidth,
                    strokeColor: lineColor
                }
            };
            return new LineShape(lineShape);

        },

        _buildBreadcrumb: function (treeRoot, seriesIndex, x, y) {
            var stack = [];

            var current = treeRoot;
            while (current) {
                stack.unshift(current.data.name);
                current = current.parent;
            }

            var series = this.series[seriesIndex];
            var textStyle = this.query(series, 'itemStyle.normal.breadcrumb.textStyle') || {};
            var textEmphasisStyle = 
                this.query(series, 'itemStyle.emphasis.breadcrumb.textStyle') || {};

            var commonStyle = {
                y: y + 10,
                textBaseline: 'top',
                textAlign: 'left',
                color: textStyle.color,
                textFont: this.getFont(textStyle)
            };
            var commonHighlightStyle = {
                brushType: 'fill',
                color: textEmphasisStyle.color || zrColor.lift(textStyle.color, -0.3),
                textFont: this.getFont(textEmphasisStyle)
            };

            for (var i = 0; i < stack.length; i++) {
                var textShape = new TextShape({
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    style: zrUtil.merge({
                        x: x,
                        text: stack[i] + (stack.length - 1 - i ? ' > ' : '')
                    }, commonStyle),
                    clickable: true,
                    highlightStyle: commonHighlightStyle
                });

                ecData.set(textShape, 'seriesIndex', seriesIndex);
                ecData.set(textShape, 'name', stack[i]);

                x += textShape.getRect(textShape.style).width;

                this.shapeList.push(textShape);
            }
        },

        __onclick : function (params) {
            var target = params.target;
            if (target) {
                var seriesIndex = ecData.get(target, 'seriesIndex');
                var name = ecData.get(target, 'name');
                var tree = this._treesMap[seriesIndex];
                var root = tree.getNodeById(name);

                if (root && root.children.length) {
                    this._buildTreemap(root, seriesIndex);
                }
            }
        }
    };

    zrUtil.inherits(Treemap, ChartBase);

    // 图表注册
    require('../chart').define('treemap', Treemap);

    return Treemap;
});