<template>
    <div class="baseTopo" id="baseTopo" ref="baseTopo">
        <topoTooltip
            v-show="showTooltip"
            class="topoTooltip-box"
            ref="topoTooltip"
            @closeTooltip="showTooltip = false"
            :havItem="havItem"
        ></topoTooltip>
        <canvas style="border: none; outline: medium" id="persagy_plan" :width="canvasWidth" :height="canvasHeight" tabindex="0"></canvas>
    </div>
</template>
<script>
import { SFloorParser, getJsonz } from "@persagy-web/big";
import { SImageItem, SImageShowType } from "@persagy-web/graph";
import { SPlanView, SPlanParser, SPlanScene, SPlanDecorator, SPlanEquipment } from "@/lib";
import { SBaseEquipment } from "@/components/editClass/big-edit";
import topoTooltip from "./topoTooltip.vue";
import { mapState, mapMutations } from "vuex";
import base64ToFile from "@/utils/base64ToFile";
import { v1 as uuidv1 } from "uuid";
import bus from "@/bus/bus";
import { saveGroup } from "@/api/editer";
import { publishGraph } from "@/api/home";
import { planerSave, planerRead, pubPlanerRead } from "@/api/labsl";
import { equipQuery } from "@/api/equipcomponent";
import { imgBaseUrl, imgServeUpload } from "@/api/imageservice";
export default {
    components: { topoTooltip },
    props: {
        // 1.底图颜色
        baseMapStyle: {
            type: Object,
            default: () => {
                return {
                    default: {
                        strokeColor: "#F0F3F7",
                        fillColor: "#F0F3F7",
                        lineWidth: 1,
                        effect: {},
                    },
                };
            },
            required: false,
        }
    },
    data() {
        return {
            scene: null, //场景
            view: null, //视图
            canvasWidth: 700, //画布宽
            canvasHeight: 700, //画布高
            havItem: false, //右击是否选中item
            showTooltip: false, //是否显示tooltip
            planContent: {}, // 读图后存储图所有数据
            autoSave: null, // 自动保存定时器
        };
    },
    computed: {
        ...mapState([
            "editCmd",
            "legendObj",
            "graphId",
            "id",
            "state",
            "projectId",
            "floorMap",
            "equipItemMap",
            "buildingId",
            "floorId",
            "objExtInfo",
            "styleMap",
        ]),
    },
    mounted() {
        // 获取 canvas 的宽高
        this.canvasWidth = this.$refs.baseTopo.offsetWidth;
        this.canvasHeight = this.$refs.baseTopo.offsetHeight - 10;
        // 初始化场景类
        this.view = new SPlanView("persagy_plan");
        if (this.scene) this.view.scene = this.scene;
        this.init();

        // 初始化bus绑定事件
        this.initBusEvent();

        // 右键事件
        this.scene.getItem = this.onContextMenu;
        this.scene.emitChoice = this.emitChoice;

        //左键事件
        this.scene.vueOnMouseDown = this.vueOnMouseDown;

        // 屏蔽浏览器右键功能（防止与编辑器右键交互重合）
        document.getElementById("baseTopo").oncontextmenu = function (e) {
            return false;
        };

        // 2分钟自动保存
        this.autoSave = setInterval(() => {
            this.autoSaveTopo();
        }, 120000);
    },
    methods: {
        ...mapMutations([
            "SETCHOICELEHEND",
            "SETLEGENDOBJ",
            "SETPROJECT",
            "SETCATEGROY",
            "SETISPUB",
            "ADDEQUIPITEM",
            "EDITEQUIPITEM",
            "SETVERSION",
            "ADDEQUIP",
            "DELETEQUIP",
            "INITSTYLE",
            "INITOBJEXTINFO",
        ]),

        // 清空画布
        clearImg() {
            this.scene = new SPlanScene();
            this.scene.imgServeUrl = imgBaseUrl;
            this.scene.emitChoice = this.emitChoice;
            this.scene.clearCmdStatus = this.clearCmdStatus;
            this.scene.vueOnMouseDown = this.vueOnMouseDown;
            if (this.view) {
                this.view.update();
            }
        },
        // 初始化
        init() {
            this.clearImg();
            this.view ? (this.view.scene = this.scene) : null;
            // 判断是否有楼层底图，有则获取数据并解析
            if (this.floorMap) this.getMapBlob();
            // 读取平面图数据
            this.readPlanMsg();
        },
        // 请求获取地图的压缩包
        getMapBlob() {
            if (this.floorMap.includes("png") || this.floorMap.includes("jpg")) {
                const url = `/image-service/common/image_get?systemId=dataPlatform&key=${this.floorMap}`;
                this.getImage(url);
            } else {
                const url = `/image-service/common/file_get?systemId=revit&key=${this.floorMap}`;
                getJsonz(url).then((data) => {
                    // 解析数据并放入压缩包中
                    this.parserData(data);
                });
            }
        },
        // 获取图片
        getImage(url) {
            const imgItem = new SImageItem(null, url);
            imgItem.showType = SImageShowType.AutoFit;
            imgItem.connect("imgLoadOver", this, () => {
                // 画板是否可拖动;
                this.scene.addItem(imgItem);
                this.view.DragMove = true;
                this.view.fitSceneToView();
            });
        },
        // 解析数据并注入 scene 类中
        parserData(data) {
            const parser = new SFloorParser();
            parser.parseData(data);
            parser.spaceList.forEach((t) => {
                //是否显示空间
                // t.visible = this.isSpaceSelectable;
                //设置样式
                Object.assign(t, this.baseMapStyle.default);
                //是否展示名称
                // t.showBaseName = true;
                // 是否可选
                t.selectable = false;
                // t.connect("onMouseDown", this, this.clickSpaceItem);

                // 添加图例
                this.scene.addItem(t);
            });
            parser.wallList.forEach((t) => {
                // 是否显示
                // t.visible = this.isShowWall;
                // 是否可选
                t.selectable = false;
                this.scene.addItem(t);
            });
            parser.virtualWallList.forEach((t) => {
                // 是否显示
                // t.visible = this.isShowVirtualWall;
                // 是否可选
                t.selectable = false;
                this.scene.addItem(t);
            });
            parser.doorList.forEach((t) => {
                // 是否显示
                // t.visible = this.isShowDoor;
                // 是否可选
                t.selectable = false;
                this.scene.addItem(t);
            });
            parser.columnList.forEach((t) => {
                // 是否显示
                // t.visible = this.isShowColumn;
                // 是否可选
                t.selectable = false;
                this.scene.addItem(t);
            });
            parser.casementList.forEach((t) => {
                // 是否显示
                // t.visible = this.isShowWindow;
                // 是否可选
                t.selectable = false;
                this.scene.addItem(t);
            });
            // 画板是否可拖动
            this.view.DragMove = true;
            this.view.fitSceneToView();
        },

        // 恢复命令状态
        clearCmdStatus() {
            this.SETCHOICELEHEND("");
            this.SETLEGENDOBJ(null);
        },
        // 右键获取item
        onContextMenu(item, [event]) {
            this.showTooltip = true;
            if (item) {
                this.havItem = true;
            } else {
                this.havItem = false;
            }
            const doms = document.getElementsByClassName("topoTooltip-box")[0];
            doms.style.left = event.offsetX + "px";
            doms.style.top = event.offsetY + "px";
        },
        // 左键事键
        vueOnMouseDown(e) {
            //  关闭tooltip
            this.showTooltip = false;
        },
        // 选中后的回调函数
        emitChoice(itemList) {
            bus.$emit("emitChoice", itemList);
        },
        //初始化bus绑定事件
        initBusEvent() {
            // 改变样式
            bus.$off("updateStyle");
            bus.$on("updateStyle", (type, val) => {
                this.scene.updateStyle(type, val);
            });
            // 撤销
            bus.$off("topoUndo");
            bus.$on("topoUndo", (val) => {
                this.scene.undo();
            });
            // 重做
            bus.$off("topoRedo");
            bus.$on("topoRedo", (val) => {
                this.scene.redo();
            });
            // 删除
            bus.$off("deleteItem");
            bus.$on("deleteItem", (val) => {
                this.scene.deleteItem([val]);
                this.EDITEQUIPITEM();
            });
            // 复制
            bus.$off("copy");
            bus.$on("copy", (val) => {
                this.scene.copy();
            });
            // 粘贴
            bus.$off("paste");
            bus.$on("paste", (val) => {
                this.scene.paste();
            });
            // 保存
            bus.$off("saveTopo");
            bus.$on("saveTopo", (val) => {
                this.saveTopoDraft();
            });
            // 设置实例置顶置底
            bus.$off("setOrder");
            bus.$on("setOrder", (val) => {
                this.scene.setOrder(val);
            });
            // 设置实例status状态
            bus.$off("setItemStatus");
            bus.$on("setItemStatus", (val) => {
                this.scene.setItemStatus();
            });
            // 下载图片
            bus.$off("saveTopoImg");
            bus.$on("saveTopoImg", () => {
                // 隐藏选择器
                this.scene.selectContainer.clear();
                this.view.saveImageSize(`${this.planContent.name}.png`, "png", this.canvasWidth, this.canvasHeight);
            });
            // 发布图片
            bus.$off("issueTopo");
            bus.$on("issueTopo", () => {
                this.saveTopoDraft().then(() => {
                    this.issueDraft();
                });
            });
            // 手动添加设备实例
            bus.$off("addEquipment");
            bus.$on("addEquipment", (val) => {
                this.addEquipmentList(val);
            });
            // 更改设备信息点
            bus.$off("changeEquipMsgPoint");
            bus.$on("changeEquipMsgPoint", (val) => {
                this.scene.changeEquipMsgPoint(val);
            });
            // 选中item
            bus.$off("chioceItem");
            bus.$on("chioceItem", (item) => {
                this.scene.toggleItem(item);
            });
        },
        // 读取拓扑图
        readPlanMsg() {
            const obj = {
                graphId: this.graphId,
                id: this.id,
            };
            if (this.state === "Publish") {
                // 已发布
                pubPlanerRead(obj).then((res) => {
                    this.getDataSuc(res);
                });
            } else {
                planerRead(obj).then((res) => {
                    this.getDataSuc(res);
                });
            }
        },
        // 读图成功回调
        getDataSuc(res) {
            // let anchorList = []; //保存锚点对象
            if (res.result == "failure") return;
            this.SETCATEGROY(res.content);
            this.planContent = res.content;
            const parse = new SPlanParser();
            parse.parseData(res.content.elements);
            parse.markers.forEach((item) => {
                item.selectable = true;
                item.moveable = true;
                item.connect("finishCreated", this.scene, this.scene.finishCreated);
                item.connect("onContextMenu", this, this.scene.getItem);
                // 判断如果是图，需要拼接路径
                if (item.data.properties.type == "BaseImage") {
                    if (item.data.style?.default?.url) {
                        item.url = imgBaseUrl + item.data.style.default.url;
                    }
                }
                this.scene.addItem(item);
            });

            // 保存设备位置信息
            if (res.content.elements.objExtInfo?.length) {
                const objExtInfo = {};
                if (res.content.elements.objExtInfo?.length) {
                    res.content.elements.objExtInfo.forEach((item) => {
                        objExtInfo[item.id] = item;
                    });
                }
                this.INITOBJEXTINFO(objExtInfo);
            }

            // 保存样式信息
            if (res.content.style) {
                // 拼接设备默认样式
                this.INITSTYLE(res.content.style);
            } else {
                const style = {};
                this.INITSTYLE(style);
            }

            // parse.nodes.forEach((item) => {
            //     item.connect("finishCreated", this.scene, this.scene.finishCreated);
            //     item.connect("onContextMenu", this, this.scene.getItem);
            //     this.scene.addItem(item);
            //     // 如果为设备则存于vuex中便于联动
            //     if (item instanceof SBaseEquipment) {
            //         anchorList = anchorList.concat(item.anchorList);
            //         this.ADDEQUIPITEM(item);
            //     }
            // });

            // 管线元素最后添加
            // parse.relations.forEach((t) => {
            //     // 设置锚点
            //     if (t.anchor1Id) {
            //         let startAnc = null;
            //         anchorList.forEach((aItem) => {
            //             if (aItem.id == t.anchor1Id) {
            //                 startAnc = aItem;
            //             }
            //         });

            //         if (startAnc) {
            //             startAnc.isConnected = true;
            //             startAnc.parent?.connect("changePos", t, t.changePos);
            //             t.startAnchor = startAnc || null;
            //             console.log("startAnc", startAnc);
            //         }
            //     }
            //     if (t.anchor12d) {
            //         let endAnc = null;
            //         anchorList.forEach((aItem) => {
            //             if (aItem.id == t.anchor12d) {
            //                 endAnc = aItem;
            //             }
            //         });
            //         if (endAnc) {
            //             endAnc.isConnected = true;
            //             endAnc.parent?.connect("changePos", t, t.changePos);
            //             t.endAnchor = endAnc || null;
            //         }
            //     }
            //     t.connect("finishCreated", this.scene, this.scene.finishCreated);
            //     t.connect("onContextMenu", this, this.scene.getItem);
            //     this.scene.addItem(t);
            // });

            if (res.content.ruleList?.length) {
                res.content.ruleList.forEach(async (rule) => {
                    if (rule.commond && rule.commond === "query") {
                        if (rule.returnType && rule.returnType === "equip") {
                            const params = { ...rule.params, buildingId: this.buildingId, floorId: this.floorId };
                            const res = await equipQuery(params);
                            if (res.result === "success") this.mergeEquipData(res.content);
                        } else if (rule.returnType && rule.returnType === "zone") {
                            setTimeout(() => {
                                console.error("请求空间数据");
                            }, 1000);
                        } else if (rule.returnType && rule.returnType === "equipGroup") {
                            setTimeout(() => {
                                console.error("请求设备组数据");
                            }, 1000);
                        }
                    } else if (rule.commond && rule.commond === "delete") {
                        /**
                         * 暂未实现
                         */
                        console.error("删除命令！！！", rule);
                    }
                });
            }
        },
        // 解析设备数据
        mergeEquipData(equipList) {
            equipList.forEach((equip) => {
                if (!this.equipItemMap[equip.id]) {
                    if (this.objExtInfo[equip.id]) {
                        equip = { ...this.objExtInfo[equip.id], ...equip };
                    }
                    if (!equip.pos) {
                        //如果未维护设备在图中的坐标
                        if (equip.locationJson) {
                            // 判断设备是否维护BIM坐标
                            const { x, y, z } = equip.locationJson;
                            equip.pos = { x, y: -y, z };
                        } else {
                            // 否则显示默认坐标位置
                            equip.pos = { x: 0, y: 0, z: 0 };
                        }
                    }
                    // 添加设备对象类型
                    equip.properties = {type: "BaseEquipment"}
                    const equipItem = new SPlanEquipment(null, equip);
                    equipItem.selectable = true;
                    equipItem.moveable = true;
                    equipItem.connect("finishCreated", this.scene, this.scene.finishCreated);
                    equipItem.connect("onContextMenu", this, this.scene.getItem);
                    if (this.styleMap[equip.id]) {
                        SPlanDecorator.equipDecorator(equipItem, this.styleMap[equip.id]);
                    } else if (this.styleMap[equip.classCode]) {
                        console.log(this.styleMap[equip.classCode])
                        SPlanDecorator.equipDecorator(equipItem, this.styleMap[equip.classCode]);
                    } else {
                        SPlanDecorator.equipDecorator(equipItem, this.styleMap["defaultEquipStyle"]);
                    }
                    this.scene.addItem(equipItem);
                    this.ADDEQUIP(equipItem);
                }
            });
            console.log(this.scene)
            this.view.fitSceneToView();
        },

        // 生成快照并保存草稿
        saveTopoDraft() {
            const uuid = uuidv1();
            return Promise.all([this.generateSnap(uuid), this.saveDraft(uuid)]).then((vals) => {
                // 重设版本号
                this.SETVERSION(vals[1].version);
                this.$message.success(`保存成功${vals[1].version}`);
            });
        },
        // 生成快照
        generateSnap(uuid) {
            // 隐藏选择器
            this.scene.selectContainer.clear();
            setTimeout(() => {
                // base64数据
                const data = this.view.imageUrl("png");
                // 根据base64生成file
                const file = base64ToFile(data);
                const reader = new FileReader();
                const fileType = file.name.split(".");
                const imgType = fileType[fileType.length - 1];
                return new Promise((resolve, reject) => {
                    reader.onloadend = function () {
                        // 这个事件在读取结束后，无论成功或者失败都会触发
                        if (reader.error) {
                            console.log("reader error", reader.error);
                            reject(reader.error);
                        } else {
                            // 构造 XMLHttpRequest 对象，发送文件 Binary 数据
                            const xhr = new XMLHttpRequest();
                            xhr.open(
                                "POST",
                                `/image-service/common/image_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true&key=${uuid}.${imgType}`
                            );
                            xhr.send(reader.result);
                            xhr.onreadystatechange = function () {
                                if (xhr.readyState == 4) {
                                    if (xhr.status == 200) {
                                        resolve(xhr);
                                    }
                                }
                            };
                        }
                    };
                    reader.readAsArrayBuffer(file);
                });
            }, 80);
        },
        // 保存草稿
        saveDraft(uuid) {
            const elements = this.scene.save();
            const obj = {
                elements,
                // name: this.planContent.name, // 名称
                // categoryId: this.categoryId, // 图分类ID
                // projectId: this.projectId, // 项目ID
                // label: this.planContent.label,
                // buildingId: "1", // 建筑ID
                // floorId: "1", // 楼层id
                // note: "1", // 图说明
                pic: `${uuid}.png`,
                graphId: this.graphId,
                id: this.id,
                // version: this.version,
            };
            return new Promise((resolve, reject) => {
                saveGroup(obj).then((res) => {
                    // 如果是从已发布跳转过来
                    if (this.state === "Publish") {
                        // 设置发布状态为 未发布
                        this.SETSTATE("Draft");
                        const gid = res.entityList[0].graphId;
                        const id = res.entityList[0].id;
                        // 重设图id 与 id
                        this.SETPROJECT({ graphId: gid, id: id });
                        // 修改url参数
                        this.$router.push({
                            name: "Editer",
                            query: {
                                graphId: gid,
                                id: id,
                                state: "Draft",
                            },
                        });
                    }
                    resolve(res.entityList[0]);
                });
            });
        },
        // 自动保存
        autoSaveTopo() {
            if (this.scene && this.scene.undoStack.isChange) {
                this.saveTopoDraft().then(() => {
                    this.scene.undoStack.isChange = false;
                });
            }
        },
        // 发布草稿
        issueDraft() {
            const pa = {
                graphId: this.graphId,
                id: this.id,
            };
            publishGraph(pa).then((res) => {
                this.$message.success("发布成功");
            });
        },
        // 手动添加设备
        addEquipmentList(list) {
            const parse = new SPlanParser();
            list.forEach((item, i) => {
                const x = (i + 1) * 100 + 300;
                const baseUrl = "/image-service/common/image_get?systemId=dataPlatform&key=";
                const url = baseUrl + item.url;
                const svg2Base = "";
                const EquipHeight = this.canvasHeight - 100;

                const data = {
                    nodeId: uuidv1(),
                    /** 名称 */
                    name: "基础设备",
                    /** 返回物理世界对象 ID 列表 */
                    attachObjectIds: [item.id],
                    size: { width: 50, height: 50 },
                    /** 图标 (Image)，线类型 (Line) */
                    type: "Image",
                    /** 位置 */
                    pos: { x: x, y: 100 },
                    /** 由应用自己定义 */
                    properties: {
                        type: "BaseEquipment",
                        classCode: item.classCode, // 设备类型
                        localId: item.localId, // 本地编码
                        localName: item.localName, //本地名称
                    },
                    style: {
                        default: {
                            strokecolor: "#c0ccda",
                            url: url,
                            base64Url: "",
                        },
                    },
                };
                parse.addNode(data);
            });
            // 添加到 scence 中
            parse.nodes.forEach((item) => {
                item.connect("finishCreated", this.scene, this.scene.finishCreated);
                item.connect("onContextMenu", this, this.scene.getItem);
                this.scene.addItem(item);
                // 如果为设备则存于vuex中便于联动
                if (item instanceof SBaseEquipment) {
                    this.ADDEQUIPITEM(item);
                }
            });
        },
    },
    watch: {
        editCmd(val) {
            console.trace(val);
            if (this.scene) {
                // 设置当前编辑状态
                this.scene.editCmd = val;
            }
        },
        legendObj: {
            handler: function (val, oldVal) {
                this.scene.legendObj = val;
            },
            deep: true,
        },
    },
    beforeDestroy() {
        clearInterval(this.autoSave);
    },
};
</script>
<style lang="less" scoped>
.baseTopo {
    width: 100%;
    height: 100%;
    position: relative;
    .topoTooltip-box {
        position: absolute;
        left: 0;
        top: 0;
    }
}
</style>