import { ConnectTableEntity } from "./../entities/ConnectTableEntity";
import { PollingEntity } from "./../entities/PollingEntity";
import ReconnectingWebSocket from "reconnecting-websocket";
import NormalWindowRequestEntity from "src/entities/NormalWindowRequestEntity";
import { PlanEntity } from "src/entities/PlanEntity";
import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
import { StringKeyValueEntity } from "src/entities/StringKeyValueEntity";
import SubtitleEntity from "src/entities/SubtitleEntity";
import { Protocol } from "src/entities/WSProtocol";
import EventBus, { EventNamesDefine } from "./EventBus";
import { EdgeBlendingPoint } from "src/entities/EdgeBlendingEntities";
import { ExternalControlTableEntity } from "src/entities/ExternalControlTableEntity";
import { SerialPortConfigEntity } from "src/entities/SerialPortConfigEntity";
import TimingTaskEntity from "src/entities/TimingTaskEntity";

class _RpcInfo {
  send_timestamp: number;
  timeout_timestamp: number;
  callback: (is_fail: boolean, packet: Protocol.Commands, data: string) => void;

  constructor(
    timeout_timestamp: number,
    callback: (
      is_fail: boolean,
      packet: Protocol.Commands,
      data: string
    ) => void
  ) {
    this.timeout_timestamp = timeout_timestamp;
    this.send_timestamp = new Date().getTime();
    this.callback = callback;
  }

  public reject() {
    this.callback(true, new Protocol.Commands(), "");
  }

  public reslove(is_fail: boolean, packet: Protocol.Commands, data: string) {
    this.callback(is_fail, packet, data);
  }
}

export default class ClientConnection {
  ws: ReconnectingWebSocket | null = null;
  url = "";
  user_name = "";
  password = "";
  _is_login = false;
  _rpc_id_counter = 0;
  rpc_map = new Map<number, _RpcInfo>();

  public login_callback:
    | ((this: ClientConnection, logined: boolean) => void)
    | null = null;

  constructor(
    url: string,
    user_name?: string | null,
    password?: string | null
  ) {
    this.url = url;
    this.user_name = user_name ?? "";
    this.password = password ?? "";

    if (this.ws) {
      this.ws.close();
    }
    this.ws = new ReconnectingWebSocket(url);

    this.initializeWs();

    setInterval(() => {
      this.checkRpcTimeout();
    }, 1000);
  }

  get is_connected() {
    return this.ws && this.ws.readyState == WebSocket.OPEN;
  }

  get is_login() {
    return this._is_login;
  }

  checkRpcTimeout() {
    const current_datetime = new Date().getTime();
    this.rpc_map.forEach((v, k, m) => {
      if (current_datetime - v.send_timestamp > v.timeout_timestamp) {
        v.reject();
        m.delete(k);
      }
    });
  }

  initializeWs() {
    if (this.ws) {
      this.ws.onclose = (ev) => {
        this.onClose(ev);
      };
      this.ws.onerror = (ev) => {
        this.onError(ev);
      };
      this.ws.onopen = (ev) => {
        this.onOpen(ev);
      };
      this.ws.onmessage = (ev) => {
        this.onMessage(ev);
      };
    }
  }

  login() {
    if (this.is_connected) {
      const request = new Protocol.LoginRequest(this.user_name, this.password);
      this.ws?.send(JSON.stringify(request));
    }
  }

  onClose(ev: any) {
    this._is_login = false;
    EventBus.getInstance().emit(EventNamesDefine.WebSocketClose, this);
  }

  onError(ev: any) {
    this._is_login = false;
    EventBus.getInstance().emit(EventNamesDefine.WebSocketError, this);
  }

  onOpen(ev: any) {
    this._is_login = false;
    this.login();
  }

