$(function () {
    $(".dropdown-menu.dropdown-select-menu").each((index, value) => {
        setDropdownItem(value);
    });
});

/**
 * fn 定義 | 手動初始化 Bootstrap dropdown select
 */
$.fn.droSetItem = function () {
    setDropdownItem(this);
    return this;
};
/**
 * fn 定義 | 輸出含原元素 html
 */
$.fn.outerHtml = function () {
    return $(this).prop("outerHTML");
};

/**
 * fn 定義 | Loading 操作
 * @param {any} type - close / start / exceed , exceed => 繼續執行並可切換文字
 * @param {any} text - 右下角 Alert 文字
 */
$.fn.Loading = function (type = "close", text) {
    let ele = this;
    let aleObj = $(this)[0]._aleObj;
    let showStatus = $(ele).data("loading-show-status");

    function closeLoading() {
        $(ele).data("loading-show-status", "close");
        $("body").css("overflow", "auto");
        $(aleObj.ele).YTAlert().hide();
        $(ele).animate({ opacity: 0 }, 300, () => {
            if ($(ele).data("loading-show-status") == "close") {
                $(ele).hide();
            }
        });
    }
    function showLoading() {
        $(ele).data("loading-show-status", "show");
        $("body").css("overflow", "hidden");
        let aleObj = YT.Alert.Tip(text || "讀取中,請稍後", "show");
        $(ele)[0]._aleObj = aleObj;
        $(ele).show();
        $(ele).animate({ opacity: 1 }, 300);

        $(aleObj.ele).YTAlert().text(text);
    }
    if (type == "close") {
        closeLoading();
    } else if (type == "exceed") {
        $(aleObj.ele).YTAlert().text(text);
    } else if (type == "start") {
        showLoading();
    }

    return $(this);
};

$.fn.YTAlert = function () {
    let th = { element: this };
    th.hide = function (delay = 0) {
        let obj = this;
        setTimeout(function () {
            $(obj.element).fadeOut(300);
            alertIdArray.splice(
                $.inArray($(obj.element).prop("id"), alertIdArray),
                1
            );
            setTimeout(function () {
                $(obj.element).remove();
            }, 1000);
        }, delay);
    };

    th.text = function (text) {
        let obj = this;
        let id = $(obj.element).prop("id").split("tip-alert-")[1];
        $(`#alert-text-${id}`).text(text);
    };
    return th;
};

/**
 * 設置 bootstrap dropdown 為下拉選單
 * @param {any} menuEle - .dropdown-menu element
 */
function setDropdownItem(menuEle) {
    if ($(menuEle).find(".dropdown-item.active").length == 0) {
        $(menuEle).find(".dropdown-item").first().addClass("active");
    }

    let actText = $(menuEle).find(".dropdown-item.active").first().text();
    let actEleId = $(menuEle).prop("id");
    $(`.dropdown-toggle[data-target=${actEleId}]`).text(actText);

    /*actChaCallback($(menuEle).find(".dropdown-item.active"))*/
    $(menuEle).trigger("active:change", $(menuEle).find(".dropdown-item.active"));

    //點選選項 add active class
    onEvent(
        "click",
        ".dropdown-menu.dropdown-select-menu .dropdown-item",
        function () {
            $(this)
                .parent(".dropdown-menu.dropdown-select-menu")
                .find(".dropdown-item")
                .removeClass("active");
            $(this).addClass("active");
            setDropdownItem($(this).parent(".dropdown-menu.dropdown-select-menu"));
        }
    );
}

/**
 * 預設設備圖像
 * @param {any} obj
 */
function defDev(obj) {
    let defSrc = "img/defdev.png";
    obj.src = defSrc;
}

/**
 * jquery datatable - ajax send data reset
 * @param {any} table
 * @param {any} sendData
 */
function dtAjaxResetSendData(table, sendData) {
    table.context[0].ajax.data = function (d) {
        d = sendData;
        return JSON.stringify(d);
    };
}

/**
 * element 建造
 * @param {any} text
 * @param {any} id
 * @param {any} name
 * @param {any} cls
 * @param {any} data
 * @param {any} attr
 */
function eleBuild(
    text = null,
    id = null,
    name = null,
    cls = [],
    data = {},
    attr = {}
) {
    (cls = cls ?? []), (data = data ?? {}), (attr = attr ?? {});
    id = id ? `id="${id}"` : "";
    name = name ? `name="${name}"` : "";
    cls = cls.length != 0 ? `class="${cls.join(" ")}"` : "";
    data =
        data.length != 0
            ? `${Object.keys(data)
                .map((x) => `data-${x}="${data[x]}"`)
                .join(" ")}`
            : "";
    attr = attr
        ? `${Object.keys(attr)
            .map((x) => `${x}="${attr[x]}"`)
            .join(" ")}`
        : "";
    let attrArr = [],
        attrText = "";
    attrArr = [id, name, cls, data, attr];
    attrText = attrArr.filter((x) => x != "").join(" ");
    text = text === null ? "" : text;
    return { attrText: attrText, text: text };
}

