<template>
  <div
    ref="wall"
    class="fit bg-white q-py-md q-mx-sm row items-center justify-evenly wall"
  >
    <div
      v-if="!$store.state.power_state"
      style="position: absolute"
      class="full-width text-center"
    >
      <span class="text-h5 text-center" style="z-index: 999; background: white">
        {{ $t("device standby mode") }}
      </span>
    </div>
    <div
      ref="wall_content"
      :style="{
        width: wall_width + 'px',
        height: wall_height + 'px',
      }"
      style="border: 1px solid black"
    >
      <div id="windows" ref="dom_windows" style="position: absolute">
        <vue3-resize-drag
          :w="item.width * wall_content_client_width"
          :h="item.height * wall_content_client_height"
          :x="
            $refs.wall?.parentElement?.offsetLeft +
            $refs.wall_content?.offsetLeft +
            item.x * wall_content_client_width
          "
          :y="
            $refs.wall?.parentElement?.offsetTop +
            $refs.wall_content?.offsetTop +
            item.y * wall_content_client_height +
            $store.state.wall_row / ($store.state.landspace ? 2 : 1)
          "
          :zIndex="
            1 +
            $store.state.windows_sort.findIndex(
              (element) => element == item.uuid
            )
          "
          :isActive="item.uuid == $store.state.selected_window"
          :resizeIconSize="14"
          :isGuide="true"
          v-for="(item, index) of windows"
          :key="index"
          @resizeEndHandler="resizeWindow(item.window_id, $event)"
          @moveEndHandler="moveWindow(item.window_id, $event)"
          style="position: fixed"
        >
          <window
            @close_this_window="closeWindow"
            @close_other_windows="closeOtherWindows"
            @close_all_windows="closeAllWindows"
            @replace_this_window="repliceWindow"
            @top_window="topWindow"
            @lower_window="lowerWindow"
            @dbtouch="(evt) => windowDBClick(item.window_id)"
            @mute_unmute="mute_unmute"
            @start_polling="start_polling"
            @stop_polling="stop_polling"
            @edit_rect="editRect"
            :ref="'window_' + item.window_id"
            :id="'window_' + item.window_id"
            :uuid="item.uuid"
            :disable="plan_running"
            :mouse_area_flag="area_open_window_flag"
            :signal_source_table_uuid="item.signal_source_table_uuid"
            :window="item"
            :plan_running="plan_running"
            class="window fit"
          >
          </window>
        </vue3-resize-drag>
      </div>
      <div
        v-show="$store.state.power_state"
        ref="wall_grids"
        @touchstart="$store.commit('setSelectedWindow', '')"
      >
        <div
          v-for="row of wall_rows"
          :key="row"
          class="row"
          :style="{
            height: wall_height.value / $store.state.wall_row + 'px',
          }"
        >
          <div
            :ref="'item' + (row - 1) * wall_cols + col"
            v-for="col of wall_cols"
            :key="col"
            class="col wall_item wall_item_flag"
            :style="{
              width: wall_width / $store.state.wall_col + 'px',
              height: wall_height / $store.state.wall_row + 'px',
            }"
            :a_row="row"
            :a_col="col"
          >
            <q-popup-proxy context-menu @show="onContextMenuShow($event)">
              <q-list>
                <q-item
                  :disable="plan_running"
                  clickable
                  v-close-popup
                  @click="openWindowByLocalFile($event)"
                >
                  <q-item-section avatar>
                    <q-icon name="open_in_browser" />
                  </q-item-section>
                  <q-item-section> {{ $t("open window") }} </q-item-section>
                </q-item>
                <q-item
                  :disable="plan_running"
                  clickable
                  v-close-popup
                  @click="closeAllWindows"
                >
                  <q-item-section avatar>
                    <q-icon name="close" color="red" />
                  </q-item-section>
                  <q-item-section>
                    {{ $t("close all windows") }}
                  </q-item-section>
                </q-item>
              </q-list>
            </q-popup-proxy>
          </div>
        </div>
      </div>
    </div>
  </div>
  <file-manage-dialog ref="file_manage_dialog" />
  <window-rect-edit-dialog ref="window_rect_edit_dialog" />