  onMessage(ev: MessageEvent) {
    try {
      const packet = JSON.parse(ev.data) as Protocol.PacketEntity;

      if (packet) {
        if (packet.has_exception) {
          console.error(ev.data);
          this.rpc_map.get(packet.rpc_id)?.reject();
          this.rpc_map.delete(packet.rpc_id);
        }
        if (Protocol.Commands.AllCommands.has(packet.command)) {
          if (
            packet.flag == Protocol.PacketEntity.FLAG_RESPONSE ||
            packet.flag == Protocol.PacketEntity.FLAG_NOTIFY
          ) {
            if (packet.command == Protocol.Commands.kLogin) {
              const login_response = JSON.parse(
                ev.data
              ) as Protocol.LoginResponse;
              if (login_response) {
                this._is_login =
                  !login_response.has_exception && login_response.success;
                if (this.is_login) {
                  EventBus.getInstance().emit(
                    EventNamesDefine.WebSocketConnected,
                    this
                  );
                }
                if (
                  this.login_callback &&
                  typeof this.login_callback == "function"
                ) {
                  this.login_callback(this._is_login);
                }
              }
            } else if (this.rpc_map.has(packet.rpc_id)) {
              this.rpc_map.get(packet.rpc_id)?.reslove(false, packet, ev.data);
              this.rpc_map.delete(packet.rpc_id);
            } else {
              EventBus.getInstance().emit(
                packet.flag == Protocol.PacketEntity.FLAG_NOTIFY
                  ? EventNamesDefine.NotifyMessage
                  : packet.flag == Protocol.PacketEntity.FLAG_RESPONSE
                  ? EventNamesDefine.ResponseMessage
                  : EventNamesDefine.UnKnow,
                {
                  packet: packet,
                  data: ev.data,
                }
              );
            }
          }
        } else {
          console.error("unknow command: " + packet.command, packet);
        }
      }
    } catch (e) {
      console.error(e);
    }
  }

  public async doRpc<_ResponseType>(
    request: Protocol.PacketEntity
  ): Promise<_ResponseType | null> {
    return new Promise((resolve, reject) => {
      const rpc_id = ++this._rpc_id_counter;
      if (this.rpc_map.has(rpc_id)) {
        this.rpc_map.get(rpc_id)?.reject();
        this.rpc_map.delete(rpc_id);
      }
      request.rpc_id = rpc_id;
      this.rpc_map.set(
        rpc_id,
        new _RpcInfo(
          request.timeout,
          (is_fail: boolean, packet: Protocol.Commands, data: string) => {
            if (is_fail) {
              reject();
            } else {
              try {
                const response = JSON.parse(data) as _ResponseType;
                if (response) {
                  resolve(response);
                } else {
                  reject();
                }
              } catch {
                reject();
              }
            }
          }
        )
      );
      if (request) {
        request.timeout;
      }
      this.ws?.send(JSON.stringify(request));
    });
  }