function creEle(
    ele,
    text = null,
    id = null,
    name = null,
    cls = [],
    data = {},
    attr = {}
) {
    let comp = eleBuild(text, id, name, cls, data, attr);
    return $(`<${ele} ${comp.attrText}>${comp.text}</${ele}>`);
}

function creDiv(
    cls = [],
    attr = {},
    id = null,
    name = null,
    data = {},
    text = null
) {
    return creEle("div", text, id, name, cls, data, attr);
}

function creBtn(
    text = null,
    id = null,
    name = null,
    cls = [],
    data = {},
    attr = {}
) {
    return creEle("button", text, id, name, cls, data, attr);
}

function creBtnHtml(
    text = null,
    id = null,
    name = null,
    cls = [],
    data = {},
    attr = {}
) {
    return creEle("button", text, id, name, cls, data, attr).prop("outerHTML");
}

function creSelect(
    id = null,
    cls = [],
    name = null,
    data = {},
    attr = {},
    text = null
) {
    return creEle("select", text, id, name, cls, data, attr);
}

function creOption(
    text = null,
    value = null,
    data = {},
    attr = {},
    cls = [],
    name = null,
    id = null
) {
    value != null ? (attr.value = value) : attr;
    return creEle("option", text, id, name, cls, data, attr);
}

function creImg(
    ele,
    text = null,
    id = null,
    name = null,
    cls = [],
    data = {},
    attr = {}
) {
    let comp = eleBuild(text, id, name, cls, data, attr);
    return $(`<${ele} ${comp.attrText}>${comp.text}`);
}

function creI(
    cls = [],
    data = {},
    attr = {},
    id = null,
    name = null,
    text = null
) {
    return creEle("i", text, id, name, cls, data, attr);
}

function creA(
    text = null,
    attr = {},
    cls = [],
    id = null,
    data = {},
    name = null
) {
    return creEle("a", text, id, name, cls, data, attr);
}

function creSpan(
    text = null,
    cls = [],
    id = null,
    attr = {},
    data = {},
    name = null
) {
    return creEle("span", text, id, name, cls, data, attr);
}
/**
 * 根據該棟建築底下的'所有'電梯執行緒物件
 * */
class ElevatorHandler {
    constructor(ele, option = {}) {
        this.ele = ele;
        this.eleId = "";
        this.eleWra = $("<div></div>");
        this.speed = 0.3;
        this.movStatus = {}; // {id:elevator01,value:0} 0=no 1=up 2=down
        this.floorHeight =
            typeof option.fHeight == "undefined" ? 60 : option.fHeight;
        this.floorWidth = typeof option.fWidth == "undefined" ? 45 : option.fWidth;
        this.floors = typeof option.floors == "undefined" ? [{}] : option.floors;
        this.elevators =
            typeof option.elevators == "undefined" ? [{}] : option.elevators; // {id:elevator01}
        this.curElevFloor =
            typeof option.curElevFloor == "undefined" ? {} : option.curElevFloor;
        this.setTimeout = null;
        this.init();
    }

    // 所有電梯初始化
    init = function () {
        this.setTabWra();
        this.setTabFloor();
        // 若已有每個設備的所在樓層,則預設到該樓層位置
        if (Object.keys(this.curElevFloor).length != 0) {
            $.each(Object.keys(this.curElevFloor), (idx, elevKey) => {
                this.setElevFloor(elevKey, this.curElevFloor[elevKey]);
            });
        }
    };

    // 設置 wrapper
    setTabWra = function () {
        let id = $(this.ele).prop("id");
        this.eleId = id;
        if ($(this.ele).parent(".elevator-table-wrapper").length != 0) {
            $(this.ele).unwrap(".elevator-table-wrapper");
        }
        let wrapper = creDiv(["elevator-table-wrapper"], null, `${id}_wrapper`);
        $(this.ele).wrap(wrapper);
        this.eleWra = wrapper;
    };