</template>

<style scoped>
.wall_item {
  border: 1px solid gray;
}

.window {
  position: absolute;
}

.wall_item_flag {
}

.mouse_area_mask {
  background: #aacceec2;
  border: 1px solid #0069bee7;
}
</style>

<script lang="ts">
import {
  defineComponent,
  Ref,
  ref,
  onMounted,
  computed,
  watch,
  nextTick,
  onUpdated,
} from "vue";
import { useQuasar, dom as DomUtil } from "quasar";
import { useI18n } from "vue-i18n";
import { useStore } from "src/store";
const elementResizeDetectorMaker = require("element-resize-detector");

import vue3ResizeDrag from "../third_lib/vue3-resize-drag/components/vue3-resize-drag/index.vue";
import Window from "src/components/Window.vue";
import WindowRectEditDialog from "src/components/WindowRectEditDialog.vue";
import GlobalData from "src/common/GlobalData";
import FileEntity from "src/entities/FileEntity";
import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
import { Protocol } from "src/entities/WSProtocol";
import FileManageDialog from "src/components/FileManageDialog.vue";
import WindowOtherStateChangeNotifyEntity from "src/entities/WindowOtherStateChangeNotifyEntity";
import { WindowOpenNotifyEntity } from "src/entities/MultimediaWindowEntity";
import { NotifyMessage } from "src/common/ClientConnection";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import FileSuffixHelper from "src/common/FileSuffixHelper";

class Rect {
  start_x = 0;
  start_y = 0;
  end_x = 0;
  end_y = 0;

  reset() {
    this.start_x = 0;
    this.start_y = 0;
    this.end_x = 0;
    this.end_y = 0;
  }
}

