<template>
  <div
    ref="wall"
    class="fit items-center justify-evenly"
    :class="$store.state.power_state ? 'wall' : ''"
    @dragenter="onDragEnter"
    @dragleave="onDragLeave"
    @dragover="onDragOver"
    @drop="onDrop"
    style="background-color: #bce0f0; margin-bottom: 10%"
  >
    <div
      id="windows"
      style="position: absolute"
      v-if="$store.state.power_state && show_windows_flag"
    >
      <vue3-resize-drag
        :w="item.width * ($refs.wall?.offsetWidth ?? 0)"
        :h="item.height * ($refs.wall?.offsetHeight ?? 0)"
        :x="
          ($refs.wall?.parentElement?.offsetLeft ?? 0) +
          ($refs.wall?.offsetLeft ?? 0) +
          item.x * ($refs.wall?.offsetWidth ?? 0)
        "
        :y="
          ($refs.wall?.parentElement?.offsetTop ?? 0) +
          ($refs.wall?.offsetTop ?? 0) +
          item.y * ($refs.wall?.offsetHeight ?? 0)
        "
        :zIndex="
          $store.state.windows_sort.findIndex(
            (element) => element == item.uuid
          ) + 1
        "
        :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"
          @dblclick="(evt) => windowDBClick(item.window_id)"
          @edit_volume="edit_volume"
          @mute_unmute="mute_unmute"
          @start_polling="start_polling"
          @stop_polling="stop_polling"
          @polling_setting="polling_setting"
          @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"
          :show_pollong_setting_context_menu="true"
          class="window fit"
        >
        </window>
      </vue3-resize-drag>
    </div>
    <div
      id="magic_wall_grids"
      ref="magic_wall_grids"
      @click="onWallGridsClick"
      v-if="
        $store.state.power_state &&
        $store.state.custom_defines.function_magic_wall
      "
    >
      <div class="row magic_wall_grids" style="height: 31.05vw; width: 55.2vw">
        <vue3-resize-drag
          v-for="(item, index) of $store.state.show_monitor_list"
          :w="item.w * $refs.wall?.clientWidth"
          :h="item.h * $refs.wall?.clientHeight"
          :x="item.currentx * $refs.wall?.clientWidth"
          :y="item.currenty * $refs.wall?.clientHeight"
          :rotate="parseInt(item.angle.toString())"
          :is-resizable="false"
          :isGuide="false"
          class="magic_wall"
          @dragenter="magic_select(index, item, $event)"
          style="text-align: center"
        >
          {{ item.id + 1 }}
        </vue3-resize-drag>

        <q-popup-proxy
          context-menu
          @show="
            {
              last_context_menu_pos_x = $event.layerX;
              last_context_menu_pos_y = $event.layerY;
            }
          "
        >
          <q-list>
            <q-item
              :disable="plan_running || !$store.state.power_state"
              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 || !$store.state.power_state"
              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
      id="wall_grids"
      ref="wall_grids"
      @click="onWallGridsClick"
      v-if="
        $store.state.power_state &&
        !$store.state.custom_defines.function_magic_wall
      "
    >
      <div
        v-for="row of wall_rows"
        :key="row"
        class="row"
        :style="{
          height: item_height + '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: item_witdh + 'px',
            height: item_height + 'px',
          }"
          :a_row="row"
          :a_col="col"
        >
          <q-popup-proxy
            context-menu
            @show="
              {
                last_context_menu_pos_x = $event.layerX;
                last_context_menu_pos_y = $event.layerY;
              }
            "
          >
            <q-list>
              <q-item
                :disable="plan_running || !$store.state.power_state"
                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 || !$store.state.power_state"
                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
    class="mouse_area_mask"
    v-show="area_open_window_flag"
    style="position: fixed; pointer-events: none; z-index: 999"
    :style="{
      left:
        Math.min(area_open_window_rect.start_x, area_open_window_rect.end_x) +
        'px',
      top:
        Math.min(area_open_window_rect.start_y, area_open_window_rect.end_y) +
        'px',
      width:
        Math.abs(area_open_window_rect.end_x - area_open_window_rect.start_x) +
        'px',
      height:
        Math.abs(area_open_window_rect.end_y - area_open_window_rect.start_y) +
        'px',
    }"
  ></div>
  <edit-volume-dialog ref="edit_volume_dialog" />
  <polling-setting-dialog ref="polling_setting_dialog" />
  <file-manage-dialog ref="file_manage_dialog" />
  <window-rect-edit-dialog ref="window_rect_edit_dialog" />