    // 設置 table 樓層
    setTabFloor = function () {
        let _w = this.floorWidth,
            _h = this.floorHeight;
        let thead = creEle("thead"),
            tbody = creEle("tbody");
        let _floors = this.floors,
            _ele = this.ele,
            _elevators = this.elevators;
        //樓層從小到大
        _floors = _floors
            .oSort("sort")
            .reverse()
            .map((x) => x.name);

        let theadTr = creEle("tr");

        for (let e = 1; e <= _elevators.length + 2; e++) {
            let th = creEle("th");
            th.css({ width: `${_w}px`, height: `${_h}px`, position: "relative" });
            if (e != 1 && e != _elevators.length + 2) {
                let elevId = _elevators[e - 2]?.id;
                // 電梯方框
                let span = creEle("span", null, "elevator-item-" + elevId, null, [
                    "elevator-item",
                ]);
                let spanUp = creEle("span", null, null, null, ["elevator-item-toup"]);
                let spanDown = creEle("span", null, null, null, [
                    "elevator-item-todown",
                ]);
                span.css({
                    width: `${_w - 3}px`,
                    height: `${_h - 3}px`,
                    top: `1.5px`,
                    left: "1.5px",
                    transition: `transform ${1 / this.speed
                        }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`,
                });
                spanUp.css({
                    width: `${_w - 3}px`,
                    height: `${(_h - 3) / 2}px`,
                    top: `1.5px`,
                    left: "1.5px",
                    transition: `transform ${1 / this.speed
                        }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`,
                });
                spanDown.css({
                    width: `${_w - 3}px`,
                    height: `${(_h - 3) / 2}px`,
                    top: `1.5px`,
                    left: "1.5px",
                    transition: `transform ${1 / this.speed
                        }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`,
                    top: `${1.5 + (_h - 3) / 2}px`,
                });
                th.append(spanUp);
                th.append(span);
                th.append(spanDown);
            }
            theadTr.append(th);
        }
        thead.css("position", "absolute");
        thead.append(theadTr);

        //樓層表格建置 tbody
        for (let f = 1; f <= _floors.length; f++) {
            let tr = creEle("tr");

            for (let e = 1; e <= _elevators.length + 2; e++) {
                let td = creEle("td");
                td.css({ width: `${_w}px`, height: `${_h}px` });
                if (e == 1) {
                    td.addClass("t-black");
                    td.text(_floors[f - 1]);
                } else if (e == _elevators.length + 2) {
                } else {
                    let div = creDiv([
                        "d-flex",
                        "justify-content-center",
                        "align-items-end",
                        "h-100",
                    ]);
                    div.append(`<i class="fal fa-door-open fs-1-2"></i>`);
                    td.append(div);
                }
                tr.append(td);
            }
            tbody.append(tr);
        }

        $(_ele).append(thead);
        $(_ele).append(tbody);

        //表格外圍無框線
        $(_ele)
            .find("tbody tr")
            .each((index, tr) => {
                $(tr).find("td:eq(0)").css("border-left", "0");
                $(tr).find("td:eq(-1)").css("border-right", "0");

                if (index == 0) {
                    $(tr)
                        .find("td")
                        .each((index, td) => {
                            $(td).css("border-top", "0");
                        });
                } else if (index == $("#floorTable tbody tr").length - 1) {
                    $(tr)
                        .find("td")
                        .each((index, td) => {
                            $(td).css("border-bottom", "0");
                        });
                }
            });
    };

    // 設置某個電梯到某個樓層
    setElevFloor = function (elevId, floId) {
        let curFloId = this.curElevFloor[elevId];
        let curSort = this.floors
            .filter((x) => x.id == curFloId)
            .map((x) => x.sort)[0];
        let tarSort = this.floors
            .filter((x) => x.id == floId)
            .map((x) => x.sort)[0];
        let gapFloor = tarSort - curSort;
        let cssEle = [
            $(`#elevator-item-${elevId}`)[0],
            $(`#elevator-item-${elevId}`).prev("span.elevator-item-toup")[0],
            $(`#elevator-item-${elevId}`).next("span.elevator-item-todown")[0],
        ];
        if (this.movStatus[elevId] != 0) {
            $(cssEle).css(
                "transition",
                `transform ${(1 / this.speed) * Math.abs(gapFloor)
                }s cubic-bezier(0, 0, 0.62, 1) 0s`
            );
        }
        clearTimeout(this.setTimeout);
        this.setTimeout = setTimeout(() => {
            $(cssEle).css(
                "transition",
                `transform ${(1 / this.speed) * Math.abs(gapFloor)
                }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`
            );
            this.setEleUpDownStyle(elevId);
        }, (1 / this.speed) * Math.abs(gapFloor) * 1000);
        this.setEleUpDownStyle(elevId);
        this.curElevFloor[elevId] = floId;
        $(cssEle).css(
            "transition",
            `transform ${(1 / this.speed) * Math.abs(gapFloor)
            }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`
        );
        $(cssEle).css(
            "transform",
            `translateY(${this.floorHeight * (this.floors.length - tarSort)}px)`
        );
    };

    // 設定現在電梯狀態 (往上/往下/停止)
    setEleMovStatus = function (elevId, status) {
        this.movStatus[elevId] = status;
    };

    // 電梯方框 往上或往下閃爍
    setEleUpDownStyle = function (elevId) {
        if (this.movStatus[elevId] == 1) {
            $(`#elevator-item-${elevId}`)
                .next("span.elevator-item-todown")
                .removeClass("light-flash-c-bd");
            $(`#elevator-item-${elevId}`)
                .prev("span.elevator-item-toup")
                .addClass("light-flash-c-bd")
                .css("--flash-color-1", "#44ea8e")
                .css("--flash-color-2", "rgba(255,255,255,0)");
        } else if (this.movStatus[elevId] == 2) {
            $(`#elevator-item-${elevId}`)
                .prev("span.elevator-item-toup")
                .removeClass("light-flash-c-bd");
            $(`#elevator-item-${elevId}`)
                .next("span.elevator-item-todown")
                .addClass("light-flash-c-bd")
                .css("--flash-color-1", "#44ea8e")
                .css("--flash-color-2", "rgba(255,255,255,0)");
        } else {
            $(`#elevator-item-${elevId}`)
                .prev("span.elevator-item-toup")
                .removeClass("light-flash-c-bd");
            $(`#elevator-item-${elevId}`)
                .next("span.elevator-item-todown")
                .removeClass("light-flash-c-bd");
        }
    };