export default defineComponent({
  name: "PadContentWallPage",
  components: {
    FileManageDialog,
    Window,
    vue3ResizeDrag,
    WindowRectEditDialog,
  },
  setup() {
    const $store = useStore();
    const $q = useQuasar();
    const $t = useI18n();

    const last_context_menu_pos_y = ref(0);
    const last_context_menu_pos_x = ref(0);

    const wall: Ref<any> = ref(null);
    const wall_content: Ref<any> = ref(null);
    const dom_windows: Ref<any> = ref(null);
    const window_rect_edit_dialog: Ref<any> = ref(null);

    const wall_content_client_width = ref(0);
    const wall_content_client_height = ref(0);

    const file_manage_dialog: Ref<any> = ref(null);

    const wall_width = ref(1);
    const wall_height = ref(1);

    const wall_rows = computed({
      get: () => $store.state.wall_row,
      set: (val) => $store.commit("setWallRow", val),
    });

    const wall_cols = computed({
      get: () => $store.state.wall_col,
      set: (val) => $store.commit("setWallCol", val),
    });

    const refresh_window_pos = () => {
      setTimeout(() => {
        wall_content_client_width.value = wall_content_client_width.value + 1;
        wall_content_client_width.value = wall_content_client_width.value - 1;
      }, 400);
    };

    // 全屏/非全屏转换时刷新窗口坐标
    watch(
      () => $q.fullscreen.isActive,
      () => refresh_window_pos()
    );

    // 全屏旋转时刷新窗口坐标
    watch(
      () => $store.state.landspace,
      () => $q.fullscreen.isActive && refresh_window_pos()
    );

    const plan_running = computed(
      () => $store.state.current_running_plan.trim() != ""
    );

    const windows = computed({
      get: () => $store.state.windows,
      set: (val) => $store.commit("setWindows", val),
    });

    const area_open_window_flag = ref(false);
    const area_open_window_rect = ref(new Rect());

    EventBus.getInstance().on(
      EventNamesDefine.DocumentBodyClick,
      (evt: PointerEvent) => {
        if (wall.value) {
          let flag = false;
          {
            let item: HTMLElement | null = evt.srcElement as HTMLElement;
            while (item) {
              if (item == wall.value) {
                flag = true;
                break;
              }
              item = item.parentElement;
            }
          }
          if (!flag) {
            $store.commit("setSelectedWindow", "");
          }
        }
      }
    );

    const __temp__size_a__ = 0.00000001;

    EventBus.getInstance().on(
      EventNamesDefine.NotifyMessage,
      (notify: NotifyMessage) => {
        try {
          switch (notify.packet.command) {
            case Protocol.Commands.kCloseWindow:
              {
                const temp = JSON.parse(notify.data);
                if (temp && temp.window_id) {
                  if (temp.window_id << 0 == -1) {
                    $store.commit("cleanWindows", {
                      window_id: temp.window_id,
                    });
                  } else {
                    $store.commit("removeWindow", {
                      window_id: temp.window_id,
                    });
                  }
                }
              }
              break;
            case Protocol.Commands.kMoveWindow:
              {
                const temp = JSON.parse(notify.data);
                if (temp && temp.window_id) {
                  const window = $store.state.windows.find(
                    (item) => item.window_id == temp.window_id
                  );
                  if (window) {
                    // 先设置一个坐标让数据变动,然后再设置新数据，保证坐标正常刷新
                    $store.commit("setWindowPropertys", [
                      {
                        window,
                        property_name: "x",
                        value: (temp.x ?? 0) + __temp__size_a__,
                      },
                      {
                        window,
                        property_name: "y",
                        value: (temp.y ?? 0) + __temp__size_a__,
                      },
                    ]);

                    setTimeout(() => {
                      $store.commit("setWindowPropertys", [
                        {
                          window,
                          property_name: "x",
                          value: temp.x ?? 0,
                        },
                        {
                          window,
                          property_name: "y",
                          value: temp.y ?? 0,
                        },
                      ]);
                    }, 0);
                  }
                }
              }
              break;
            case Protocol.Commands.kResizeWindow:
              {
                const temp = JSON.parse(notify.data);
                if (temp && temp.window_id) {
                  const window = $store.state.windows.find(
                    (item) => item.window_id == temp.window_id
                  );
                  if (window) {
                    $store.commit("setWindowPropertys", [
                      {
                        window,
                        property_name: "width",
                        value: (temp.width ?? 0) + __temp__size_a__,
                      },
                      {
                        window,
                        property_name: "height",
                        value: (temp.width ?? 0) + __temp__size_a__,
                      },
                    ]);

                    setTimeout(() => {
                      $store.commit("setWindowPropertys", [
                        {
                          window,
                          property_name: "width",
                          value: temp.width ?? 0,
                        },
                        {
                          window,
                          property_name: "height",
                          value: temp.height ?? 0,
                        },
                      ]);
                    }, 0);
                  }
                }
              }
              break;
            case Protocol.Commands.kOpenWindow:
              {
                const temp = JSON.parse(notify.data) as WindowOpenNotifyEntity;
                if (temp) {
                  $store.commit("pushWindow", temp);
                }
              }
              break;
            case Protocol.Commands.kWindowOtherStateChanged:
              {
                const temp = JSON.parse(
                  notify.data
                ) as WindowOtherStateChangeNotifyEntity;
                if (temp && temp.window_id) {
                  const window = $store.state.windows.find(
                    (item) => item.window_id == temp.window_id
                  );
                  if (window) {
                    $store.commit("setWindowPropertys", [
                      {
                        window,
                        property_name: "paused",
                        value: temp.paused,
                      },
                      {
                        window,
                        property_name: "muted",
                        value: temp.muted,
                      },
                      {
                        window,
                        property_name: "volume",
                        value: temp.volume,
                      },
                      {
                        window,
                        property_name: "volume",
                        value: temp.volume,
                      },
                      {
                        window,
                        property_name: "polling",
                        value: temp.polling,
                      },
                      {
                        window,
                        property_name: "polling_title",
                        value: temp.title,
                      },
                      {
                        window,
                        property_name: "polling_window_type",
                        value: temp.window_type,
                      },
                    ]);
                  }
                }
              }
              break;
            case Protocol.Commands.kTopWindow:
              {
                const temp = JSON.parse(
                  notify.data
                ) as Protocol.TopWindowNotifyEntity;
                if (temp) {
                  for (const window of $store.state.windows) {
                    if (window && window.window_id != temp.new_window_id) {
                      $store.commit("setWindowProperty", {
                        window,
                        property_name: "focus",
                        value: false,
                      });
                    }
                  }
                  const window = $store.state.windows.find(
                    (item) => item.window_id == temp.new_window_id
                  );
                  $store.commit("setWindowProperty", {
                    window,
                    property_name: "focus",
                    value: true,
                  });
                  $store.commit("topWindow", temp.new_window_id);
                }
              }
              break;
            case Protocol.Commands.kLowerWindow:
              {
                const temp = JSON.parse(
                  notify.data
                ) as Protocol.LowerWindowNotifyEntity;
                if (temp) {
                  $store.commit("lowerWindow", temp.window_id);
                }
              }
              break;
          }
        } catch {}
      }
    );

    onMounted(() => {
      if (wall.value && wall.value.parentElement) {
        const wall_parent = wall.value.parentElement as HTMLElement;

        elementResizeDetectorMaker().listenTo(
          wall_parent,
          (element: HTMLElement) => {
            if (element) {
              let height = wall_parent.offsetHeight * 0.9;
              let width = height / 0.56;

              if (width > element.offsetWidth) {
                width = element.offsetWidth * 0.9;
                height = width * 0.56;
              }

              if (height < 1) {
                height = 1;
              }
              if (width < 1) {
                width = 1;
              }

              wall_height.value = parseInt(height.toFixed(0));
              wall_width.value = parseInt(width.toFixed(0));
            }
          }
        );
      } else {
        console.error("dom error");
        console.error((wall.value as HTMLElement).parentElement);
      }

      if (wall.value && wall.value.parentElement) {
        elementResizeDetectorMaker().listenTo(
          wall_content.value,
          (element: HTMLElement) => {
            if (element) {
              wall_content_client_height.value = DomUtil.height(element);
              wall_content_client_width.value = DomUtil.width(element);
            }
          }
        );
      } else {
        console.error("dom error");
        console.error((wall.value as HTMLElement).parentElement);
      }
    });

    interface __Rect {
      width: number;
      height: number;
      x: number;
      y: number;
      left: number;
      top: number;
    }

    const moveWindow = (window_id: number, rect: __Rect) => {
      rect.x = rect.x ?? 0;
      rect.y = rect.y ?? 0;
      if (wall.value) {
        const x =
          rect.left -
          (wall.value.parentElement?.offsetLeft ?? 0) -
          wall_content.value.offsetLeft;
        const y =
          rect.top -
          (wall.value.parentElement?.offsetTop ?? 0) -
          wall_content.value.offsetTop;
        GlobalData.getInstance()
          .getCurrentClient()
          ?.moveWindow(
            window_id,
            x / wall_content.value.clientWidth,
            y / wall_content.value.clientHeight
          );
      }
    };

    const resizeWindow = (window_id: number, rect: __Rect) => {
      rect.width = rect.width ?? 0;
      rect.height = rect.height ?? 0;
      rect.left = rect.left ?? 0;
      rect.top = rect.top ?? 0;
      // moveWindow(window_id, evt);
      if (wall.value) {
        // GlobalData.getInstance()
        //   .getCurrentClient()
        //   ?.resizeWindow(
        //     window_id,
        //     evt.width / wall.value.clientWidth,
        //     evt.height / wall.value.clientHeight
        //   );
        const x =
          rect.left -
          (wall.value.parentElement?.offsetLeft ?? 0) -
          wall_content.value.offsetLeft;
        const y =
          rect.top -
          (wall.value.parentElement?.offsetTop ?? 0) -
          wall_content.value.offsetTop;
        GlobalData.getInstance()
          .getCurrentClient()
          ?.setWindowGeometry(
            window_id,
            x / wall_content.value.clientWidth,
            y / wall_content.value.clientHeight,
            rect.width / wall_content.value.clientWidth,
            rect.height / wall_content.value.clientHeight
          );
      }
    };

    const find_parent_dom = (dom: HTMLElement, classess: string[]) => {
      let parent: HTMLElement | null = dom;
      while (parent) {
        if (parent) {
          for (const clazz of classess) {
            if (clazz) {
              if (parent.classList.contains(clazz)) {
                return parent;
              }
            }
          }
          parent = parent.parentElement;
        } else {
          break;
        }
      }
      return parent;
    };

    interface _IDropToWall {
      data: any;
      type: string;
      pos: {
        x: number;
        y: number;
      };
    }

    const onDropSignalSourceOrPolliong = (evt: _IDropToWall) => {
      if (!plan_running.value) {
        if (evt && evt.data) {
          let dom_element = document.elementFromPoint(
            evt.pos.x,
            evt.pos.y
          ) as HTMLElement;

          const signal_sources = GlobalData.getInstance().signal_source.filter(
            (item) => (item as any)?.uuid == evt.data.uuid
          );

          // 有可能是窗口的子节点收到了拖拽信息，需要找到真正的窗口节点来判断
          if (dom_element) {
            const temp = find_parent_dom(dom_element, [
              "wall_item_flag",
              "window_flag",
            ]);
            if (temp) {
              dom_element = temp;
            }
          }

          if (dom_element) {
            if (dom_element.classList.contains("wall_item_flag")) {
              // 开窗
              const cell_width = 1 / $store.state.wall_col;
              const cell_height = 1 / $store.state.wall_row;

              let col = 0;
              let row = 0;

              try {
                col = parseInt(dom_element.getAttribute("a_col") ?? "1") - 1;
                row = parseInt(dom_element.getAttribute("a_row") ?? "1") - 1;
                if (isNaN(row)) {
                  row = 0;
                }
                if (isNaN(col)) {
                  col = 0;
                }
              } catch {}

              const x = col * cell_width;
              const y = row * cell_height;
              const width = cell_width;
              const height = cell_height;

              switch (evt.type) {
                case "polling":
                  GlobalData.getInstance()
                    .getCurrentClient()
                    ?.openPolling(
                      new Protocol.OpenPollingRequestEntity(
                        evt.data.uuid,
                        x,
                        y,
                        width,
                        height
                      )
                    );
                  break;
                case "signal_source" /**OpenPollingRequestEntity */:
                  if (signal_sources.length) {
                    const signal_source = signal_sources[0];
                    if (signal_source) {
                      GlobalData.getInstance()
                        .getCurrentClient()
                        ?.openWindow(
                          new Protocol.OpenWindowRequestEntity(
                            signal_source.uuid,
                            x,
                            y,
                            width,
                            height
                          )
                        );
                    }
                  }
                  break;
              }
            } else if (dom_element.classList.contains("window_flag")) {
              // 拖拽信号源替换窗口 后面还有一处替换窗口
              const rep_uuid = dom_element.getAttribute("uuid");
              if (rep_uuid) {
                let window = $store.state.windows.find(
                  (item) => item.uuid == rep_uuid
                );
                if (window) {
                  let client = GlobalData.getInstance().getCurrentClient();
                  if (client) {
                    let x = window.x;
                    let y = window.y;
                    let width = window.width;
                    let height = window.height;

                    setTimeout(() => {
                      if (!window) {
                        return;
                      }
                      switch (evt.type) {
                        case "polling":
                          {
                            client?.replaceWindow2(
                              window.window_id,
                              evt.data.uuid,
                              true
                            );
                          }

                          break;
                        case "signal_source":
                          {
                            if (signal_sources.length) {
                              const signal_source = signal_sources[0];
                              if (signal_source) {
                                client?.replaceWindow2(
                                  window.window_id,
                                  signal_source.uuid
                                );
                              }
                            }
                          }
                          break;
                      }
                    }, 50);
                  }
                }
              }
            }
          }
        }
      } else {
        $q.notify({
          type: "warning",
          message: $t.t("plan running! can't open window!"),
          position: "top",
          timeout: 1500,
        });
      }
    };

    EventBus.getInstance().on(
      EventNamesDefine.DropToWall,
      (evt: _IDropToWall) => {
        if (!$store.state.power_state) {
          return;
        }
        if (evt && evt.data) {
          switch (evt.type) {
            case "signal_source":
            case "polling":
              onDropSignalSourceOrPolliong(evt);
              break;
            case "mode":
              try {
                if ($store.state.current_running_plan.trim() == "") {
                  GlobalData.getInstance()
                    .getCurrentClient()
                    ?.callMode(evt.data.uuid);
                  $q.notify({
                    color: "positive",
                    icon: "done",
                    message:
                      $t.t("call mode directives send") + $t.t("success") + "!",
                    position: "top",
                    timeout: 1500,
                  });
                } else {
                  $q.notify({
                    type: "warning",
                    message: $t.t("plan running! can't call mode!"),
                    position: "top",
                    timeout: 1500,
                  });
                }
              } catch {}
              break;
            case "plan":
              try {
                GlobalData.getInstance()
                  .getCurrentClient()
                  ?.runPlan(evt.data.uuid);
                $q.notify({
                  color: "positive",
                  icon: "done",
                  message:
                    $t.t("run plan directives send") + $t.t("success") + "!",
                  position: "top",
                  timeout: 1500,
                });
              } catch {}
              break;
          }
        }
      }
    );

    return {
      wall,
      window_rect_edit_dialog,
      file_manage_dialog,
      wall_width,
      wall_height,
      wall_rows,
      wall_cols,
      plan_running,
      area_open_window_flag,
      area_open_window_rect,
      last_context_menu_pos_x,
      last_context_menu_pos_y,
      windows,
      wall_content,
      dom_windows,
      wall_content_client_width,
      wall_content_client_height,

      // functions
      moveWindow,
      resizeWindow,
      loga(a: any) {
        console.log(a);
      },
      mute_unmute(window_id: number) {
        const window = $store.state.windows.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          if (window.muted) {
            GlobalData.getInstance()
              .getCurrentClient()
              ?.unmuteWindow(window_id);
          } else {
            GlobalData.getInstance().getCurrentClient()?.muteWindow(window_id);
          }
        }
      },
      start_polling(window_id: number) {
        const window = $store.state.windows.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          GlobalData.getInstance().getCurrentClient()?.startPolling(window_id);
        }
      },
      stop_polling(window_id: number) {
        const window = $store.state.windows.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          GlobalData.getInstance().getCurrentClient()?.stopPolling(window_id);
        }
      },
      async editRect(window_id: number) {
        if (window_rect_edit_dialog.value) {
          window_rect_edit_dialog.value.showDialog(window_id);
        }
      },
      topWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.focusIn(window_id);
      },
      lowerWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.lowerWindow(window_id);
      },
      windowDBClick(window_id: number) {
        if (plan_running.value) {
          return;
        }
        GlobalData.getInstance().getCurrentClient()?.windowFitGrid(window_id);
      },
      closeOtherWindows(window_id: number) {
        for (const window of $store.state.windows) {
          if (window && window.window_id != window_id) {
            GlobalData.getInstance()
              .getCurrentClient()
              ?.closeWindow(window.window_id);
          }
        }
      },
      closeWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.closeWindow(window_id);
      },
      closeAllWindows() {
        GlobalData.getInstance().getCurrentClient()?.closeWindow(-1);
      },
      async repliceWindow(window_id: number) {
        // 选择信号源替换窗口,上面还有一处拖拽信号源替换
        if (!wall.value) {
          return;
        }
        const old_window = $store.state.windows.find(
          (element) => element && element.window_id == window_id
        );
        if (old_window) {
          const old_signal_source = GlobalData.getInstance().signal_source.find(
            (element) =>
              element && element.uuid == old_window.signal_source_table_uuid
          );
          if (old_signal_source) {
            const obj = await file_manage_dialog.value.showDialogAsync(
              "select",
              false,
              true,
              true
            );
            if (obj) {
              interface __I {
                path: string;
                file: FileEntity;
              }
              let { path, file }: __I = obj;
              if (path && file) {
                const full_path = (path + "/" + file.name).replace(/\\/g, "/");
                const entity: SignalSourceEntity = new SignalSourceEntity();
                if (
                  file.name.endsWith("mp4") ||
                  file.name.endsWith("avi") ||
                  file.name.endsWith("ts") ||
                  file.name.endsWith("webm") ||
                  file.name.endsWith("flv") ||
                  file.name.endsWith("mkv")
                ) {
                  entity.window_type = "EwindowType::Multimedia";
                  entity.media_url = JSON.stringify([full_path]);
                } else {
                  entity.window_type = "EwindowType::Image";
                  entity.media_url = full_path;
                }
                entity.name = file.name;
                entity.local_file_flag = true;
                entity.group_uuid = "";
                try {
                  const response = await GlobalData.getInstance()
                    .getCurrentClient()
                    ?.addSignalSource(entity);
                  if (response && response.success) {
                    const open_window_request =
                      new Protocol.OpenWindowRequestEntity(
                        response.uuid,
                        old_window.x,
                        old_window.y,
                        old_window.width,
                        old_window.height
                      );

                    open_window_request.muted = old_window.muted;
                    open_window_request.volume = old_window.volume;
                    open_window_request.paused = old_window.paused;
                    open_window_request.play_speed = old_window.play_speed;

                    GlobalData.getInstance()
                      .getCurrentClient()
                      ?.closeWindow(old_window.window_id);

                    GlobalData.getInstance()
                      .getCurrentClient()
                      ?.openWindow(open_window_request);
                  }
                } catch {}
              }
            }
          }
        }
      },
      onContextMenuShow(event: TouchEvent) {
        if (event && event.changedTouches && event.changedTouches.length) {
          last_context_menu_pos_x.value = event.changedTouches[0].pageX;
          last_context_menu_pos_y.value = event.changedTouches[0].pageY;
        }
      },
      async openWindowByLocalFile(event: MouseEvent) {
        if (!wall.value) {
          return;
        }

        // 异步请求后获取不到 dom 节点数据,所以在异步请求之前先计算出目标窗口的x,y,w,h
        const target_rect = {
          x: 0,
          y: 0,
          w: 0,
          h: 0,
        };

        {
          const cell_width = 1.0 / $store.state.wall_col;
          const cell_height = 1.0 / $store.state.wall_row;

          const col = Math.floor(
            (last_context_menu_pos_x.value -
              (wall.value.parentElement?.offsetLeft ?? 0) -
              wall_content.value.offsetLeft) /
              wall_content.value.offsetWidth /
              cell_width
          );
          const row = Math.floor(
            (last_context_menu_pos_y.value -
              (wall.value.parentElement?.offsetTop ?? 0) -
              wall_content.value.offsetTop) /
              wall_content.value.offsetHeight /
              cell_height
          );

          target_rect.x = col * cell_width;
          target_rect.y = row * cell_height;
          target_rect.w = cell_width;
          target_rect.h = cell_height;
        }

        const obj = await file_manage_dialog.value.showDialogAsync(
          "select",
          false,
          true.valueOf,
          true
        );

        if (obj) {
          interface __I {
            path: string;
            file: FileEntity;
          }
          let { path, file }: __I = obj;
          if (path && file) {
            const full_path = (path + "/" + file.name).replace(/\\/g, "/");
            const entity: SignalSourceEntity = new SignalSourceEntity();
            if (
              file.name.endsWith("mp4") ||
              file.name.endsWith("avi") ||
              file.name.endsWith("ts") ||
              file.name.endsWith("webm") ||
              file.name.endsWith("flv") ||
              file.name.endsWith("mkv")
            ) {
              entity.window_type = "EwindowType::Multimedia";
              entity.media_url = JSON.stringify([full_path]);
            } else {
              entity.window_type = "EwindowType::Image";
              entity.media_url = full_path;
            }
            entity.name = file.name;
            entity.local_file_flag = true;
            entity.group_uuid = "";
            try {
              const response = await GlobalData.getInstance()
                .getCurrentClient()
                ?.addSignalSource(entity);

              if (response && response.success) {
                if (
                  target_rect &&
                  !isNaN(target_rect.x) &&
                  !isNaN(target_rect.y) &&
                  !isNaN(target_rect.w) &&
                  !isNaN(target_rect.h)
                ) {
                  const open_window_request =
                    new Protocol.OpenWindowRequestEntity(
                      response.uuid,
                      target_rect.x,
                      target_rect.y,
                      target_rect.w,
                      target_rect.h
                    );
                  GlobalData.getInstance()
                    .getCurrentClient()
                    ?.openWindow(open_window_request);
                }
              }
            } catch {}
          }
        }
      },
    };
  },
});
</script>
