/**
 * 补充的CellType类型
 *
 * @author Mai
 * @date 2018/02/05
 * @version
 */

SpreadJsExtendCellType = {
    /**
     * 获取树结构CellType
     * 通过SpreadJsObj.loadSheetData(sheet, 'tree', tree)加载树结构数据
     * 要求tree类型为PathTree, 节点必须含有{id, pid, level, order, is_leaf}数据
     * @returns {TreeNodeCellType}
     */
    getTreeNodeCellType: function () {
        const indent = 20;
        const levelIndent = -5;
        const halfBoxLength = 5;
        const halfExpandLength = 3;

        /**
         * 画一条线段
         * @param canvas - 画布
         * @param x1 - 线段起点 x
         * @param y1 - 线段起点 y
         * @param x2 - 线段终点 x
         * @param y2 - 线段终点 y
         * @param color - 线段颜色
         */
        const drawLine = function (canvas, x1, y1, x2, y2, color) {
            canvas.save();
            // 设置偏移量
            canvas.translate(0.5, 0.5);
            canvas.beginPath();
            canvas.moveTo(x1, y1);
            canvas.lineTo(x2, y2);
            canvas.strokeStyle = color;
            canvas.stroke();
            canvas.restore();
        };
        /**
         * 画一个方框
         * @param {Object} canvas - 画布
         * @param {Object} rect - 方框区域
         * @param {String} lineColor - 画线颜色
         * @param {String} fillColor - 填充颜色
         */
        const drawBox = function (canvas, rect, lineColor, fillColor) {
            canvas.save();
            // 设置偏移量
            canvas.translate(0.5, 0.5);
            canvas.strokeStyle = lineColor;
            canvas.beginPath();
            canvas.moveTo(rect.left, rect.top);
            canvas.lineTo(rect.left, rect.bottom);
            canvas.lineTo(rect.right, rect.bottom);
            canvas.lineTo(rect.right, rect.top);
            canvas.lineTo(rect.left, rect.top);
            canvas.stroke();
            canvas.fillStyle = fillColor;
            canvas.fill();
            canvas.restore();
        };
        /**
         * 画树结构-展开收起按钮
         * @param {Object} canvas - 画布
         * @param {Number} x - 单元格左顶点坐标 x
         * @param {Number} y - 单元格左顶点坐标 y
         * @param {Number} w - 单元格宽度
         * @param {Number} h - 单元格高度
         * @param {Number} centerX - 按钮中央坐标
         * @param {Number} centerY - 按钮中央坐标
         * @param {Boolean} expanded - 当前节点展开收起状态
         */
        const drawExpandBox = function (canvas, x, y, w, h, centerX, centerY, expanded) {
            let rect = {
                top: centerY - halfBoxLength,
                bottom: centerY + halfBoxLength,
                left: centerX - halfBoxLength,
                right: centerX + halfBoxLength
            };
            let h1, h2, offset = 1;

            if (rect.left < x + w) {
                // 方框超出单元格宽度时，超出部分不画。
                rect.right = Math.min(rect.right, x + w);
                drawBox(canvas, rect, 'black', 'white');

                // 画中心十字
                // 画十字横线
                h1 = centerX - halfExpandLength;
                h2 = Math.min(centerX + halfExpandLength, x + w);
                if (h2 > h1) {
                    drawLine(canvas, h1, centerY, h2, centerY, 'black');
                }
                // 画十字竖线
                if (!expanded && (centerX < x + w)) {
                    drawLine(canvas, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black');
                }
            }
        };

        let TreeNodeCellType = function (){};
        TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
        const proto = TreeNodeCellType.prototype;

        /**
         * 绘制方法
         * @param {Object} canvas - 画布
         * @param value - cell.value
         * @param {Number} x - 单元格左顶点坐标 x
         * @param {Number} y - 单元格左顶点坐标 y
         * @param {Number} w - 单元格宽度
         * @param {Number} h - 单元格高度
         * @param {Object} style - cell.style
         * @param {Object} options
         */
        proto.paint = function (canvas, value, x, y, w, h, style, options) {
            // 清理 画布--单元格范围 旧数据
            if (style.backColor) {
                canvas.save();
                canvas.fillStyle = style.backColor;
                canvas.fillRect(x, y, w, h);
                canvas.restore();
            } else {
                canvas.clearRect(x, y, w, h);
            }

            const tree = options.sheet.zh_tree;
            // 使用TreeCellType前，需定义sheet.tree
            if (tree) {
                const node = options.row < tree.nodes.length ? tree.nodes[options.row] : null;
                if (node) {
                    const showTreeLine = true;
                    const centerX = Math.floor(x) + (node.level) * indent + (node.level) * levelIndent + indent / 2;
                    const centerY = Math.floor((y + (y + h)) / 2);
                    // Draw Sibling Line
                    if (showTreeLine) {
                        // Draw Horizontal Line
                        if (centerX < x + w) {
                            const x1 = centerX + indent / 2;
                            drawLine(canvas, centerX, centerY, Math.min(x1, x + w), centerY, 'gray');
                        }
                        // Draw Vertical Line
                        if (centerX < x + w) {
                            const y1 = tree.isLastSibling(node) ? centerY : y + h;
                            const parent = tree.getParent(node);
                            const y2 = y1 - centerY;
                            if (node.order === 1 && !parent) {
                                drawLine(canvas, centerX, centerY, centerX, y1, 'gray');
                            } else {
                                drawLine(canvas, centerX, y, centerX, y1, 'gray');
                            }
                        }
                    }
                    // Draw Expand Box
                    if (!node.is_leaf) {
                        drawExpandBox(canvas, x, y, w, h, centerX, centerY, node.expanded);
                    }
                    // Draw Parent Line
                    if (showTreeLine) {
                        let parent = tree.getParent(node), parentCenterX = centerX - indent - levelIndent;
                        while (parent) {
                            if (!tree.isLastSibling(parent)) {
                                if (parentCenterX < x + w) {
                                    drawLine(canvas, parentCenterX, y, parentCenterX, y + h, 'gray');
                                }
                            }
                            parent = tree.getParent(parent);
                            parentCenterX -= (indent + levelIndent);
                        }
                    };
                    // 重定位x
                    x = x + (node.level + 1) * indent +  (node.level) * levelIndent;
                }
            }
            // Drawing Text
            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
        };
        /**
         * 获取点击信息
         * @param {Number} x
         * @param {Number} y
         * @param {Object} cellStyle
         * @param {Object} cellRect
         * @param {Object} context
         * @returns {{x: *, y: *, row: *, col: *|boolean|*[]|number|{}|UE.dom.dtd.col, cellStyle: *, cellRect: *, sheet: *|StyleSheet, sheetArea: *}}
         */
        proto.getHitInfo = function (x, y, cellStyle, cellRect, context) {
            return {
                x: x,
                y: y,
                row: context.row,
                col: context.col,
                cellStyle: cellStyle,
                cellRect: cellRect,
                sheet: context.sheet,
                sheetArea: context.sheetArea
            };
        };
        /**
         * 鼠标点击 树结构按钮 响应展开收起（未加载子节点时，先加载子节点）
         * @param {Object} hitinfo - 见getHitInfo
         */
        proto.processMouseDown = function (hitinfo) {
            const offset = -1;

            const tree = hitinfo.sheet.zh_tree;
            if (!tree) { return; }

            const node = tree.nodes[hitinfo.row];
            if (!node) { return; }

            let centerX = hitinfo.cellRect.x + offset + (node.level) * indent + (node.level) * levelIndent + indent / 2;
            let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;

            // 点击展开节点时，如果已加载子项，则展开，反之这加载子项，展开
            if (Math.abs(hitinfo.x - centerX) < halfBoxLength && Math.abs(hitinfo.y - centerY) < halfBoxLength) {
                if (!node.expanded && !node.is_leaf && tree.getChildren(node).length === 0) {
                    tree.loadChildren(node, function () {
                        node.expanded = true;
                        const children = tree.getChildren(node);
                        hitinfo.sheet.addRows(hitinfo.row + 1, children.length);
                        SpreadJsObj.reLoadRowData(hitinfo.sheet, hitinfo.row + 1, children.length);
                    });
                } else {
                    tree.setExpanded(node, !node.expanded);
                    SpreadJsObj.massOperationSheet(hitinfo.sheet, function () {
                        const posterity = tree.getPosterity(node);
                        for (const child of posterity) {
                            hitinfo.sheet.setRowVisible(tree.nodes.indexOf(child), child.visible, hitinfo.sheetArea);
                        }
                    });
                    hitinfo.sheet.repaint();
                }
            }
        }

        return new TreeNodeCellType();
    },
    /**
     * 获取带悬浮提示CellType
     * @returns {TipCellType}
     */
    getTipCellType: function () {
        const TipCellType = function () {};
        // 继承 SpreadJs定义的 普通的TextCellType
        TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
        const proto = TipCellType.prototype;

        /**
         * 获取点击信息
         * @param {Number} x
         * @param {Number} y
         * @param {Object} cellStyle
         * @param {Object} cellRect
         * @param {Object} context
         * @returns {{x: *, y: *, row: *, col: *|boolean|*[]|number|{}|UE.dom.dtd.col, cellStyle: *, cellRect: *, sheet: *|StyleSheet, sheetArea: *}}
         */
        proto.getHitInfo = function (x, y, cellStyle, cellRect, context) {
            return {
                x: x,
                y: y,
                row: context.row,
                col: context.col,
                cellStyle: cellStyle,
                cellRect: cellRect,
                sheet: context.sheet,
                sheetArea: context.sheetArea
            };
        };
        /**
         * 鼠标进入单元格事件 - 显示悬浮提示
         * @param {Object} hitinfo - 见getHitInfo返回值
         */
        proto.processMouseEnter = function (hitinfo) {
            const text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
            const setting = hitinfo.sheet.setting;
            if (setting.pos && text && text !== '') {
                if (!this._toolTipElement) {
                    let div = $('#autoTip')[0];
                    if (!div) {
                        div = document.createElement("div");
                        $(div).css("position", "absolute")
                            .css("border", "1px #C0C0C0 solid")
                            .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
                            .css("font", "9pt Arial")
                            .css("background", "white")
                            .css("padding", 5)
                            .attr("id", 'autoTip');
                        $(div).hide();
                        document.body.insertBefore(div, null);
                    }
                    this._toolTipElement = div;
                    $(this._toolTipElement).text(text).css("top", setting.pos.y + hitinfo.y + 15).css("left", setting.pos.x + hitinfo.x + 15);
                    $(this._toolTipElement).show("fast");
                }
            }
        };
        /**
         * 鼠标移出单元格事件 - 隐藏悬浮提示
         * @param {Object} hitinfo - 见getHitInfo返回值
         */
        proto.processMouseLeave = function (hitinfo) {
            if (this._toolTipElement) {
                $(this._toolTipElement).hide();
                this._toolTipElement = null;
            }
        };

        return new TipCellType();
    }
};