    // 設定現在某個電梯所在樓層
    setCurElevFloor = function (elevId, floId) {
        this.curElevFloor[elevId] = floId;
    };

    // 重新繪製
    redraw = function () {
        $(this.ele).empty();
        this.setTabFloor();
        if (Object.keys(this.curElevFloor).length != 0) {
            $.each(Object.keys(this.curElevFloor), (idx, elevKey) => {
                this.setElevFloor(elevKey, this.curElevFloor[elevKey]);
            });
        }
    };
}

// 從數字週數轉為中文週數
function dayToChiDay(num) {
    let chiDay = ["週日", "週一", "週二", "週三", "週四", "週五", "週六"];
    return chiDay[num];
}

// 取得現在或前後時間,輸出單位依據 type
function getTimeByType(type = null, cal = 0, unit = "d") {
    let now = new Date();
    return strToDate(now, type, cal, unit);
}

// 取得某當下時間或前後時間,輸出單位依據 type
function strToDate(text, type = null, cal = 0, unit = "d") {
    let dec = 24 * 60 * 60 * 1000;

    if (unit == "d") {
        dec = 24 * 60 * 60 * 1000;
    } else if (unit == "h") {
        dec = 60 * 60 * 1000;
    } else if (unit == "m") {
        dec = 60 * 1000;
    } else if (unit == "s") {
        dec = 1000;
    }

    let calDay = function (_d, _cal) {
        return new Date(_d.getTime() + cal * dec);
    };

    let tarDate = new Date(text);
    let result = 0;
    if (type == "year") {
        result = calDay(tarDate, cal).getFullYear();
    } else if (type == "month") {
        result = calDay(tarDate, cal).getMonth();
    } else if (type == "date") {
        result = calDay(tarDate, cal).getDate();
    } else if (type == "day") {
        result = calDay(tarDate, cal).getDay();
    } else {
        result = calDay(tarDate, cal);
    }
    return result;
}

// 將只有時間(Hms) 格式轉換為當日的時間
function fullTime(time) {
    let nowDate = displayDate(new Date(), "date");
    return new Date(nowDate + " " + time);
}

function dateRanCutPart(start, end, cutNum) {
    let sTime = new Date(start).getTime();
    let eTime = new Date(end).getTime();
    let cutTimeArr = [];
    if (sTime < eTime) return [];

    let partNum = (sTime - eTime) / cutNum;
    for (let i = eTime; i <= sTime; i = i + partNum) {
        cutTimeArr.push(i);
    }

    cutTimeArr.forEach((x) => new Date(x));

    return cutTimeArr;
}

function isJSON(str) {
    try {
        JSON.parse(str);
        return true;
    } catch {
        return false;
    }
}

function addBsToast(
    container,
    type = "warning",
    title = "",
    content = "",
    id,
    datas = {},
    option = {}
) {
    datas =
        Object.keys(datas).length != 0
            ? `${Object.keys(datas)
                .map((x) => `data-${x}="${datas[x]}"`)
                .join(" ")}`
            : "";
    let iconClass = option.iconHtml ?? `fas fa-exclamation-triangle`;
    let strHtml = `<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false" ${datas}>
                      <div class="toast-header ${warning ? `bg-` + warning : ""
        }">
                          <i class="${iconClass}"></i>
                          <strong class="mr-auto">${title}</strong>
                          <small class="text-muted">just now</small>
                          <button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
                              <span aria-hidden="true">&times;</span>
                          </button>
                      </div>
                      <div class="toast-body">
                          ${content}
                      </div>
                  </div>`;
}

/**
 * 取得資料庫電梯設備,根據 baja 訂閱移動 3D 電梯
 * */
class Forge3DElevFull {
    constructor(option = {}) {
        this.allElevDevList = []; //全電梯設備清單
        this.subSeviceData = []; //每個設備訂閱點位值
        this.floList = [];
        this.elev3DBind = {};
        this.elev3DOption = {};
        this.elev3DObj = [];
        this.viewer = option.viewer ?? null;
        this.ordPath = option.ordPath ?? {};
        this.sysMainTag = option.system_tag ?? "ELEV";
        this.sysSubTag = option.name_tag ?? "EL";
        this.selector = option.selector ?? "#forgeViewer";
        this.bajaChaCallback = option.bajaChaCallback ?? null;
        this.bajaEndCallback = option.bajaEndCallback ?? null;
        this.sensorObjs = option.sensorObjs ?? null;
    }

    init = function () {
        // 系統大類、小類固定
        this.ordPath.system_tag = this.sysMainTag;
        this.ordPath.name_tag = this.sysSubTag;

        // if (pageAct.sysSubTag === "M12") {
        //   console.log("@@",pageAct, pageAct.sysSubTag)
        //   this.getSensorDevList();
        // }
        this.getElevDevList();
    };