</template>

<style scoped>
.wall {
  border: 1px solid black;
}

.wall_item {
  border: 1px solid gray;
}

.window {
  position: absolute;
}

.wall_item_flag {
}

.mouse_area_mask {
  background: #aacceec2;
  border: 1px solid #0069bee7;
}
.magic_wall {
  border: 1px solid black;
  background-color: rgb(50,130,246);
  position: absolute;
}
.magic_wall_select {
  border: 1px dashed black;
}
.magic_wall_grids {
}
</style>

<script lang="ts">
import GlobalData from "src/common/GlobalData";
import { defineComponent, ref, Ref, computed, onMounted, nextTick } from "vue";
const elementResizeDetectorMaker = require("element-resize-detector");
import { Protocol } from "src/entities/WSProtocol";
import Window from "src/components/Window.vue";
import WindowRectEditDialog from "src/components/WindowRectEditDialog.vue";

import { useI18n } from "vue-i18n";
import { NullSignalSource, useStore } from "src/store";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { WindowOpenNotifyEntity } from "src/entities/MultimediaWindowEntity";
import WindowOtherStateChangeNotifyEntity from "src/entities/WindowOtherStateChangeNotifyEntity";
import { extend, useQuasar } from "quasar";
import { NotifyMessage } from "src/common/ClientConnection";

import EditVolumeDialog from "src/components/EditVolumeDialog.vue";
import PollingSettingDialog from "src/components/PollingSettingDialog.vue";

import vue3ResizeDrag from "../third_lib/vue3-resize-drag/components/vue3-resize-drag/index.vue";