  public async getSignalSources() {
    try {
      return await this.doRpc<Protocol.GetSignalSourcesResponse>(
        new Protocol.GetSignalSourcesRequest()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addSignalSourceGroup(parent_uuid: string, name: string) {
    try {
      return await this.doRpc<Protocol.AddSignalSourceGroupResponseEntity>(
        new Protocol.AddSignalSourceGroupRequestEntity(0, parent_uuid, name)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editSignalSourceGroup(
    uuid: string,
    name: string,
    parent_uuid: string
  ) {
    try {
      return await this.doRpc<Protocol.EditSignalSourceGroupResponseEntity>(
        new Protocol.EditSignalSourceGroupRequestEntity(
          0,
          uuid,
          name,
          parent_uuid
        )
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deleteSignalSourceGroup(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeleteSignalSourceGroupResponseEntity>(
        new Protocol.DeleteSignalSourceGroupRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addSignalSource(item: SignalSourceEntity) {
    try {
      return await this.doRpc<Protocol.AddSignalSourceResponseEntity>(
        new Protocol.AddSignalSourceRequestEntity(0, item)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editSignalSource(item: SignalSourceEntity) {
    try {
      return await this.doRpc<Protocol.EditSignalSourceResponseEntity>(
        new Protocol.EditSignalSourceRequestEntity(0, item)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deleteSignalSource(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeleteSignalSourceResponseEntity>(
        new Protocol.DeleteSignalSourceRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getModes() {
    try {
      return await this.doRpc<Protocol.GetModesResponseEntity>(
        new Protocol.GetModesRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addPlanGroup(group_uuid: string, name: string) {
    try {
      return await this.doRpc<Protocol.AddPlanGroupResponseEntity>(
        new Protocol.AddPlanGroupRequestEntity(0, group_uuid, name)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editPlanGroup(uuid: string, name: string, parent_uuid: string) {
    try {
      return await this.doRpc<Protocol.EditPlanGroupResponseEntity>(
        new Protocol.EditPlanGroupRequestEntity(0, uuid, name, parent_uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deletePlanGroup(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeletePlanGroupResponseEntity>(
        new Protocol.DeletePlanGroupRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addPlan(entity?: PlanEntity) {
    try {
      return await this.doRpc<Protocol.AddPlanResponseEntity>(
        new Protocol.AddPlanRequestEntity(0, entity)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editPlan(entity?: PlanEntity) {
    try {
      return await this.doRpc<Protocol.EditPlanResponseEntity>(
        new Protocol.EditPlanRequestEntity(0, entity)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deletePlan(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeletePlanResponseEntity>(
        new Protocol.DeletePlanRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deletePollingGroup(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeletePollingGroupResponseEntity>(
        new Protocol.DeletePollingGroupRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addPolling(
    group_uuid: string,
    name: string,
    datas: StringKeyValueEntity[]
  ) {
    try {
      return await this.doRpc<Protocol.AddPollingResponseEntity>(
        new Protocol.AddPollingRequestEntity(0, group_uuid, name, datas, "")
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editPolling(entity: PollingEntity) {
    try {
      return await this.doRpc<Protocol.EditPollingResponseEntity>(
        new Protocol.EditPollingRequestEntity(0, entity)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deletePolling(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeletePollingResponseEntity>(
        new Protocol.DeletePollingRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getCurrentRunningPlan() {
    try {
      return await this.doRpc<Protocol.GetCurrentRunningPlanResponseEntity>(
        new Protocol.GetCurrentRunningPlanRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public runPlan(uuid: string) {
    this.ws?.send(JSON.stringify(new Protocol.RunPlanRequestEntity(uuid)));
  }

  public stopCurrentRunningPlan() {
    this.ws?.send(
      JSON.stringify(new Protocol.StopCurrentRunningPlanRequestEntity())
    );
  }

  public async getPlans() {
    try {
      return await this.doRpc<Protocol.GetPlansResponseEntity>(
        new Protocol.GetPlansRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addModeGroup(group_uuid: string, name: string) {
    try {
      return await this.doRpc<Protocol.AddModeGroupResponseEntity>(
        new Protocol.AddModeGroupRequestEntity(0, group_uuid, name)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editModeGroup(uuid: string, name: string, parent_uuid: string) {
    try {
      return await this.doRpc<Protocol.EditModeGroupResponseEntity>(
        new Protocol.EditModeGroupRequestEntity(0, uuid, name, parent_uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async updateModeWindowList(uuid: string) {
    try {
      return await this.doRpc<Protocol.UpdateModeWindowListResponseEntity>(
        new Protocol.UpdateModeWindowListRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deleteModeGroup(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeleteModeGroupResponseEntity>(
        new Protocol.DeleteModeGroupRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addMode(group_uuid?: string, name?: string, index?: number) {
    try {
      return await this.doRpc<Protocol.AddModeResponseEntity>(
        new Protocol.AddModeRequestEntity(0, name, group_uuid, index)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editMode(
    uuid?: string,
    name?: string,
    index?: number,
    group_uuid?: string
  ) {
    try {
      return await this.doRpc<Protocol.EditModeResponseEntity>(
        new Protocol.EditModeRequestEntity(0, name, uuid, index, group_uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async deleteMode(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeleteModeResponseEntity>(
        new Protocol.DeleteModeRequestEntity(0, uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public callMode(uuid: string) {
    this.ws?.send(JSON.stringify(new Protocol.CallModeRequestEntity(uuid)));
  }

  public async getApplicationSettins() {
    try {
      return await this.doRpc<Protocol.GetApplicationConfigResponseEntity>(
        new Protocol.GetApplicationConfigRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getWindows() {
    try {
      return await this.doRpc<Protocol.GetWindowsResponseEntity>(
        new Protocol.GetWindowsRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getDeviceAttribute() {
    try {
      return await this.doRpc<Protocol.GetDeviceAttributeResponseEntity>(
        new Protocol.GetDeviceAttributeRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public setDeviceAttribute(attribute: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.SetDeviceAttributeRequestEntity(attribute))
    );
  }

  public moveWindow(window_id: number, x: number, y: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.MoveWindowRequestEntity(window_id, x, y))
    );
  }

  public resizeWindow(window_id: number, width: number, height: number) {
    this.ws?.send(
      JSON.stringify(
        new Protocol.ResizeWindowRequestEntity(window_id, width, height)
      )
    );
  }

  public setWindowGeometry(
    window_id: number,
    x: number,
    y: number,
    width: number,
    height: number,
    limit: boolean = true
  ) {
    this.ws?.send(
      JSON.stringify(
        new Protocol.SetWindowGeometryRequestEntity(
          window_id,
          x,
          y,
          width,
          height,
          limit
        )
      )
    );
  }

  public closeWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.CloseWindowRequestEntity(window_id))
    );
  }

  public openWindow(data: Protocol.OpenWindowRequestEntity) {
    this.ws?.send(JSON.stringify(data));
  }

  public openPolling(data: Protocol.OpenPollingRequestEntity) {
    this.ws?.send(JSON.stringify(data));
  }

  public focusIn(window_id: number) {
    this.ws?.send(
      JSON.stringify(
        new NormalWindowRequestEntity(Protocol.Commands.kTopWindow, window_id)
      )
    );
  }

  public lowerWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(
        new NormalWindowRequestEntity(Protocol.Commands.kLowerWindow, window_id)
      )
    );
  }

  public setWallRowCol(wall_row: number, wall_col: number) {
    this.ws?.send(
      JSON.stringify(
        new Protocol.SetApplicationConfigRequestEntity(
          0,
          "wall_row",
          wall_row.toString()
        )
      )
    );
    this.ws?.send(
      JSON.stringify(
        new Protocol.SetApplicationConfigRequestEntity(
          0,
          "wall_col",
          wall_col.toString()
        )
      )
    );
  }

  public setPowerOnPlan(uuid: string) {
    this.ws?.send(
      JSON.stringify(
        new Protocol.SetApplicationConfigRequestEntity(0, "power_on_plan", uuid)
      )
    );
  }

  public windowFitGrid(window_id: number) {
    this.ws?.send(
      JSON.stringify(
        new NormalWindowRequestEntity(
          Protocol.Commands.kWindowFitGrid,
          window_id
        )
      )
    );
  }

  public windowFullScreen(window_id: number, full_screen: boolean) {
    this.ws?.send(
      JSON.stringify(new Protocol.WindowFullScreen(window_id, full_screen))
    );
  }

  public async getSubtitle() {
    try {
      return await this.doRpc<Protocol.GetSubtitleResponseEntity>(
        new Protocol.GetSubtitleRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getRegisterInfo() {
    try {
      return await this.doRpc<Protocol.GetRegisterInfoResponseEntity>(
        new Protocol.GetRegisterInfoRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async registerDevice(
    register_code: string,
    active_code: string,
    online: boolean,
    active_forever: boolean,
    secret_key?: string,
    hour?: number
  ) {
    try {
      return await this.doRpc<Protocol.RegisterDeviceResponseEntity>(
        new Protocol.RegisterDeviceRequestEntity(
          register_code,
          active_code,
          online,
          active_forever,
          secret_key,
          hour,
          0
        )
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async setSubtitle(subtitle: SubtitleEntity) {
    try {
      return await this.doRpc<Protocol.SetSubtitleResponseEntity>(
        new Protocol.SetSubtitleRequestEntity(0, subtitle)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async setSystemNetwork(
    request: Protocol.SetSystemNetworkRequestEntity
  ) {
    return await this.doRpc<Protocol.SetSystemNetworkResponseEntity>(request);
  }
  public async setSystemGraphics(
    request: Protocol.SetSystemGraphicsRequestEntity
  ) {
    return await this.doRpc<Protocol.SetSystemGraphicsResponseEntity>(request);
  }
  public async setSystemOther(request: Protocol.SetSystemOtherRequestEntity) {
    return await this.doRpc<Protocol.SetSystemOtherResponseEntity>(request);
  }
  public async getSupportResolutions() {
    try {
      return await this.doRpc<Protocol.GetSupportResolutionsResponseEntity>(
        new Protocol.GetSupportResolutionsRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getOutputBoardSetting() {
    try {
      return await this.doRpc<Protocol.GetOutputBoardSettingResponseEntity>(
        new Protocol.GetOutputBoardSettingRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async setOutputBoardSetting(
    request: Protocol.SetOutputBoardSettingRequestEntity
  ) {
    try {
      return await this.doRpc<Protocol.SetOutputBoardSettingResponseEntity>(
        request
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async restoreOutputBoard() {
    try {
      return await this.doRpc<Protocol.RestoreOutputBoardResponseEntity>(
        new Protocol.RestoreOutputBoardRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }
  public async setWindowVolume(window_id: number, volume: number) {
    this.ws?.send(
      JSON.stringify(
        new Protocol.SetWindowVolumeRequestEntity(window_id, volume, 0)
      )
    );
  }

  public async unmuteWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.UnMuteWindowRequestEntity(window_id, 0))
    );
  }

  public async muteWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.MuteWindowRequestEntity(window_id, 0))
    );
  }

  public async playWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.PlayWindowRequestEntity(window_id, 0))
    );
  }

  public async windowPlayNext(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.WindowPlayNextRequestEntity(window_id, 0))
    );
  }

  public async windowPlayPrev(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.WindowPlayPrevRequestEntity(window_id, 0))
    );
  }

  public async pauseWindow(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.PauseWindowRequestEntity(window_id, 0))
    );
  }

  public async startPolling(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.StartPollingRequestEntity(window_id))
    );
  }

  public async stopPolling(window_id: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.StopPollingRequestEntity(window_id))
    );
  }

  public async setWindowPollingData(
    window_id: number,
    name: string,
    datas?: StringKeyValueEntity[]
  ) {
    return await this.doRpc<Protocol.SetWindowPollingDataResponseEntity>(
      new Protocol.SetWindowPollingDataRequestEntity(window_id, name, datas)
    );
  }

  public async getBuildInfo() {
    return await this.doRpc<Protocol.GetBuildInfoResponseEntity>(
      new Protocol.GetBuildInfoRequestEntity(0)
    );
  }

  public async getSystemTimes() {
    return await this.doRpc<Protocol.GetSystemTimesResponseEntity>(
      new Protocol.GetSystemTimesRequestEntity(0)
    );
  }

  public restartDevice(delay_ms?: number) {
    this.ws?.send(
      JSON.stringify(new Protocol.RestartDeviceRequestEntity(delay_ms))
    );
  }

  public async getUsbDevices() {
    try {
      return await this.doRpc<Protocol.GetUsbDevicesResponseEntity>(
        new Protocol.GetUsbDevicesRequestEntity(0)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getPollings() {
    try {
      return await this.doRpc<Protocol.GetPollingsResponseEntity>(
        new Protocol.GetPollingsRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async fileOperator(
    from_path: string,
    to_path: string,
    operator_type: string,
    force_operator: boolean = true
  ) {
    try {
      return await this.doRpc<Protocol.FileOperatorResponseEntity>(
        new Protocol.FileOperatorRequestEntity(
          from_path,
          to_path,
          operator_type,
          force_operator
        )
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getEdgeBlendingInfo() {
    return await this.doRpc<Protocol.GetEdgeBlendingInfoResponseEntity>(
      new Protocol.GetEdgeBlendingInfoRequestEntity(0)
    );
  }

  public async setEdgeBlendingInfo(
    enable_blending: boolean,
    enable_correct: boolean,
    width: number,
    height: number,
    col: number,
    row: number,
    point_count: number
  ) {
    return await this.doRpc<Protocol.SetEdgeBlendingInfoResponseEntity>(
      new Protocol.SetEdgeBlendingInfoRequestEntity(
        enable_blending,
        enable_correct,
        width,
        height,
        col,
        row,
        point_count,
        0
      )
    );
  }

  public async wakeUpDevice() {
    return await this.doRpc<Protocol.SetDevicePowerResponseEntity>(
      new Protocol.SetDevicePowerRequestEntity(
        Protocol.SetDevicePowerRequestEntity.kPowerStatePowerOn
      )
    );
  }

  public async deviceStandByMode() {
    return await this.doRpc<Protocol.SetDevicePowerResponseEntity>(
      new Protocol.SetDevicePowerRequestEntity(
        Protocol.SetDevicePowerRequestEntity.kPowerStateStandBy
      )
    );
  }

  public async getExternalControlDatas() {
    return await this.doRpc<Protocol.RpcGetExternalControlDatasResponseEntity>(
      new Protocol.RpcGetExternalControlDatasRequestEntity()
    );
  }

  public async deleteExternalControlData(uuid: string) {
    return await this.doRpc<Protocol.RpcDeleteExternalControlDataResponseEntity>(
      new Protocol.RpcDeleteExternalControlDataRequestEntity(uuid)
    );
  }

  public async editExternalControlData(entity: ExternalControlTableEntity) {
    return await this.doRpc<Protocol.RpcEditExternalControlDataResponseEntity>(
      new Protocol.RpcEditExternalControlDataRequestEntity(entity)
    );
  }

  public async addExternalControlData(entity: ExternalControlTableEntity) {
    return await this.doRpc<Protocol.RpcAddExternalControlDataResponseEntity>(
      new Protocol.RpcAddExternalControlDataRequestEntity(entity)
    );
  }

  public async getExternalControlSerialPortConfig() {
    return await this.doRpc<Protocol.RpcGetExternalControlSerialPortConfigResponseEntity>(
      new Protocol.RpcGetExternalControlSerialPortConfigRequestEntity()
    );
  }

  public async setExternalControlSerialPortConfig(
    config: SerialPortConfigEntity
  ) {
    return await this.doRpc<Protocol.RpcSetExternalControlSerialPortConfigResponseEntity>(
      new Protocol.RpcSetExternalControlSerialPortConfigRequestEntity(config)
    );
  }

  public callExternalControlData(uuid: string) {
    this.ws?.send(
      JSON.stringify(new Protocol.CallExternalControlDataRequestEntity(uuid))
    );
  }
  public setEdgeBlendingPoint(point: EdgeBlendingPoint) {
    this.ws?.send(
      JSON.stringify(new Protocol.SetEdgeBlendingPointRequestEntity(point))
    );
  }

  public setServerLanguage(language: string) {
    this.ws?.send(
      JSON.stringify(new Protocol.SetLanguageRequestEntity(language))
    );
  }

  public async getConnectList() {
    return await this.doRpc<Protocol.GetConnectionListResponseEntity>(
      new Protocol.GetConnectionListRequestEntity()
    );
  }
  public async setConnectItem(entity: ConnectTableEntity) {
    return await this.doRpc<Protocol.SetConnectionItemResponseEntity>(
      new Protocol.SetConnectionItemRequestEntity(entity)
    );
  }

  public async getTimingTasks() {
    try {
      return await this.doRpc<Protocol.GetTimingTasksResponseEntity>(
        new Protocol.GetTimingTasksRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async addTimingTask(task: TimingTaskEntity) {
    try {
      return await this.doRpc<Protocol.AddTimingTaskResponseEntity>(
        new Protocol.AddTimingTaskRequestEntity(task)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async editTimingTask(task: TimingTaskEntity) {
    try {
      return await this.doRpc<Protocol.EditTimingTaskResponseEntity>(
        new Protocol.EditTimingTaskRequestEntity(task)
      );
    } catch (e) {
      console.error(e);
    }
  }
  public async deleteTimingTask(uuid: string) {
    try {
      return await this.doRpc<Protocol.DeleteTimingTaskResponseEntity>(
        new Protocol.DeleteTimingTaskRequestEntity(uuid)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getSystemNetworkInfo() {
    try {
      return await this.doRpc<Protocol.GetSystemNetworkInfoResponseEntity>(
        new Protocol.GetSystemNetworkInfoRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async setHdmiInDecodeType(index: number, type: string) {
    try {
      return await this.doRpc<Protocol.SetHdmiInDecodeTypeResponseEntity>(
        new Protocol.SetHdmiInDecodeTypeRequestEntity(index, type)
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getCityList() {
    try {
      return await this.doRpc<Protocol.GetCityListResponseEntity>(
        new Protocol.GetCityListRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public async getPowerState() {
    try {
      return await this.doRpc<Protocol.GetPowerStateResponseEntity>(
        new Protocol.GetPowerStateRequestEntity()
      );
    } catch (e) {
      console.error(e);
    }
  }

  public destory() {
    if (this.ws) {
      this.ws.onclose = null;
      this.ws.onerror = null;
      this.ws.onopen = null;
      this.ws.onmessage = null;
    }
    this.ws?.close();
    this.ws = null;
  }
}

export interface NotifyMessage {
  packet: Protocol.PacketEntity;
  data: string;
}