    // 訂閱電梯設備
    subElevDevice = function () {
        let myBaja = new subscriptionDevices();
        let ordPath = this.ordPath;

        myBaja.setSubscribeDevicesByBql(ordPath);
        myBaja.setSubscribeDevicesCallBack((data) => {
            this.bajaChaCallback ? this.bajaChaCallback(data) : "";
            if (this.allElevDevList.length == 0) {
                return false;
            }
            data.device_number = data.device_number_full;

            let matchDevice = this.allElevDevList.filter(
                (x) => x.device_number == data.device_number
            )[0];

            if (!matchDevice) {
                return;
            }

            //將訂閱值塞入 subSeviceData
            if (
                this.subSeviceData.findIndex(
                    (x) => x.device_number == matchDevice.device_number
                ) == -1
            ) {
                let obj = {};
                obj.device_number = matchDevice.device_number;
                this.subSeviceData.push(obj);
            }

            let subData = this.subSeviceData.filter(
                (x) => x.device_number == matchDevice.device_number
            )[0];

            if (subData) {
                subData[data.point_name] = data.value;
            }

            if (data.point_name == "CP") {
                if (this.elev3DObj.length != 0) {
                    let elevObj = this.elev3DObj.filter(
                        (x) => x.nodeId == this.elev3DBind[matchDevice.device_number]
                    )[0];
                    if (elevObj && elevObj.id) {
                        elevObj.obj.setElevatorFloor(data.value);
                        elevObj.obj.movElevator();
                    }
                }
            }
        });

        myBaja.setSubscribeDeviceEndCallBack((data) => {
            this.floList = data
                .filter((x) => x.point_name.startsWith("SP_FLS_"))
                .map((x) => x?.point_name?.split("SP_FLS_")[1])
                .Distinct();
            this.set3DElevOpt(data);
            this.bajaEndCallback != null ? this.bajaEndCallback() : "";
        });
    };