import FileManageDialog from "src/components/FileManageDialog.vue";
import FileEntity from "src/entities/FileEntity";
import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
import FileSuffixHelper from "src/common/FileSuffixHelper";
import { SpecialVideoHelper } from "src/common/SpecialVideoHelper";
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;
  }
}
class test_monitor {
  w = 0.0;
  h = 0.0;
  currentx = 0.0;
  currenty = 0.0;
  centerx = 0.0;
  centery = 0.0;
  angle = 0;
  id = 0;
  constructor(id: number, w: number, h: number) {
    this.currentx = 0.0;
    this.currenty = 0.0;
    this.angle = 0;
    this.centerx = 0;
    this.centery = 0;
    this.id = id;
    this.w = w;
    this.h = h;
  }
}

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

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

    const show_windows_flag = ref(true); // 用于刷新 window 坐标
    const refresh_windows_pos = async () => {
      // 浏览器窗口大小调整时, 重新显示隐藏虚拟窗口来刷新虚拟窗口坐标
      show_windows_flag.value = false;
      setTimeout(() => {
        nextTick(() => {
          show_windows_flag.value = true;
        });
        if (wall.value) {
          let teph = wall.value?.clientHeight / offsetHeight;
          let tepw = wall.value?.clientWidth / offsetWidth;
        }
      }, 100);
    };

    EventBus.getInstance().on(
      EventNamesDefine.WindowResize,
      refresh_windows_pos
    );

    const last_context_menu_pos_x = ref(0);
    const last_context_menu_pos_y = ref(0);
    let offsetHeight = 0;
    let offsetWidth = 0;
    const plan_running = computed(
      () => $store.state.current_running_plan.trim() != ""
    );

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

    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 wall: Ref<HTMLElement | null> = ref(null);

    const area_open_window_flag = ref(false);
    const area_open_window_rect = ref(new Rect());
    let item_witdh = ref(0);
    const item_height = ref(0);
    const radians = () => {
      const test_monitor_list: any = clacMonitor();
      if (test_monitor_list) {
        const item = test_monitor_list[current_index.value];
        return /*a*/ (item.angle * Math.PI) / 180;
      }
    };
    const calculateCoordinates = (
      px: number,
      py: number,
      cx: number,
      cy: number
    ) => {
      const x =
        cx +
        (px - cx) * Math.cos(Number(radians())) -
        (py - cy) * Math.sin(Number(radians()));

      const y =
        cy +
        (px - cx) * Math.sin(Number(radians())) +
        (py - cy) * Math.cos(Number(radians()));

      return { x, y };
    };
    let current_index = ref(0);
    const clacMonitor = () => {
      let test_monitor_list: any = [];
      $store.state.show_monitor_list.forEach((element) => {
        let item: test_monitor = new test_monitor(0, 0, 0);
        const wall_dom = wall.value;
        if (wall_dom) {
          item.h = element.h * wall_dom.clientHeight;
          item.w = element.w * wall_dom.clientWidth;
          item.currentx = element.currentx * wall_dom.clientWidth;
          item.currenty = element.currenty * wall_dom.clientHeight;
          item.centerx = item.currentx + item.w * 0.5;
          item.centery = item.currenty + item.h * 0.5;
          item.angle = element.angle;
          item.id = element.id;
          test_monitor_list.push(item);
        }
      });
      return test_monitor_list;
    };
    const four_point = () => {
      const test_monitor_list: any = clacMonitor();
      if (test_monitor_list) {
        const item = test_monitor_list[current_index.value];
        item.centerx = parseInt(item.centerx.toString());
        item.centery = parseInt(item.centery.toString());
        const x2: number = item.currentx + item.w;
        const y2: number = item.currenty + item.h;
        if (item.angle != 0) {
          const point_left_top = calculateCoordinates(
            item.currentx,
            item.currenty,
            item.centerx,
            item.centery
          );
          const point_left_bootom = calculateCoordinates(
            item.currentx,
            y2,
            item.centerx,
            item.centery
          );
          const point_right_top = calculateCoordinates(
            x2,
            item.currenty,
            item.centerx,
            item.centery
          );
          const point_right_bottom = calculateCoordinates(
            x2,
            y2,
            item.centerx,
            item.centery
          );
          const point_list = [
            point_left_top,
            point_left_bootom,
            point_right_top,
            point_right_bottom,
          ];

          return point_list;
        }
      }
    };
    const select_x = () => {
      const point_list = four_point();
      const item = $store.state.show_monitor_list[current_index.value];
      if (item.angle != 0) {
        if (point_list) {
          let minx = 100000;
          point_list.forEach((element) => {
            if (minx > element.x) {
              minx = element.x;
            }
          });
          return minx;
        }
      } else {
        if (wall.value) return item.currentx * wall.value?.clientWidth;
      }
    };
    const select_y = () => {
      const point_list = four_point();
      let miny = 100000;
      if (point_list) {
        point_list.forEach((element) => {
          if (miny > element.y) {
            miny = element.y;
          }
        });
      }
      const item = $store.state.show_monitor_list[current_index.value];
      if (item.angle != 0) {
        return miny;
      } else {
        if (wall.value) return item.currenty * wall.value?.clientHeight;
      }
    };
    const select_height = () => {
      const point_list = four_point();
      let maxy = 0;
      let miny = 100000;
      if (point_list) {
        point_list.forEach((element) => {
          if (miny > element.y) {
            miny = element.y;
          }
          if (maxy < element.y) {
            maxy = element.y;
          }
        });
      }
      const item = $store.state.show_monitor_list[current_index.value];
      if (item.angle != 0) {
        return maxy - miny;
      } else {
        if (wall.value) return item.h * wall.value?.clientHeight;
      }
    };

    const select_width = () => {
      const point_list = four_point();
      let maxx = 0;
      let minx = 100000;
      if (point_list) {
        point_list.forEach((element) => {
          if (minx > element.x) {
            minx = element.x;
          }
          if (maxx < element.x) {
            maxx = element.x;
          }
        });
      }
      const item = $store.state.show_monitor_list[current_index.value];
      if (item.angle != 0) {
        return maxx - minx;
      } else {
        if (wall.value) return item.w * wall.value?.clientWidth;
      }
    };
    const calcWallItemWH = () => {
      item_witdh.value = Math.floor(
        (wall?.value?.parentElement?.offsetWidth ?? 0) / wall_cols.value
      );
      if (wall.value && wall.value.parentElement) {
        if ($store.state.isSpecialVideo()) {
          const screen_info = SpecialVideoHelper.getScreenInfo(
            wall_cols.value,
            wall_rows.value
          );

          const wv_scaler = screen_info.unit_width / screen_info.unit_height;
          item_height.value =
            wall.value.parentElement.offsetWidth /
            wv_scaler /
            screen_info.desktop_col;

          if (screen_info.screen_rows > screen_info.screen_cols) {
            item_height.value = item_height.value * 0.7;
          }
        } else {
          const wv_scaler =
            /*$store.state.device_screen_width / $store.state.device_screen_height*/ 1920 /
            1080;
          item_height.value =
            wall.value.parentElement.offsetWidth / wv_scaler / wall_rows.value;
        }
        if (wall_rows.value > wall_cols.value) {
          item_height.value *= 0.85;
        }
      } else {
        item_height.value = 0;
      }

      item_witdh.value =
        Math.ceil(item_witdh.value - wall_cols.value) & ~wall_cols.value;
      item_height.value =
        Math.ceil(item_height.value - wall_rows.value) & ~wall_rows.value;
    };

    const wallMouseDown = (evt: MouseEvent) => {
      if (plan_running.value) {
        return;
      }
      if ((evt.ctrlKey || evt.shiftKey || evt.altKey) && wall.value) {
        let left =
          wall.value.offsetLeft + (wall.value.parentElement?.offsetLeft ?? 0);
        let top =
          wall.value.offsetTop + (wall.value.parentElement?.offsetTop ?? 0);

        if (
          left <= evt.clientX &&
          top <= evt.clientY &&
          left + wall.value.offsetWidth >= evt.clientX &&
          top + wall.value.offsetHeight >= evt.clientY
        ) {
          area_open_window_rect.value.start_x = evt.clientX;
          area_open_window_rect.value.start_y = evt.clientY;
          area_open_window_rect.value.end_x = evt.clientX;
          area_open_window_rect.value.end_y = evt.clientY;
          area_open_window_flag.value = true;
          evt.stopPropagation();
        }
      }
    };

    const wallMouseUp = (evt: MouseEvent) => {
      if (area_open_window_flag.value && wall.value) {
        evt.stopPropagation();
        // 大小为0 不开窗
        if (
          area_open_window_rect.value.start_x !=
            area_open_window_rect.value.end_x &&
          area_open_window_rect.value.start_y !=
            area_open_window_rect.value.end_y
        ) {
          // 开窗
          let left =
            wall.value.offsetLeft + (wall.value.parentElement?.offsetLeft ?? 0);
          let top =
            wall.value.offsetTop + (wall.value.parentElement?.offsetTop ?? 0);
          let start_x =
            Math.min(
              area_open_window_rect.value.start_x,
              area_open_window_rect.value.end_x
            ) - left;
          let start_y =
            Math.min(
              area_open_window_rect.value.start_y,
              area_open_window_rect.value.end_y
            ) - top;
          let end_x = Math.abs(
            area_open_window_rect.value.end_x -
              area_open_window_rect.value.start_x
          );
          let end_y = Math.abs(
            area_open_window_rect.value.end_y -
              area_open_window_rect.value.start_y
          );

          if ($store.state.current_left_tab == "signal_source") {
            if ($store.state.selected_signal_source != NullSignalSource) {
              GlobalData.getInstance()
                .getCurrentClient()
                ?.openWindow(
                  new Protocol.OpenWindowRequestEntity(
                    $store.state.selected_signal_source,
                    start_x / wall.value.offsetWidth,
                    start_y / wall.value.offsetHeight,
                    end_x / wall.value.offsetWidth,
                    end_y / wall.value.offsetHeight
                  )
                );
            }
          } else {
            if ($store.state.selected_polling != NullSignalSource) {
              GlobalData.getInstance()
                .getCurrentClient()
                ?.openPolling(
                  new Protocol.OpenPollingRequestEntity(
                    $store.state.selected_polling,
                    start_x / wall.value.offsetWidth,
                    start_y / wall.value.offsetHeight,
                    end_x / wall.value.offsetWidth,
                    end_y / wall.value.offsetHeight
                  )
                );
            }
          }
          //开窗
        }
      }
      area_open_window_flag.value = false;
      area_open_window_rect.value.reset();
    };

    const wallMouseMove = (evt: MouseEvent) => {
      if (area_open_window_flag.value) {
        evt.stopPropagation();
        if (wall.value) {
          let left =
            wall.value.offsetLeft + (wall.value.parentElement?.offsetLeft ?? 0);
          let top =
            wall.value.offsetTop + (wall.value.parentElement?.offsetTop ?? 0);
          let right = left + wall.value.offsetWidth;
          let bottom = top + wall.value.offsetHeight;
          if (evt.clientX < left) {
            area_open_window_rect.value.end_x = left;
          } else if (evt.clientX > right) {
            area_open_window_rect.value.end_x = right;
          } else {
            area_open_window_rect.value.end_x = evt.clientX;
          }

          if (evt.clientY < top) {
            area_open_window_rect.value.end_y = top;
          } else if (evt.clientY > bottom) {
            area_open_window_rect.value.end_y = bottom;
          } else {
            area_open_window_rect.value.end_y = evt.clientY;
          }
        }
      }
    };

    const show_magic_wall = async () => {
      // $store.state.windows_sort.findIndex((element) => element == item.uuid)
      let client = GlobalData.getInstance().getCurrentClient();
      if (client) {
        const response = await client.getMagicWallConfig();
        const settings = await GlobalData.getInstance()
          .getCurrentClient()
          ?.getOutputBoardSetting();
        if (response && settings) {
          const a = response?.config.windows;
          const wall_dom = wall.value;
          let monitorList: any = [];

          if (a && wall_dom) {
            offsetHeight = wall_dom.clientHeight;
            offsetWidth = wall_dom.clientHeight;
            a.forEach((element) => {
              let item: test_monitor = new test_monitor(0, 0, 0);
              item.h = element.h;
              item.w = element.w;
              item.currentx = element.lt.x;
              item.currenty = element.lt.y;
              item.angle = element.angle;
              item.id = element.index;
              if ($store.state.show_monitor_list.length == 0) {
                monitorList.push(item);
                $store.commit("setShowMonitorList", monitorList);
              } else {
                let flag = false;
                $store.state.show_monitor_list.forEach((ele: any) => {
                  if (element.index == ele.id) {
                    flag = true;
                  }
                });
                if (!flag) {
                  monitorList.push(item);
                  $store.commit("setShowMonitorList", monitorList);
                }
              }
            });
          }
        }
      }
    };
    EventBus.getInstance().on(EventNamesDefine.WindowMouseDown, wallMouseDown);
    EventBus.getInstance().on(EventNamesDefine.WindowMouseMove, wallMouseMove);
    EventBus.getInstance().on(EventNamesDefine.WindowMouseUp, wallMouseUp);

    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("setSelectedWindow", "");
                    $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) {
        elementResizeDetectorMaker().listenTo(
          wall.value,
          (element: HTMLElement) => {
            if ($store.state.custom_defines.function_magic_wall) {
              show_magic_wall();
            }
            if (element) {
              calcWallItemWH();
            }
          }
        );
      }
    });

    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.value.offsetLeft;
        const y =
          rect.top -
          (wall.value.parentElement?.offsetTop ?? 0) -
          wall.value.offsetTop;
        GlobalData.getInstance()
          .getCurrentClient()
          ?.moveWindow(
            window_id,
            x / wall.value.clientWidth,
            y / wall.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;
      if (wall.value) {
        const x =
          rect.left -
          (wall.value.parentElement?.offsetLeft ?? 0) -
          wall.value.offsetLeft;
        const y =
          rect.top -
          (wall.value.parentElement?.offsetTop ?? 0) -
          wall.value.offsetTop;
        GlobalData.getInstance()
          .getCurrentClient()
          ?.setWindowGeometry(
            window_id,
            x / wall.value.offsetWidth,
            y / wall.value.clientHeight,
            rect.width / wall.value.offsetWidth,
            rect.height / wall.value.clientHeight
          );
      }
    };

    return {
      windows,
      wall,
      window_rect_edit_dialog,
      wall_rows,
      wall_cols,
      item_witdh,
      item_height,
      show_windows_flag,
      plan_running,
      edit_volume_dialog,
      polling_setting_dialog,
      file_manage_dialog,
      area_open_window_rect,
      area_open_window_flag,
      last_context_menu_pos_x,
      last_context_menu_pos_y,
      loga(a: any) {
        console.log(a);
      },
      async onDrop(e: DragEvent) {
        e.preventDefault();
        let target = e.target as any;

        // 有可能是窗口的子节点收到了拖拽信息，需要找到真正的窗口节点来判断
        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;
        };

        if (target) {
          const temp = find_parent_dom(target, [
            "wall_item_flag",
            "window_flag",
          ]);
          if (temp) {
            target = temp;
          }
        }

        if (target) {
          target.classList.remove("drag-enter");
        }

        if (plan_running.value) {
          $q.notify({
            type: "warning",
            message: $t.t("plan running! can't open window!"),
            position: "top",
            timeout: 1500,
          });
          return;
        }

        const type = e.dataTransfer?.getData("type");
        const uuid = e.dataTransfer?.getData("uuid");
        if (uuid && uuid.length > 0 && type && type.length > 0) {
          const signal_sources = GlobalData.getInstance().signal_source.filter(
            (item) => (item as any)?.uuid == uuid
          );

          {
            const dom_element: HTMLElement | null = target as HTMLElement;
            if (wall.value && dom_element) {
              let x = 0;
              let y = 0;
              let width = 0;
              let height = 0;
              let muted = true;
              let paused = false;
              let play_speed = 1;
              let find_flag = false;
              let find_window = 0;

              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 {}

                x = col * cell_width;
                y = row * cell_height;
                width = cell_width;
                height = cell_height;
              } 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) {
                    x = window.x;
                    y = window.y;
                    width = window.width;
                    height = window.height;
                    muted = window.muted;
                    paused = window.paused;
                    play_speed = window.play_speed;
                    find_window = window.window_id;
                    find_flag = true;
                  }
                }
              }

              if (e.altKey) {
                if (window_rect_edit_dialog.value) {
                  try {
                    let screen_width = $store.state.device_screen_width;
                    let screen_height = $store.state.device_screen_height;
                    if ($store.state.isSpecialVideo()) {
                      const screen_info = SpecialVideoHelper.getScreenInfo(
                        $store.state.wall_col,
                        $store.state.wall_row
                      );
                      screen_width = screen_info.screen_width;
                      screen_height = screen_info.screen_height;
                    }
                    const result =
                      await window_rect_edit_dialog.value.showDialogAsync(
                        x * screen_width,
                        y * screen_height,
                        width * screen_width,
                        height * screen_height
                      );
                    if (result) {
                      x = result.x / screen_width;
                      y = result.y / screen_height;
                      width = result.width / screen_width;
                      height = result.height / screen_height;
                    } else {
                      // 点击了取消按钮
                      return;
                    }
                  } catch {
                    return;
                  }
                }
              }

              setTimeout(() => {
                if (!window) {
                  return;
                }
                switch (type) {
                  case "polling":
                    {
                      if (find_flag) {
                        GlobalData.getInstance()
                          .getCurrentClient()
                          ?.replaceWindow2(find_window, uuid, true);
                      } else {
                        const open_polling_request =
                          new Protocol.OpenPollingRequestEntity(
                            uuid,
                            x,
                            y,
                            width,
                            height
                          );
                        open_polling_request.muted = muted;
                        open_polling_request.paused = paused;
                        open_polling_request.play_speed = play_speed;
                        GlobalData.getInstance()
                          .getCurrentClient()
                          ?.openPolling(open_polling_request);
                      }
                    }

                    break;
                  case "signal_source":
                    {
                      if (signal_sources.length) {
                        const signal_source = signal_sources[0];
                        if (signal_source) {
                          if (find_flag) {
                            GlobalData.getInstance()
                              .getCurrentClient()
                              ?.replaceWindow2(find_window, uuid);
                          } else {
                            if (
                              $store.state.custom_defines.function_magic_wall
                            ) {
                              const item =
                                $store.state.show_monitor_list[
                                  current_index.value
                                ];
                              if (wall.value) {
                                x = Number(select_x()) / wall.value.clientWidth;
                                y =
                                  Number(select_y()) / wall.value.clientHeight;
                                width =
                                  Number(select_width()) /
                                  wall.value.clientWidth;
                                height =
                                  Number(select_height()) /
                                  wall.value.clientHeight;
                              }
                            }
                            const open_window_request =
                              new Protocol.OpenWindowRequestEntity(
                                uuid,
                                x,
                                y,
                                width,
                                height
                              );
                            open_window_request.muted = muted;
                            open_window_request.paused = paused;
                            open_window_request.play_speed = play_speed;
                            GlobalData.getInstance()
                              .getCurrentClient()
                              ?.openWindow(open_window_request);
                          }
                        }
                      }
                    }

                    break;
                }
              }, 50);
            }
          }
        }
      },

      onDragEnter(e: DragEvent) {
        e.stopPropagation();
        let target: HTMLElement | null = e.target as HTMLElement;
        if (target && target.draggable !== true) {
          while (
            target &&
            !target.classList.contains("window_flag") &&
            !target.classList.contains("wall_item_flag")
          ) {
            target = target.parentElement;
          }

          target?.classList.add("drag-enter");
        }
      },
      magic_select(index: number, item: test_monitor, e: DragEvent) {
        current_index.value = index;
        e.stopPropagation();
        let target: HTMLElement | null = e.target as HTMLElement;
        if (target) {
          target?.classList.add("drag-enter");
        }
      },

      onDragLeave(e: DragEvent) {
        let target: HTMLElement = e.target as HTMLElement;
        target?.classList.remove("drag-enter");
      },

      onDragOver(e: DragEvent) {
        if (!plan_running.value && $store.state.power_state) {
          e.preventDefault();
        }
      },

      onWallGridsClick(e: MouseEvent) {
        e.stopPropagation();
        $store.commit("setSelectedWindow", "");
      },
      moveWindow,
      resizeWindow,
      closeAllWindows() {
        GlobalData.getInstance().getCurrentClient()?.closeWindow(-1);
      },
      topWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.focusIn(window_id);
      },
      lowerWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.lowerWindow(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);
          }
        }
      },
      windowDBClick(window_id: number) {
        if (plan_running.value) {
          return;
        }
        GlobalData.getInstance().getCurrentClient()?.windowFitGrid(window_id);
      },
      closeWindow(window_id: number) {
        GlobalData.getInstance().getCurrentClient()?.closeWindow(window_id);
      },
      edit_volume(window_id: number) {
        const window = windows.value.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          edit_volume_dialog.value?.showDialog(window_id, window.volume);
        }
      },
      mute_unmute(window_id: number) {
        const window = windows.value.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 = windows.value.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          GlobalData.getInstance().getCurrentClient()?.startPolling(window_id);
        }
      },
      stop_polling(window_id: number) {
        const window = windows.value.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);
        }
      },
      async polling_setting(window_id: number) {
        const window = windows.value.find(
          (element) => element && element.window_id == window_id
        );
        if (window) {
          if (window.polling) {
            $q.notify({
              color: "positive",
              icon: "done",
              message: $t.t("please stop polling first") + "!",
              position: "top",
              timeout: 1500,
            });
            return;
          }
          const polling = GlobalData.getInstance().pollings.find(
            (element) => element && element.uuid == window.polling_uuid
          );
          const signal_source = GlobalData.getInstance().signal_source.find(
            (element) =>
              element && element.uuid == window.signal_source_table_uuid
          );
          const result = await polling_setting_dialog.value.showDialogAsync(
            polling ? polling.name : signal_source ? signal_source.name : null,
            polling ? polling.polling_signal_sources : []
          );
          if (result) {
            const { name, datas } = result;
            if (name && datas) {
              try {
                const resposne = await GlobalData.getInstance()
                  .getCurrentClient()
                  ?.setWindowPollingData(window_id, name, datas);
                if (resposne && resposne.success) {
                  $q.notify({
                    color: "positive",
                    icon: "done",
                    message: $t.t("set polling data") + $t.t("success") + "!",
                    position: "top",
                    timeout: 1500,
                  });
                } else {
                  $q.notify({
                    color: "negative",
                    icon: "warning",
                    message: $t.t("set polling data") + $t.t("failed") + "!",
                    position: "top",
                    timeout: 1500,
                  });
                }
              } catch (e) {
                console.log(e);
              }
            }
          }
        }
      },
      async openWindowByLocalFile(event: MouseEvent) {
        if (!wall.value) {
          return;
        }

        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 (FileSuffixHelper.isVideoPath(file.name)) {
              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 = "";

            const do_open_local_source = async (
              signal_source: SignalSourceEntity
            ) => {
              try {
                const response = await GlobalData.getInstance()
                  .getCurrentClient()
                  ?.addSignalSource(signal_source);
                if (wall.value && response && response.success) {
                  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.offsetWidth /
                      cell_width
                  );
                  const row = Math.floor(
                    last_context_menu_pos_y.value /
                      wall.value.offsetHeight /
                      cell_height
                  );

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

                  if (!isNaN(x) && !isNaN(y)) {
                    const open_window_request =
                      new Protocol.OpenWindowRequestEntity(
                        response.uuid,
                        x,
                        y,
                        cell_width,
                        cell_height
                      );

                    GlobalData.getInstance()
                      .getCurrentClient()
                      ?.openWindow(open_window_request);
                  }
                }
              } catch {}
            };

            if ($store.state.isSpecialVideo()) {
              $q.dialog({
                title: $t.t("open window"),
                message: $t.t("please select window rotation") + ":",
                options: {
                  type: "radio",
                  model: "0",
                  items: [
                    { label: "0°", value: "0" },
                    { label: "90°", value: "90" },
                    { label: "180°", value: "180" },
                    { label: "270°", value: "270" },
                  ],
                },
                ok: {
                  label: $t.t("ok"),
                  noCaps: true,
                  flat: true,
                },
                cancel: {
                  label: $t.t("cancel"),
                  noCaps: true,
                  flat: true,
                },
                persistent: true,
              }).onOk(async (data) => {
                let temp_rotation = parseInt(data);
                if (isNaN(temp_rotation) || temp_rotation == Infinity) {
                  temp_rotation = 0;
                }
                entity.rotation = temp_rotation;
                do_open_local_source(entity);
              });
            } else {
              do_open_local_source(entity);
            }
          }
        }
      },
      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 (FileSuffixHelper.isVideoPath(file.name)) {
                  entity.window_type = "EwindowType::Multimedia";
                  entity.media_url = JSON.stringify([full_path]);
                } else if (FileSuffixHelper.isImagePath(file.name)) {
                  entity.window_type = "EwindowType::Image";
                  entity.media_url = full_path;
                } else {
                  return;
                }
                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) {
                    GlobalData.getInstance()
                      .getCurrentClient()
                      ?.replaceWindow2(old_window.window_id, response.uuid);
                  }
                } catch {}
              }
            }
          }
        }
      },
    };
  },
});
</script>
