'use strict';

/**
 *
 *
 * @author Zhong
 * @date 2018/6/28
 * @version
 */

const pmShare = (function () {
    const spreadDom = $('#shareSpread');
    let shareSeleted = null;
    let spreadObj = { workBook: null, sheet: null };
    let preSelection = null;
    //项目分享类型，由别人分享给自己的，和自己分享给别人的
    const shareType = { receive: 'receive', shareTo: 'shareTo' };
    //操作类型
    const oprType = { copy: 'copy', cancel: 'cancel' };
    let tree = null,
        actualIDShareInfo = {};//项目真实树ID与项目分享信息映射
    const treeCol = 0;
    const treeSetting = {
        tree: {
            id: 'ID',
            pid: 'ParentID',
            nid: 'NextSiblingID',
            rootId: -1,
            autoUpdate: false
        }
    };
    const headers = [
        { name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left' },
        { name: '来自', dataCode: 'from', width: 80, rateWidth: 0.15, vAlign: 'center', hAlign: 'left' },
        { name: '分享时间', dataCode: 'shareDate', width: 140, rateWidth: 0.15, vAlign: 'center', hAlign: 'left' },
        { name: '总造价', dataCode: 'totalCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00' },
        { name: '项目类别', dataCode: 'valuationType', width: 100, vAlign: 'center', hAlign: 'left' },
    ];
    const spreadOpts = {
        workBook: {
            tabStripVisible: false,
            allowContextMenu: false,
            allowCopyPasteExcelStyle: false,
            allowExtendPasteRange: false,
            allowUserDragDrop: false,
            allowUserDragFill: false,
            scrollbarMaxAlign: true
        },
        sheet: {
            isProtected: true,
            frozenlineColor: '#ababab',
            protectionOptions: { allowResizeRows: true, allowResizeColumns: true },
            clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
        }
    };
    const spreadEvents = {
        SelectionChanging: function (sender, info) {
            initSelection(info.newSelections[0], info.oldSelections[0]);
        }
    };
    //设置选中行底色
    //@param
    function setSelStyle(sel, backColor, sheet) {
        sel.row = sel.row === -1 ? 0 : sel.row;
        renderSheetFunc(sheet, function () {
            let style = projTreeObj.getSelStyle(backColor);
            for (let i = 0; i < sel.rowCount; i++) {
                let row = i + sel.row;
                sheet.setStyle(row, -1, style);
            }
        });
    }
    //初始化焦点
    //@param {Object}newSel {Object}oldSel @return {void}
    function initSelection(newSel, oldSel = null) {
        let node = tree.items[newSel.row];
        tree.selected = node;
        shareSeleted = node;
        //恢复底色
        if (oldSel) {
            setSelStyle(oldSel, projTreeObj.setting.style.defalutBackColor, spreadObj.sheet);
        }
        //设置选中行底色
        if (newSel) {
            setSelStyle(newSel, projTreeObj.setting.style.selectedColor, spreadObj.sheet);
        }
        preSelection = newSel;
    }
    //渲染时方法，停止渲染
    //@param {Object}sheet {Function}func @return {void}
    function renderSheetFunc(sheet, func) {
        sheet.suspendEvent();
        sheet.suspendPaint();
        if (func) {
            func();
        }
        sheet.resumeEvent();
        sheet.resumePaint();
    }
    //设置表选项
    //@param {Object}workBook {Object}opts @return {void}
    function setSpreadOptions(workBook, opts) {
        for (let opt in opts.workBook) {
            workBook.options[opt] = opts.workBook[opt];
        }
        for (let opt in opts.sheet) {
            workBook.getActiveSheet().options[opt] = opts.sheet[opt];
        }
    }
    //建表头
    //@param {Object}sheet {Array}headers @return {void}
    function buildHeader(sheet, headers) {
        let fuc = function () {
            sheet.setColumnCount(headers.length);
            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
            //let spreadWidth = getWorkBookWidth();
            for (let i = 0, len = headers.length; i < len; i++) {
                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
                if (headers[i].formatter) {
                    sheet.setFormatter(-1, i, headers[i].formatter);
                }
                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
                sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
                sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
            }
        };
        renderSheetFunc(sheet, fuc);
    }
    //表监听事件
    //@param {Object}workBook @return {void}
    function bindEvent(workBook, events) {
        if (Object.keys(events).length === 0) {
            return;
        }
        const Events = GC.Spread.Sheets.Events;
        for (let event in events) {
            workBook.bind(Events[event], events[event]);
        }
    }
    //建表
    //@return {void}
    function buildSheet() {
        spreadObj.workBook = new GC.Spread.Sheets.Workbook(spreadDom[0], { sheetCount: 1 });
        sheetCommonObj.spreadDefaultStyle(spreadObj.workBook);
        spreadObj.sheet = spreadObj.workBook.getActiveSheet();
        setSpreadOptions(spreadObj.workBook, spreadOpts);
        bindEvent(spreadObj.workBook, spreadEvents);
        buildHeader(spreadObj.sheet, headers);
        //全表不可编辑
        spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true);

    }
    //此项目的分享权限信息(可能会被父级项目覆盖，以新为准)
    //@param {String}userID(本用户id) {Object}project(项目) @return {Object} || {Null}
    function getShareInfo(userID, project) {
        if (!project.actualTreeInfo) {
            return null;
        }
        //获取跟本用户和选中项目相关的分享信息
        let shareList = [];
        let actualID = project.actualTreeInfo.ID,
            actualData = actualIDShareInfo[actualID];
        while (actualData) {
            for (let data of actualData.shareInfo) {
                if (data.userID === userID) {
                    shareList.push(data);
                    break;
                }
            }
            actualData = actualIDShareInfo[actualData.ParentID];
        }
        //获取最新分享
        shareList.sort(function (a, b) {
            return Date.parse(b.updateDate) - Date.parse(a.updateDate);
        });
        return shareList[0] || null;

    }
    //此项目是否可以拷贝
    //@param {String}userID {Object}project @return {Boolean}
    function isAllowCopy(userID, project) {
        let myShareInfo = getShareInfo(userID, project);
        if (!myShareInfo) {
            return false;
        }
        return !!myShareInfo.allowCopy;
    }
    //此项目是否可以协作
    //@param {String}userID {Object}project @return {Boolean}
    function isAllowCoop(userID, project) {
        let myShareInfo = getShareInfo(userID, project);
        if (!myShareInfo) {
            return false;
        }
        return !!myShareInfo.allowCooperate;
    }
    //获取树节点
    //@param {Object}tree @return {Object}
    function getTreeNodeCell(tree) {
        let indent = 20;
        let levelIndent = -5;
        let halfBoxLength = 5;
        let halfExpandLength = 3;
        let imgWidth = 18;
        let imgHeight = 14;
        let TreeNodeCellType = function () {
        };
        TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
        TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
            if (style.backColor) {
                ctx.save();
                ctx.fillStyle = style.backColor;
                ctx.fillRect(x, y, w, h);
                ctx.restore();
            } else {
                ctx.clearRect(x, y, w, h);
            }
            let drawLine = function (canvas, x1, y1, x2, y2, color) {
                ctx.save();
                ctx.translate(0.5, 0.5);
                ctx.beginPath();
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                ctx.strokeStyle = color;
                ctx.stroke();
                ctx.restore();
            };
            let drawExpandBox = function (ctx, x, y, w, h, centerX, centerY, expanded) {
                let rect = {}, h1, h2, offset = 1;
                rect.top = centerY - halfBoxLength;
                rect.bottom = centerY + halfBoxLength;
                rect.left = centerX - halfBoxLength;
                rect.right = centerX + halfBoxLength;

                if (rect.left < x + w) {
                    rect.right = Math.min(rect.right, x + w);

                    ctx.save();
                    ctx.translate(0.5, 0.5);
                    ctx.strokeStyle = 'black';
                    ctx.beginPath();
                    ctx.moveTo(rect.left, rect.top);
                    ctx.lineTo(rect.left, rect.bottom);
                    ctx.lineTo(rect.right, rect.bottom);
                    ctx.lineTo(rect.right, rect.top);
                    ctx.lineTo(rect.left, rect.top);
                    ctx.stroke();
                    ctx.fillStyle = 'white';
                    ctx.fill();
                    ctx.restore();

                    // Draw Horizontal Line
                    h1 = centerX - halfExpandLength;
                    h2 = Math.min(centerX + halfExpandLength, x + w);
                    if (h2 > h1) {
                        drawLine(ctx, h1, centerY, h2, centerY, 'black');
                    }
                    // Draw Vertical Line
                    if (!expanded && (centerX < x + w)) {
                        drawLine(ctx, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black');
                    }
                }

            }
            let node = tree.items[options.row];
            let showTreeLine = true;
            if (!node) { return; }

            let centerX = Math.floor(x) + node.depth() * indent + node.depth() * levelIndent + indent / 2;
            let x1 = centerX + indent / 2;
            let centerY = Math.floor((y + (y + h)) / 2);
            let y1;
            // Draw Sibling Line
            if (showTreeLine) {
                // Draw Horizontal Line
                if (centerX < x + w) {
                    drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, 'gray');
                    let img;
                    if (node.data.projType === projectType.folder) {
                        img = document.getElementById('folder_open_pic');
                        imgWidth = 15;
                    }
                    else if (node.data.projType === projectType.project) {
                        img = document.getElementById('proj_pic');
                        imgWidth = 18;
                    }
                    else if (node.data.projType === projectType.engineering) {
                        img = document.getElementById('eng_pic');
                        imgWidth = 14;
                    }
                    else if (node.data.projType === projectType.tender) {
                        img = document.getElementById('tender_pic');
                        imgWidth = 14;
                    }
                    ctx.drawImage(img, centerX + indent / 2 + 3, centerY - 7, imgWidth, imgHeight);
                }
                // Draw Vertical Line
                if (centerX < x + w) {
                    y1 = node.isLast() ? centerY : y + h;
                    if (node.isFirst() && !node.parent.parent) {
                        drawLine(ctx, centerX, centerY, centerX, y1, 'gray');
                    } else {
                        drawLine(ctx, centerX, y, centerX, y1, 'gray');
                    }
                }
            }
            // Draw Expand Box
            if (node.children.length > 0) {
                drawExpandBox(ctx, x, y, w, h, centerX, centerY, node.expanded);
            }
            // Draw Parent Line
            if (showTreeLine) {
                var parent = node.parent, parentCenterX = centerX - indent - levelIndent;
                while (parent.parent) {
                    if (!parent.isLast()) {
                        if (parentCenterX < x + w) {
                            drawLine(ctx, parentCenterX, y, parentCenterX, y + h, 'gray');
                        }
                    }
                    parent = parent.parent;
                    parentCenterX -= (indent + levelIndent);
                }
            };
            // Draw Text
            arguments[2] = x + (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3;
            arguments[4] = w - (node.depth() + 1) * indent - node.depth() * levelIndent - imgWidth - 3;
            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
        };
        TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
            let info = { x: x, y: y, row: context.row, col: context.col, cellStyle: cellStyle, cellRect: cellRect, sheetArea: context.sheetArea };
            let node = tree.items[info.row];
            if (node && node.data.projType === projectType.tender) {
                info.isReservedLocation = true;
            }
            return info;
        };
        TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
            let offset = -1;
            let node = tree.items[hitinfo.row];
            let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2;
            let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
            let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
            let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
                zoom = hitinfo.sheet.zoom();
            let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
            //(图标+名字)区域
            function withingClickArea() {
                return hitinfo.x > centerX + halfBoxLength && hitinfo.x < centerX + halfBoxLength + imgWidth + indent / 2 + 3 + textLength;
            }
            //点击单位工程
            if (node.data.projType === projectType.tender) {
                /*let newTab = window.open('about:blank');
                //打开项目的实际ID
                BeforeOpenProject(node.data.actualTreeInfo.ID, {'fullFolder': GetFullFolder(node.parent)}, function () {
                    let mainUrl = `/main?project=${node.data.actualTreeInfo.ID}`;
                    CommonAjax.get(mainUrl, [], function () {
                        newTab.location.href = mainUrl;
                    });
                });*/
                let thisClick = Date.now(),
                    open = false;
                if (this.preNode === node && this.preClick && thisClick - this.preClick <= 300) {
                    open = true;
                    projTreeObj.openTender(node.data.actualTreeInfo.ID, node.parent, 200);
                }
                this.preClick = open ? null : thisClick;
                this.preNode = open ? null : node;
            }
            if (!node || node.children.length === 0) {
                return;
            }
            if (hitinfo.x >= centerX - halfBoxLength - 2 && hitinfo.x <= centerX + halfBoxLength + 2 &&
                hitinfo.y >= centerY - halfBoxLength - 2 && hitinfo.y <= centerY + halfBoxLength + 2) {
                node.setExpanded(!node.expanded);
                TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () {
                    let iCount = node.posterityCount(), i, child;
                    for (i = 0; i < iCount; i++) {
                        child = tree.items[hitinfo.row + i + 1];
                        hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.visible, hitinfo.sheetArea);
                    }
                    hitinfo.sheet.invalidateLayout();
                });
                hitinfo.sheet.repaint();
            }
        };
        /*TreeNodeCellType.prototype.processMouseMove = function (hitInfo) {
            let sheet = hitInfo.sheet;
            let div = sheet.getParent().getHost();
            let canvasId = div.id + "vp_vp";
            let canvas = $(`#${canvasId}`)[0];
            //改变鼠标图案
            if (sheet && hitInfo.isReservedLocation) {
                canvas.style.cursor='pointer';
                return true;
            }else{
                canvas.style.cursor='default';
            }
            return false;
        };*/
        TreeNodeCellType.prototype.processMouseEnter = function (hitinfo) {
            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
            let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
            let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
            let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
                zoom = hitinfo.sheet.zoom();
            let node = tree.items[hitinfo.row];
            let nodeIndent = node ? (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3 : 0;
            let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
            let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
            if (textLength > cellWidth - nodeIndent) {
                TREE_SHEET_HELPER.showTipsDiv(text, { pos: {} }, hitinfo);
            }
        };
        TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
            TREE_SHEET_HELPER.tipDiv = 'hide';
            if (TREE_SHEET_HELPER._toolTipElement) {
                $(TREE_SHEET_HELPER._toolTipElement).hide();
                TREE_SHEET_HELPER._toolTipElement = null;
            };
            TREE_SHEET_HELPER.tipDivCheck();//延时检查：当tips正在show的时候，就调用了hide方法，会导致tips一直存在，所以设置一个超时处理
        }
        return new TreeNodeCellType();
    }
    //互动单元格
    function getInteractionCell() {
        let editImg = document.getElementById('edit_pic'),
            editImgWidth = 13,
            editImgHeight = 13,
            copyImg = document.getElementById('copy_pic'),
            copyImgWidth = 13,
            copyImgHeight = 13;
        let InteractionCell = function () {
        };
        InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
        InteractionCell.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
            if (style.backColor) {
                ctx.save();
                ctx.fillStyle = style.backColor;
                ctx.fillRect(x, y, w, h);
                ctx.restore();
            } else {
                ctx.clearRect(x, y, w, h);
            }
            let node = tree.items[options.row];
            // Draw Text
            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
            if (node && node.data.projType === projectType.tender) {
                let text = options.sheet.getText(options.row, options.col);
                let acStyle = options.sheet.getActualStyle(options.row, options.col),
                    zoom = options.sheet.zoom();
                let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: options.sheet, row: options.row, col: options.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
                const imgIndent = 5;
                let nowX = Math.floor(x) + textLength + imgIndent,
                    nowY = Math.floor((y + (y + h)) / 2) - 7;
                if (node.data.allowCooperate) {
                    ctx.drawImage(editImg, nowX, nowY, editImgWidth, editImgHeight);
                    nowX += editImgWidth;
                }
                if (node.data.allowCopy) {
                    ctx.drawImage(copyImg, nowX, nowY, copyImgWidth, copyImgHeight);
                }
            }

        };
        InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
            return {
                x: x,
                y: y,
                row: context.row,
                col: context.col,
                cellStyle: cellStyle,
                cellRect: cellRect,
                sheetArea: context.sheetArea,
                isReservedLocation: true
            };
        };
        InteractionCell.prototype.processMouseDown = function (hitinfo) {
            let dataCode = headers[hitinfo.col]['dataCode'];
            let node = tree.items[hitinfo.row];
            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
            let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
            let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
                zoom = hitinfo.sheet.zoom();
            let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
            if (hitinfo.x - hitinfo.cellRect.x > 0 && hitinfo.x - hitinfo.cellRect.x < textLength) {
                //由..分享，弹出分享者信息
                if (dataCode === 'from') {
                    if (node.data.shareType === shareType.receive) {
                        $('#userinfo').find('h4').text(node.data.userInfo.name);
                        $('#userinfo').find('h6').text(node.data.userInfo.company);
                        let mobileHtml = `<i class="fa fa-tablet"> ${node.data.userInfo.mobile ? node.data.userInfo.mobile : ''}</i>`;
                        $('#userinfo').find('li:first-child').html(mobileHtml);
                        let emailHtml = `<i class="fa fa-envelope-o"> ${node.data.userInfo.email ? node.data.userInfo.email : ''}</i>`;
                        $('#userinfo').find('li:last-child').html(emailHtml);
                        $('#userinfo').modal('show');
                    }
                }
            }
        };
        InteractionCell.prototype.processMouseMove = function (hitInfo) {
            let dataCode = headers[hitInfo.col]['dataCode'];
            let node = tree.items[hitInfo.row];
            let sheet = hitInfo.sheet;
            let div = sheet.getParent().getHost();
            let canvasId = div.id + "vp_vp";
            let canvas = $(`#${canvasId}`)[0];
            //改变鼠标图案
            let text = hitInfo.sheet.getText(hitInfo.row, hitInfo.col);
            let value = hitInfo.sheet.getValue(hitInfo.row, hitInfo.col);
            let acStyle = hitInfo.sheet.getActualStyle(hitInfo.row, hitInfo.col),
                zoom = hitInfo.sheet.zoom();
            let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitInfo.sheet, row: hitInfo.row, col: hitInfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
            if (sheet && hitInfo.x - hitInfo.cellRect.x > 0 && hitInfo.x - hitInfo.cellRect.x < textLength) {
                canvas.style.cursor = 'pointer';
                return true;
            } else {
                canvas.style.cursor = 'default';
            }
            return false;
        };
        return new InteractionCell();
    }

    function isUnread(unreadList, node) {
        if (!unreadList) {
            return false;
        }
        const actualID = node && node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID || null;
        if (!actualID) {
            return false;
        }
        return !!unreadList.find(ID => ID === actualID);
    }
    const foreColor = '#007bff';
    const dangerColor = '#dc3545';
    // 标记已读
    // 打开任意的单位工程，都会将其父分享条目标记和自身为已读 
    // eg:被分享了一个建设项目，和其下一个单位工程，打开该一个单位工程，建设项目标记为已读、该单位工程也标记为已读
    function handleMarkRead(unreadList, markReadProjectIDs) {
        const col = headers.findIndex(item => item.dataCode === 'shareDate');
        const sheet = spreadObj.workBook.getActiveSheet();
        const style = new GC.Spread.Sheets.Style();
        projTreeObj.renderSheetFuc(sheet, function () {
            markReadProjectIDs.forEach(projectID => {
                SHARE_TO.removeUnread(projectID, unreadList);
                tree.items.forEach(node => {
                    if (node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === projectID) {
                        const row = node.serialNo();
                        sheet.setStyle(row, col, style);
                    }
                });
            });
        });
    }
    //显示树结构数据
    //@param {Array}nodes {Array}headers @return {void}
    function showTreeData(nodes, headers) {
        let sheet = spreadObj.workBook.getActiveSheet();
        let fuc = function () {
            sheet.setRowCount(nodes.length);
            for (let i = 0; i < nodes.length; i++) {
                let treeNodeCell = getTreeNodeCell(tree);
                sheet.getCell(i, treeCol).cellType(treeNodeCell);
                for (let j = 0; j < headers.length; j++) {
                    sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
                    sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
                    let dataCode = headers[j].dataCode;
                    if (dataCode === 'from') {
                        let style = new GC.Spread.Sheets.Style();
                        style.foreColor = foreColor;
                        sheet.setStyle(i, j, style);
                        sheet.getCell(i, j).cellType(getInteractionCell());
                    } else if (dataCode === 'shareDate') {
                        let style = new GC.Spread.Sheets.Style();
                        if (isUnread(unreadShareList, nodes[i])) {
                            style.foreColor = dangerColor;
                        }
                        sheet.setStyle(i, j, style);
                    }
                    sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
                }
            }
        };
        renderSheetFunc(sheet, fuc);
    }
    // 获取实际树ID为某值的所有节点
    function getNodesByActualID(ID, items) {
        return items.filter(node => node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === ID);
    }
    //同一棵树，可能存在相同数据显示多条的问题(传入的datas中不存在相同数据)
    //将真实树结构数据存在actualTreeInfo中，外部树结构数据用uuid重置。
    //@param {Array}datas
    function setTreeInfo(datas) {
        let IDMapping = {};
        for (let data of datas) {
            //项目真实ID与项目分享信息映射，方便确定项目的权限
            if (!actualIDShareInfo[data.ID]) {
                actualIDShareInfo[data.ID] = { ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID, shareInfo: data.shareInfo };
            }
            IDMapping[data.ID] = uuid.v1();
        }
        for (let data of datas) {
            data.actualTreeInfo = { ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID };
            data.ID = IDMapping[data.ID];
            data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;
            data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;
        }
    }
    //整理同层数据的NextSiblingID，ParentID
    //@param {Array}datas {Number || String}pid @return {void}
    function sortSameDepthData(datas, pid) {
        for (let i = 0; i < datas.length; i++) {
            let data = datas[i],
                nextData = datas[i + 1];
            data.NextSiblingID = nextData ? nextData.ID : -1;
            data.ParentID = pid;
        }
    }
    //给项目设置分享信息：由xx分享、分享时间、分享给我，含有userInfo信息的文件为他人直接分享的文件，他人分享父级文件，子文件不含有userInfo信息
    //@param {Array}datas @return {void}
    function setShareInfo(datas) {
        for (let data of datas) {
            if (data.userInfo) {
                //shareInfo中我的条目
                let selfInfo = _.find(data.shareInfo, { userID: userID });
                data.shareDate = selfInfo ? selfInfo.shareDate : ''
                data.from = data.userInfo.name;
                data.to = '分享给 我';
                data.cancel = '清除';
            }
        }
    }
    //给项目设置汇总信息
    //@param {Array}projs {Object}summaryInfo
    function setSummaryInfo(grouped, summaryInfo) {
        if (!summaryInfo) {
            return;
        }
        let allDatas = [];
        for (let data of grouped) {
            allDatas.push(data);
            if (data.children && data.children.length > 0) {
                allDatas = allDatas.concat(data.children);
            }
        }
        for (let proj of allDatas) {
            let summaryProj = summaryInfo[proj.ID];
            if (summaryProj) {
                proj.totalCost = summaryProj.totalCost;
            }
        }
    }
    //从同层树数据获取第一个节点ID
    //@param {Array}treeDatas树的数据 @return {String}第一个节点的虚拟树ID
    function getFirstID(treeDatas) {
        let treeMapping = {};
        //建立ID索引
        for (let data of treeDatas) {
            //新建一个简单对象,防止污染treeDatas的数据
            treeMapping[data.ID] = { ID: data.ID, prev: null, next: null };
        }
        //绑定prev next
        for (let data of treeDatas) {
            let me = treeMapping[data.ID],
                next = treeMapping[data.NextSiblingID];
            if (next) {
                me.next = next;
                next.prev = me;
            }
        }
        //返回没有prev属性的数据
        let result = _.find(treeDatas, function (data) {
            return !treeMapping[data.ID].prev
        });
        return result ? result.ID : -1;
    }
    //获取可成树的数据
    //@param {Array}datas @return {Array}
    function getTreeDatas(groupedDatas, ungroupedDatas) {
        //设置新的树结构数据
        for (let data of groupedDatas) {
            setTreeInfo([data].concat(data.children));
        }
        //未分类分段
        let tenders = _.filter(ungroupedDatas, { projType: projectType.tender });
        setTreeInfo(tenders);
        let rst = [];
        //整理树结构
        sortSameDepthData(groupedDatas, -1);
        //第一个根节点数据
        let firstID = getFirstID(groupedDatas);
        //新建未分类建设项目及单项工程
        let ungroupedProj = { ID: uuid.v1(), ParentID: -1, NextSiblingID: firstID, name: '未分类建设项目', projType: projectType.project };
        /*if (groupedDatas.length > 0) {
            groupedDatas[groupedDatas.length - 1].NextSiblingID = ungroupedProj.ID;
        }*/
        //将未分类的数据归类
        sortSameDepthData(tenders, ungroupedProj.ID);
        let allDatas = groupedDatas.concat(ungroupedDatas);
        //设置分享信息及操作信息
        setShareInfo(allDatas);
        for (let data of allDatas) {
            rst.push(data);
            if (data.children) {
                rst = rst.concat(data.children);
            }
        }
        rst.push(ungroupedProj);
        return rst;
    }
    //按照时间排序
    //@param {Array}datas @return {void}
    function sortByDate(datas) {
        datas.sort(function (a, b) {
            let shareInfoA = _.find(a.shareInfo, { userID }),
                shareInfoB = _.find(b.shareInfo, { userID });
            let aV = shareInfoA ? Date.parse(shareInfoA.shareDate) : 0,
                bV = shareInfoB ? Date.parse(shareInfoB.shareDate) : 0;
            //时间越晚越靠前
            if (aV > bV) {
                return -1;
            } else if (aV < bV) {
                return 1;
            }
            return 0;
        });
    }
    //设置节点数据权限
    //@param {Array}datas项目数据
    function setPermissionsInfo(datas) {
        //data.allowCopy与shareInfo里allowCopy的区别：
        //data.allowCopy为该单位实际的权限（跟着最新的分享信息走，可能随着父项）
        for (let data of datas) {
            if (data.projType === projectType.tender) {
                data.allowCopy = isAllowCopy(userID, data);
                data.allowCooperate = isAllowCoop(userID, data);
            }
        }

    }
    //建立树
    //@return void
    function initShareTree() {
        $.bootstrapLoading.start();
        //获取分享数据
        CommonAjax.post('/pm/api/receiveProjects', { user_id: userID }, function (rstData) {
            // 排序 --分享的文件按照时间先后顺序排序，分享文件下的子文件，按照原本树结构显示，不需要排序
            sortByDate(rstData.grouped);
            sortByDate(rstData.ungrouped);
            //设置汇总信息
            if (rstData.summaryInfo) {
                setSummaryInfo(rstData.grouped, rstData.summaryInfo.grouped);
                setSummaryInfo(rstData.ungrouped, rstData.summaryInfo.ungrouped);
            }
            let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);
            setPermissionsInfo(treeDatas);
            tree = pmTree.createNew(treeSetting, treeDatas);
            tree.selected = tree.items[0];
            showTreeData(tree.items, headers);
            //初始选择
            let initSel = spreadObj.sheet.getSelections()[0] ? spreadObj.sheet.getSelections()[0] : { row: 0, rowCount: 1 };
            initSelection(initSel);
            autoFlashHeight();
            spreadObj.sheet.frozenColumnCount(4);
            spreadObj.workBook.refresh();
            $.bootstrapLoading.end();
        });
    }
    //初始化右键菜单
    function initContextMenu() {
        $.contextMenu({
            selector: '#shareSpread',
            build: function ($trigger, e) {
                let target = SheetDataHelper.safeRightClickSelection($trigger, e, spreadObj.workBook);
                initSelection({ row: target.row, rowCount: 1 }, preSelection ? preSelection : null, spreadObj.sheet);
                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
            },
            items: {
                "copy": {
                    name: "拷贝工程",
                    icon: 'fa-copy',
                    disabled: function () {
                        let selected = tree.selected;
                        return !(selected && selected.data.allowCopy);
                    },
                    callback: function (key, opt) {
                        $('#copyShare').modal('show');
                    }
                },
                "cancel": {
                    name: "清除",
                    icon: 'fa-remove',
                    disabled: function () {
                        let selected = tree.selected;
                        return !(selected && selected.data.cancel && selected.data.cancel === '清除');
                    },
                    callback: function (key, opt) {
                        let $p = $('<p>').text(`点“确定”按钮，确认清除分享文件 “${tree.selected.data.name}”。`);
                        $('#cancelShare').find('.modal-body').empty();
                        $('#cancelShare').find('.modal-body').append($p);
                        $('#cancelShare').modal('show');
                    }
                }
            }
        });
    }
    //初始化视图
    //@return void
    function initView() {
        if (tree) {
            tree = null;
        }
        if (spreadObj.workBook) {
            spreadObj.workBook.destroy();
            spreadObj.workBook = null;
        }
        initContextMenu();
        buildSheet();
        initShareTree();
    }
    //根据建设项目获取单项工程
    //@param {Number}projID @return {void}
    function setEng(projID) {
        let engQuery = { $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], projType: projectType.engineering, userID: userID, ParentID: projID };
        CommonAjax.post('/pm/api/getProjectsByQuery', { user_id: userID, query: engQuery, options: '-_id -property' }, function (rstData) {
            $('#copyShare_selectEng').empty();
            for (let eng of rstData) {
                let opt = $('<option>').val(eng.ID).text(eng.name);
                $('#copyShare_selectEng').append(opt);
            }
        });
    }
    //从其他建设项目中复制中，建设项目的文件层次结构名称和顺序
    //@param {Array}treeData @return {Array}
    function getFileHierarchyInfo(treeData) {
        let tree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1 });
        tree.loadDatas(treeData);
        let items = tree.items;
        let rst = [];
        function getFileHierarchyName(node) {
            let nodeName = node.data.name;
            let name = [];
            while (node.parent) {
                name.push(node.parent.data.name ? node.parent.data.name : '');
                node = node.parent;
            }
            name = name.reverse();
            name.push(nodeName);
            return name.join('\\');
        }
        for (let node of items) {
            if (node.children.length === 0) {//project
                rst.push({ ID: node.data.ID, fileHierarchyName: getFileHierarchyName(node) })
            }
        }
        return rst;
    }
    //设置拷贝工程下拉选择
    //@return {void}
    function setCopyModal() {
        //获取建设项目
        let projQuery = { $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], projType: { $in: [projectType.project, projectType.folder] }, userID: userID };
        CommonAjax.post('/pm/api/getProjectsByQuery', { user_id: userID, query: projQuery, options: '-_id -property' }, function (rstData) {
            let fileHierarchyData = getFileHierarchyInfo(rstData);
            $('#copyShare_selectProj').empty();
            for (let proj of fileHierarchyData) {
                let opt = $('<option>').val(proj.ID).text(proj.fileHierarchyName);
                $('#copyShare_selectProj').append(opt);
            }
            //初始选择
            /*if(fileHierarchyData.length > 0){
                setEng(fileHierarchyData[0].ID);
            }*/
        });
    }
    //拷贝分享的工程
    //@param {Object}selected {Number}parentID @return {void}
    async function copyShareProject(selected, projID) {
        try {
            if (!projID || !selected) {
                return;
            }
            let copyMap = { copy: null, update: null };
            let newName = getCopyName(selected);
            //获取建设项目的分段
            let tenderQuery = { $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], userID: userID, ParentID: projID };
            const rstData = await ajaxPost('/pm/api/getProjectsByQuery', { user_id: userID, query: tenderQuery, options: '-_id -property' }, 10000);
            let updateTender = null;
            for (let tender of rstData) {
                if (tender.name === newName) {
                    $('#copyShare_name').text('已存在此单位工程。');
                    $('#copyShare_name').addClass('text-danger');
                    return;
                }
                if (tender.NextSiblingID == -1) {
                    updateTender = tender;
                }
            }
            //更新前节点
            if (updateTender) {
                copyMap.update = { query: { ID: updateTender.ID } };
            }
            //拷贝
            let copyData = {
                userID: userID,
                ID: selected.data.actualTreeInfo.ID,
                NextSiblingID: -1,
                ParentID: projID,
                name: newName,
                shareInfo: [],
                compilation: selected.data.compilation,
                createDateTime: selected.data.createDateTime,
                fileVer: selected.data.fileVer ? selected.data.fileVer : '',
                projType: selected.data.projType,
                property: {},
                recentDateTime: selected.data.recentDateTime,
                fullFolder: selected.data.fullFolder
            };
            copyData.property.rootProjectID = projID;
            copyMap.copy = { document: copyData };
            $('#copyShare').modal('hide');
            $.bootstrapLoading.progressStart('拷贝项目', true);
            $("#progress_modal_body").text('正在拷贝项目，请稍候……');
            await ajaxPost('/pm/api/copyProjects', { projectMap: copyMap, user_id: userID, tenderCount: 1 });
            importProcessChecking(null, null, projTreeObj.emitTreeChange);
        } catch (err) {
            alert(err);
        }
    }
    //获取拷贝后的名称
    //@param {Object}node @return {String}
    function getCopyName(node) {
        //当前单位工程可能没有分享的用户信息，可能他人分享的是父级文件，userInfo在父级文件中
        let orgName = node.data.name,
            userInfo = node.data.userInfo;
        while (node && !userInfo) {
            node = node.parent;
            userInfo = node.data.userInfo;
        }
        return `${orgName} (${userInfo.name}分享拷贝)`;
    }
    //清除了该节点后，可能还有该节点的数据在树上(树允许有重复数据)，需要更新分享信息
    function updateAfterCancel(userID, projectID) {
        for (let item of tree.items) {
            if (item.data.actualTreeInfo && item.data.actualTreeInfo.ID === projectID) {
                _.remove(item.data.shareInfo, function (data) {
                    return data.userID === userID;
                });
            }
        }
    }
    // 处理节点操作属性变更(是否可拷贝、是否可编辑)
    function handlePropChange(projectID, prop) {
        const actualShareData = actualIDShareInfo[projectID];
        if (actualShareData) {
            const shareItem = actualShareData.shareInfo.find(s => s.userID === userID);
            if (shareItem) {
                Object.assign(shareItem, prop);
            }
        }
        const nodes = getNodesByActualID(projectID, tree.items);
        nodes.forEach(node => {
            const shareItem = node.data.shareInfo.find(s => s.userID === userID);
            if (shareItem) {
                Object.assign(shareItem, prop);
            }
        });
        const treeData = tree.items.map(item => item.data);
        setPermissionsInfo(treeData);
        showTreeData(tree.items, headers);
    }
    function handleCancelShare(cancelProjID) {
        const node = tree.items.find(item => item.data.actualTreeInfo && item.data.actualTreeInfo.ID === cancelProjID);
        if (node) {
            tree.removeNode(node);
        }
        //更新与清除节点数据相同，且未被清除缓存分享信息
        updateAfterCancel(userID, cancelProjID);
        //重新设置actualIDShareInfo，以正确更新权限(清除了分享信息后，可能会导致权限变化 eg:清除了新的分享，则存留的分享项目采用旧的)
        actualIDShareInfo = {};
        let treeDatas = [];
        for (let item of tree.items) {
            treeDatas.push(item.data);
            let actualTreeInfo = item.data.actualTreeInfo;
            if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {
                actualIDShareInfo[actualTreeInfo.ID] = {
                    ID: actualTreeInfo.ID,
                    ParentID: actualTreeInfo.ParentID,
                    NextSiblingID: actualTreeInfo.NextSiblingID,
                    shareInfo: item.data.shareInfo
                };
            }
        }
        //重新设置权限
        setPermissionsInfo(treeDatas);
        showTreeData(tree.items, headers);
    }
    //事件监听器
    //@return void
    function eventListener() {
        //tab
        $('#tab_pm_share').on('shown.bs.tab', function () {
            //侧滑隐藏
            $('.slide-sidebar').removeClass('open');
            $('.slide-sidebar').css('width', '0');
            projTreeObj.tree = null;
            if (projTreeObj.workBook) {
                projTreeObj.workBook.destroy();
                projTreeObj.workBook = null;
            }
            gcTreeObj.tree = null;
            if (gcTreeObj.workBook) {
                gcTreeObj.workBook.destroy();
                gcTreeObj.workBook = null;
            }
            initView();
        });
        //关闭拷贝工程
        $('#copyShare').on('hidden.bs.modal', function () {
            $('#copyShareProj-info').hide();
            $('#copyShareEng-info').hide();
        });
        //打开拷贝工程
        $('#copyShare').on('shown.bs.modal', function () {
            setCopyModal();
            //更改显示名称
            let newName = getCopyName(shareSeleted);
            $('#copyShare_name').html(`拷贝后，工程将重命名为 "<b>${newName}</b>"`);
            $('#copyShare_name').removeClass('text-danger');
        });
        //拷贝工程改变选择建设项目
        $('#copyShare_selectProj').change(function () {
            //更改显示名称
            let newName = getCopyName(shareSeleted);
            $('#copyShare_name').html(`拷贝后，工程将重命名为 "<b>${newName}</b>"`);
            $('#copyShare_name').removeClass('text-danger');
            $('#copyShareProj-info').hide();
            $('#copyShareEng-info').hide();
            let curSelID = $(this).select().val();
            setEng(parseInt(curSelID));
        });
        //拷贝工程改变选择单项工程
        $('#copyShare_selectEng').change(function () {
            //更改显示名称
            let newName = getCopyName(shareSeleted);
            $('#copyShare_name').html(`拷贝后，工程将重命名为 "<b>${newName}</b>"`);
            $('#copyShare_name').removeClass('text-danger');
        });
        //确认拷贝
        $('#copyShare_confirm').click(function () {
            let selProj = $('#copyShare_selectProj').select().val();
            if (!selProj) {
                $('#copyShareProj-info').show();
                return;
            }
            copyShareProject(tree.selected, parseInt(selProj));
        });
        //清除分享
        $('#cancelShareConfirm').click(function () {
            $.bootstrapLoading.start();
            const cancelProjID = tree.selected.data.actualTreeInfo.ID;
            const permissionType = commonConstants.SharePermissionChangeType.CANCEL;
            CommonAjax.post('/pm/api/share', { user_id: userID, type: oprType.cancel, permissionType, projectID: cancelProjID, shareData: [{ userID: userID }] }, function (rstData) {
                handleCancelShare(cancelProjID);

                // 推送已打开的项目，通知已取消分享
                SHARE_TO.emitPermissionChange(permissionType, userID, cancelProjID, rstData.emitTenders);
                // 清除已读
                SHARE_TO.removeUnread(cancelProjID, unreadShareList);

                $.bootstrapLoading.end();
            }, function () {
                $.bootstrapLoading.end();
            });
        });
    }

    return {
        spreadObj,
        headers,
        initView,
        eventListener,
        initShareTree,
        handlePropChange,
        handleCancelShare,
        handleMarkRead
    }
})();

$(document).ready(function () {
    pmShare.eventListener();
});