    // 電梯 3D Option 設置
    set3DElevOpt = function (data) {
        let devNumArr = data
            .map((x) => {
                return {
                    devNum: x.device_number_full,
                    priority: this.allElevDevList.filter(
                        (y) => y.device_number == x.device_number_full
                    )[0]?.priority,
                };
            })
            .DistinctBy("devNum");
        devNumArr = devNumArr.oSort("priority");
        $.each(devNumArr, (idx, devObj) => {
            let devNum = devObj.devNum;
            let subData = this.subSeviceData.filter(
                (x) => x.device_number == devNum
            )[0];

            if (subData) {
                //// 左側 3D 電梯 nodeID 與 device_number match
                //if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
                //    elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
                //}
                // 左側 3D 電梯 Viewer Option 設置
                /*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
                this.elev3DOption.nodeId = this.elev3DBind[devNum];
                this.elev3DOption.floorHeight = this.floList.map((x) => {
                    return { floor: x };
                });
                this.elev3DOption.floorHeight.forEach((floObj, idx) => {
                    if (floObj.floor.startsWith("B")) {
                        let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
                        floObj.height = floor * -13;
                    } else {
                        let floor = parseInt(floObj.floor.split("F")[0]);
                        if (floor == 1) {
                            floObj.height = 0;
                        } else if (floor == 2) {
                            floObj.height = 14.75;
                        } else {
                            floObj.height = 14.75 + (floor - 2) * 9.75;
                        }
                    }
                });

                if (this.elev3DObj.length != 0) {
                    let elevObj = this.elev3DObj.filter(
                        (x) => x.nodeId == this.elev3DBind[devNum]
                    )[0];
                    if (!elevObj.id) {
                        elevObj.id = devNum;
                    }
                    elevObj.obj = Object.assign(elevObj.obj, this.elev3DOption);
                    elevObj.obj.init(() => {
                        let frags = elevObj.obj.fragProxys.filter(
                            (x) => x.nodeId == this.elev3DBind[devNum]
                        );

                        frags.forEach((fragProxy) => {
                            fragProxy.frag.position.z =
                                this.elev3DOption.floorHeight.filter(
                                    (x) => x.floor == subData["CP"]
                                )[0]?.height ?? 0;
                            let start = 0;
                            // 改變感測器熱點位置
                            this.sensorObjs &&
                                this.sensorObjs[0]?.changePos(
                                    node + 2,
                                    fragProxy.frag.position.z
                                );
                            // if (node === 15200 && start == 0) {
                            //     start = 1;
                            // }
                            fragProxy.frag.updateAnimTransform();
                        });
                        elevObj.obj.viewer.impl.sceneUpdated(true);
                    });
                }
            }
        });
        this.set3DElevPos();
    };

    // 電梯 3D 位置呈現
    set3DElevPos = function () {
        let nodeIds = this.allElevDevList
            .filter((x) => !isNaN(parseInt(x.forge_dbid)))
            .map((x) => {
                return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) };
            });

        $.each(nodeIds, (idx, item) => {
            this.elev3DBind[item.devNum] = item.nodeId;
        });
        nodeIds = nodeIds.map((x) => x.nodeId);
        $.each(nodeIds, (idx, node) => {
            let options = {
                element: $(this.selector),
                viewer: this.viewer,
                nodeId: node,
                floorHeight: this.elev3DOption.floorHeight ?? [],
                sensorObjs: this.sensorObjs,
                inited: function () { },
            };
            let elevator3DObj = new elevator3D(options);
            let devNum = Object.keys(this.elev3DBind).filter(
                (x) => this.elev3DBind[x] == node
            )[0];
            let subData = this.subSeviceData.filter(
                (x) => x.device_number == devNum
            )[0];

            if (this.elev3DObj.filter((x) => x.nodeId == node).length == 0) {
                this.elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
            }

            if (subData) {
                let elevObj = this.elev3DObj.filter((x) => x.nodeId == node)[0];
                if (!elevObj.id) {
                    elevObj.id = devNum;
                }
                elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {});
                elevObj.obj.init(() => {
                    let frags = elevObj.obj.fragProxys.filter((x) => x.nodeId == node);
                    frags.forEach((fragProxy) => {
                        fragProxy.frag.position.z =
                            this.elev3DOption.floorHeight.filter(
                                (x) => x.floor == subData["CP"]
                            )[0]?.height ?? 0;
                        let start = 0;
                        this.sensorObjs &&
                            this.sensorObjs[0]?.changePos(
                                node + 2,
                                fragProxy.frag.position.z
                            );
                        // if (node === 15200 && start == 0) {
                        //     // 改變感測器熱點位置
                        //     start = 1;
                        // }
                        fragProxy.frag.updateAnimTransform();
                    });
                    elevObj.obj.viewer.impl.sceneUpdated(true);
                });
            }
        });
    };

    // 取得設備列表
    getElevDevList = function () {
        let url = baseApiUrl + "/api/Device/GetDeviceList";
        let sendData = {
            sub_system_tag: this.ordPath.name_tag,
            building_tag: this.ordPath.building_tag,
        };
        objSendData.Data = sendData;
        ytAjax = new YourTeam.Ajax(
            url,
            objSendData,
            (res) => {
                if (!res || res.code != "0000" || !res.data) {
                } else {
                    $.each(res.data, (index, floObj) => {
                        $.each(floObj.device_list, (index2, devObj) => {
                            this.allElevDevList.push(devObj);
                        });
                    });
                    this.subElevDevice();
                }
            },
            null,
            "POST"
        ).send();
    };

    getNodeIds = function () {
        return this.elev3DObj.map((x) => x.nodeId);
    };
}

/**
 * 取得資料庫溫度感測器
 * 1. baja 取得溫度感測器改變顏色
 * 2. 參數取得要移動到的電梯位置
 * */
class Forge3DSensor {
    constructor(option = {}) {
        this.subDeviceData = []; //每個設備訂閱點位值
        this.viewer = option.viewer ?? null;
        this.ordPath = option.ordPath; // TPE_B1
        this.sysMainTag = "ME";
        this.sysSubTag = "M12";
        this.selector = "#forgeViewer";
        this.heatMap = null;
        this.bajaChaCallback = option.bajaChaCallback ?? null;
        this.bajaEndCallback = option.bajaEndCallback ?? null;
        this.floorHeight = 0;
        this.dataVizExtn = null;
        this.DataVizCore = null;
        this.tempVal = 20;
        this.curDevice = option.curDevice ?? null;
        this.selector = option.selector ?? "#forgeViewer";
        this.elevCb = option.elevCb ?? null;
        this.deviceList = option.deviceList ?? null;
        this.#init();
    }

    #init = async function () {
        // 系統大類、小類固定
        this.ordPath.system_tag = this.sysMainTag;
        this.ordPath.name_tag = this.sysSubTag;
        this.dataVizExtn = await this.viewer.loadExtension(
            "Autodesk.DataVisualization"
        );
        this.DataVizCore = Autodesk.DataVisualization.Core;
        await this.registerHotPoint();
        this.changeColorForSensorHotspot(this.curDevice.forge_dbid, 35);
        this.elevCb && this.elevCb();
        this.subSensorDevice();
    };

    // // 建立熱點
    // async addHotPoint() {

    //     // this.dataVizExtn.removeAllViewables()
    //     await this.registerHotPoint()
    //     this.subSensorDevice();
    //     // console.log("2",this.dataVizExtn)
    // }

    async registerHotPoint(color = "") {
        var viewer = this.viewer;
        const viewableType = this.DataVizCore.ViewableType.SPRITE; //DataVizCore.ViewableType.SPRITE;
        const spriteColor = new THREE.Color(0xff8c00);
        // const highlightedColor = new THREE.Color(0xe0e0ff);
        let spriteIcon = "/file/img/forge/sensor_circle.svg";
        if (location.href.indexOf("localhost:5966") != -1) {
            spriteIcon = "/img/forge/sensor_circle.svg";
        }
        const style = new this.DataVizCore.ViewableStyle(
            viewableType,
            spriteColor,
            spriteIcon
        );

        const viewableData = new this.DataVizCore.ViewableData();
        viewableData.spriteSize = 30; // Sprites as points of size 24 x 24 pixels
        // console.log(this.curDevice, [this.curDevice])

        [this.curDevice].forEach((myData, index) => {
            // console.log(myData)
            const dbId = myData.forge_dbid;
            const myPosition = myData.position;
            const viewable = new this.DataVizCore.SpriteViewable(
                myPosition,
                style,
                dbId
            );
            myData._dbId = dbId;
            viewableData.addViewable(viewable);
        });
        // console.log(viewableData)
        await viewableData.finish();
        this.dataVizExtn.addViewables(viewableData);
        // console.log("1",this.dataVizExtn)
        viewer.addEventListener(
            this.DataVizCore.MOUSE_CLICK,
            this.onSpriteClicked.bind(this)
        ); // SPRITE_SELECTED
        // viewer.addEventListener(this.DataVizCore.MOUSE_CLICK_OUT, onSpriteClickedOut.bind(this));
    }
    // ---------------- 熱點點擊事件 --------------------
    onSpriteClicked(event) {
        console.log(event);
        event.hasStopped = true;
        const dbIdStart = 10;
        if (event != undefined && event != null) {
            if (event.dbId >= dbIdStart) {
                let myData = [this.curDevice].filter(
                    (x) => x.forge_dbid == event.dbId
                )[0];
                this.changeColorForSensorHotspot(event.dbId, this.tempVal);
                moveViewToDevice(myData.forge_dbid); //移動視角至該設備
                $(this.selector).trigger("autodesk:click:sprite", { event, myData });
            } else {
                $(this.selector).trigger("autodesk:clickOut:sprite", { event });
            }
        }
    }

    // 改變熱點位置
    async changePos(dbId, positionZ) {
        // const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization") || this.dataVizExtn;
        this.dataVizExtn?.invalidateViewables(dbId, (viewable) => {
            // console.log(viewable._position)
            const z = viewable._position.z + positionZ;
            const newPos = { ...viewable._position, z };
            return {
                // Move the viewable to a new location.
                position: newPos,
            };
        });
    }

    // 熱點 更換顏色---環境感知器
    async changeColorForSensorHotspot(dbId, temp, type = "") {
        // const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
        const temps = [
            new THREE.Color(0x00009c),
            new THREE.Color(0xffff31),
            new THREE.Color(0xff8c00),
            new THREE.Color(0xff0000),
        ];
        let index = Math.floor(temp / 10) - 1 || 0;
        if (index > 3) {
            index = 3;
        }
        const viewablesToUpdate = dbId;
        let color = temps[index];
        // debugger
        // this.registerHotPoint(color)
        //   const _this=this
        //   setInterval(() => {
        //     _this.dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
        //         return { color: color };
        //     });
        //     // sceneUpdated(true)
        // }, 1000);
        if (type == "error") {
            color = new THREE.Color(0xff0000);
        }
        this.dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
            return {
                color: color,
            };
        });
        // debugger
        // console.log("3", this.dataVizExtn)
    }

    static deviceScatterNormalArr = [];
    static deviceScatterCloseArr = [];
    static deviceScatterErrorArr = [];

    static deviceNormalArr = [];
    static deviceCloseArr = [];

    // 訂閱sensor設備
    subSensorDevice() {
        // console.log("sensor 訂閱")
        // require(["baja!"], (baja)=>{
        //   const sub = new baja.subscriber();
        //   sub.attach("changed",function(){
        //     console.log(this)
        //   })
        //   baja.Ord.make("local:|foxs:|station:|slot:/TPE/B1/ME/M12/U1F/NA/TH/N1/TEMP").get({subscribe: sub})
        // })

        let myBaja = new subscriptionDevices();
        myBaja.setSubscribeDevicesByBql(this.ordPath);

        myBaja.setSubscribeDevicesCallBack((data) => {
            // console.log(data)
            this.bajaChaCallback ? this.bajaChaCallback(data) : "";
            if (this.curDevice == null) {
                $(loadEle).Loading("close");
                return false;
            }

            data.device_number = data.device_number_full; // "TPE_B1_ME_M12_U1F_NA_TH_N1" (forge TPE_B1_ME_M12_R2F_NA_TH_N1)

            //將訂閱值塞入 subDeviceData
            if (
                this.subDeviceData.findIndex(
                    (d) => d.device_number == this.curDevice.id
                ) == -1
            ) {
                let obj = {};
                obj.device_number = this.curDevice.id;
                obj.dbid = this.curDevice.roomDbId;
                this.subDeviceData.push(obj);
            }
            let subData = this.subDeviceData.find(
                (x) =>
                    x.device_number == this.curDevice.id ||
                    x.device_number == "TPE_B1_ME_M12_R2F_NA_TH_N1"
            );

            if (subData) {
                subData[data.point_name] = data.value;
            }
            let norDevPoiName = this.curDevice.device_normal_point_name;
            let cloDevPoiName = this.curDevice.device_close_point_name || "";
            let errDevPoiName = this.curDevice.device_error_point_name;

            if (data.point_name == "Temp" || data.point_name == "TEMP") {
                this.tempVal = !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0;
                // this.heatMap?.changeTemp(
                //   this.curDevice.id,
                //   !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0,
                // );
                this.curDevice.temp = this.tempVal;
                if (
                    subData &&
                    subData[this.curDevice.device_error_point_name] ==
                    this.curDevice.device_error_point_value
                ) {
                    this.changeColorForSensorHotspot(
                        this.curDevice.forge_dbid,
                        this.curDevice.temp,
                        "error"
                    );
                } else {
                    this.changeColorForSensorHotspot(
                        this.curDevice.forge_dbid,
                        parseInt(data.value)
                    );
                }
                // changeColorForSensorHotspot(this.curDevice.forge_dbid, parseInt(data.value))
            }

            if (
                data.point_name == norDevPoiName &&
                data.value == this.curDevice.device_normal_point_value &&
                !Forge3DSensor.deviceNormalArr.some(
                    ({ device_number }) => device_number === this.curDevice.device_number
                )
            ) {
                //顯示正常燈號
                $(`#${this.curDevice.device_number}_status`)
                    .attr("data-light-type", "normal")
                    .data("light-type", "normal");

                Forge3DSensor.deviceNormalArr.push(this.curDevice);
                Forge3DSensor.deviceCloseArr = Forge3DSensor.deviceCloseArr.filter(
                    (device) => device.spriteDbid !== this.curDevice.spriteDbid
                );
            } else if (
                data.point_name == cloDevPoiName &&
                data.value == this.curDevice.device_close_point_value &&
                !Forge3DSensor.deviceCloseArr.some(
                    ({ device_number }) => device_number === this.curDevice.device_number
                )
            ) {
                $(`#${this.curDevice.device_number}_status`)
                    .attr("data-light-type", "close")
                    .data("light-type", "close");

                Forge3DSensor.deviceCloseArr.push(this.curDevice);
                Forge3DSensor.deviceNormalArr = Forge3DSensor.deviceNormalArr.filter(
                    (device) => device.spriteDbid !== this.curDevice.spriteDbid
                );
            }

            if (
                data.point_name == errDevPoiName &&
                data.value == this.curDevice.device_error_point_value &&
                !alarmDbIdList.some(
                    (device) => device.device_number === this.curDevice.device_number
                )
            ) {
                $(`#${this.curDevice.device_number}_status`)
                    .attr("data-light-error-type", "error")
                    .data("light-error-type", "error");

                alarmDbIdList.push(this.curDevice);
            } else if (
                data.point_name == errDevPoiName &&
                data.value !== this.curDevice.device_error_point_value
            ) {
                $(`#${this.curDevice.device_number}_status`)
                    .attr("data-light-error-type", "")
                    .data("light-error-type", "");
                alarmDbIdList = alarmDbIdList.filter(
                    (device) => device.device_number !== this.curDevice.device_number
                );
            }

            if (
                Forge3DSensor.deviceCloseArr.length === 0 &&
                alarmDbIdList.some(
                    (device) => device.device_number === this.curDevice.device_number
                )
            ) {
                $(`#${this.curDevice.device_number}_status`)
                    .attr("data-light-type", "error")
                    .data("light-type", "error");
            }
            setLightColor();

            if (pageAct.floTag) {
                const option = floChart.getOption();

                if (!alarmDbIdList.some(a => a.device_number === this.curDevice.device_number)) {
                    this.deviceList.forEach((device) => {
                        const cur = option.series[0].data.find(
                            ({ device_number }) => device_number === device.device_number
                        );

                        const normalColor = currentData.find(
                            ({ device_number }) => device_number === device.device_number
                        ).device_normal_color;
                        if (cur) {
                            cur.itemStyle = { color: normalColor };
                        }
                    });
                } else {
                    alarmDbIdList.forEach((device) => {
                        const cur = option.series[0].data.find(
                            ({ device_number }) => device_number === device.device_number
                        );
                        const errColor = currentData.find(
                            ({ device_number }) => device_number === device.device_number
                        )?.device_error_color;

                        if (cur) {
                            cur.itemStyle = { color: errColor };
                        }
                    });
                }
                floChart.setOption(option);
            }
            $(loadEle).Loading("close");
            setDevItemPoiValBySub(data);
        });

        myBaja.setSubscribeDeviceEndCallBack((data) => {
            if (
                data.findIndex(
                    (x) => x.point_name == "Temp" || x.point_name == "TEMP"
                ) != -1
            ) {
                // 顯示溫度條
                showHeat("[name=forgeHeatBar]");
            }
        });
        // window.x = 28
        // setInterval(()=>{
        //   this.changeColorForSensorHotspot(this.curDevice.forge_dbid, x++)
        // }, 2000)
    }
}