//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
/* player client
 * communication.js
 */
import { packed } from './packData';
export class Communication {
  public _client;
  public _sock = null as any;
  public _ip;
  public _port;
  public _videoType;
  public _key;
  // 总的帧数
  public _totalframe = 0;
  // 量化值
  public _dqtzType = 0;
  // 索引包存放索引大小
  public _indexcount = 20;
  public _iframepos = [] as Array<any>;
  public _indexpos = [] as Array<any>;
  public _heartBeatTask = null as any;
  public _securityWarning = 1;
  public _host;

  // 构建websocket对象
  constructor(client: any, ip: string, port: number, videoType: number, key: string, host: number) {
    this._client = client;
    this._ip = ip;
    this._port = port;
    this._videoType = videoType;
    this._key = key;
    this._host = host;
    this._CreatConnection();
  }
  
  // 创建webScoket对象
  _CreatConnection() {
    // 监听浏览器页签关闭事件，发送断开链接请求
    window.onbeforeunload = () => {
      this._Send(packed.packDisconnect());
    };
    const self = this;
    this._sock = new WebSocket(`wss://${this._ip}:${this._port}/websocket/video`);
    this._sock.onopen = (e: any) => {
      self._WSOpen(e);
    };
    this._sock.onclose = (e: any) => {
      self._WSClose(e);
    };
    this._sock.onerror = (e: any) => {
      self._WSError(e);
    };
    this._sock.onmessage = (e: any) => {
      self._WSMessage(e);
    };
  }

  // token字符串转义
  public getKvmToken() {
    const tokenLength = this._key?.length;
    const buffer = new Uint8Array(tokenLength);
    for (let i = 0; i < tokenLength; i++) {
      buffer[i] = this._key.charCodeAt(i);
    }
    return [...buffer];
  }

  // 以下为websocket相对应的回调事件处理
  _WSOpen(e: any) {
    const self = this;
  // 连接之后发送 连接命令 发送心跳包
    self._Send(packed.packConnect(this.getKvmToken()));
    this._heartBeatTask = setInterval(() => {
      self._Send(packed.packHeartBeat());
    }, 2000);
  }

  _WSClose(event: any) {
    const self = this;
    // 发送断开连接指令
    self._Send(packed.packDisconnect());
    this._sock = null;
    clearInterval(this._heartBeatTask);
    // code值1008表示会话超时
    if (event?.code === 1008) {
      this._client._showMessage('REMOTE_ERR_TIMEOUT');
    } else if (event?.code === 4001) {
      // code值4001表示会话被强制踢出
      this._client._toolbar.updatePlayDisplay(0);
      this._client._showMessage('VIDEO_FORCE_CLOSE_CONNECT');
    } else {
      if (event?.code !== 1015) {
        // 默认提示网络中断
        this._client._showMessage('REMOTE_ERR_NETWORK_INTERRUPT');
      }
    }
  }

  _WSError(e: any) {
    if (this._securityWarning === 1) {
      this._securityWarning = 0;
      this._ResolveSecurityWarning();
      return;
    }
  }

  // 读取到服务端的数据 并进行解析
  _WSMessage(e: any) {
    let _data = null as any;
    const reader = new FileReader();
    const self = this;
    reader.onload = event => {
      if (event.target?.readyState === FileReader.DONE) {
        _data = event.target.result;
        _data = new Uint8Array(_data);
        self._DataParse(_data);
      }
    };
    reader.readAsArrayBuffer(e.data);
  }

  _ResolveSecurityWarning() {
    const self = this;
    let interval = null as any;
    let times = 0;
    function receiver(event: any) {
      if (event.data === 'Certificate OK.') {
        clearInterval(interval);
        window.removeEventListener('message', receiver);
        self._CreatConnection();
      }
    }
    const targetOrigin = `https://${this._ip}:${this._port}`;
    const popUpWin = window.open(targetOrigin, '_blank');
    if (popUpWin) {
      popUpWin.opener = null;
    }
    window.addEventListener('message', receiver);

    interval = setInterval(() => {
      popUpWin?.postMessage('hello', targetOrigin);
      if (times++ > 150) {
        clearInterval(interval);
        window.removeEventListener('message', receiver);
        this._client._toolbar.updatePlayDisplay(0);
        self._client._showMessage('VIDEO_ERR_VERIFY_TIMEOUT');
      }
    }, 200);
  }

  // 通信数据解析
  _DataParse(data: any) {
    const self = this;
    let head = 0;
    let start = 0;
    let resultstart = 0;
    let state = 0;
    let dlen = 0;
    let sublen = 0;
    let rdlen = 0;
    let result;
    while (start < data.length) {
      switch (state) {
        case 0:
          head += data[start++] & 0xff;
          if ((head & 0xffff) === 0xfef6) {
            state = 1;
          }
          head <<= 8;
          break;
        case 1:
          if (start < data.length) {
            dlen += (data[start++] & 0xff) << ((3 - sublen) * 8);
            sublen++;
          }
          if (sublen > 3) {
            resultstart = 0;
            result = new Array(dlen - 6);
            state = 2;
          }
          break;
        case 2:
          if (result) {
            result[resultstart++] = data[start++];
            rdlen++;
            if (rdlen >= result.length) {
              self._MsgDispatch(result);
            }
          }
          break;
        default:
          break;
      }
    }
  }

  // 处理来自服务端不同类型的数据的任务调度
  _MsgDispatch(data: any) {
    const self = this;
    switch (data[0]) {
      // 解析文件头
      case 0x01:
        self._GetFileTopData(data);
        break;
      // 解析索引文件
      case 0x02:
        self._GetIndexData(data);
        this._client.scope.playStatus = 'VIDEO_PLAY';
        break;
      // 解析图像文件
      case 0x03:
        this._client._display.Draw(data);
        // 处理是否跳帧
        if (this._client._progressbar.isSkipFrame()) {
          // 找到最近的I帧
          const iframepos = this._client._toolbar.findIFrame(
            this._client._progressbar.getSkipFramePosition(),
            this._iframepos
          );
          self.sendJumpingFrame(iframepos);
          this._client._progressbar.clearIsSkipFrame();
        }
        this._client._progressbar.updateSlider(this._totalframe);
        break;
      // 收到连接成功命令，发送连接到录像的命令
      case 0x04:
        self._Send(packed.packStartPlay(this._videoType, 1, this._host));
        break;
      default:
    }
  }

  // 解析文件头数据
  _GetFileTopData(data: any) {
    const self = this;
    if (data[0] !== 0x01) {
      return;
    }
    // 获取总的帧数
    let partialByte = data.slice(2, 2 + 4);
    this._totalframe = self._BytesToInt(partialByte);

    // 获取包头量化表的类型
    partialByte = data.slice(23, 23 + 1);
    this._dqtzType = self._BytesToInt(partialByte);

    this._client.scope.isInited = true;
  }

  // 解析索引数据
  _GetIndexData(data: any) {
    if (data[0] !== 0x02) {
      return;
    }
    let framepos;
    let indexpos;
    // 获取一个索引包中的20个I帧信息
    for (let i = 0; i < this._indexcount; i++) {
      framepos = data.slice(1 + (i * (4 + 8)), 1 + (i * (4 + 8)) + 4);
      indexpos = data.slice(1 + (i * (4 + 8)) + 4, 1 + (i * (4 + 8)) + 4 + 8);

      framepos = this._BytesToInt(framepos);
      indexpos = this._BytesToInt(indexpos);

      if (framepos === 0 && indexpos === 0) {
        return;
      }
      // 替换Map类
      if (this._iframepos.indexOf(framepos) === -1 && this._indexpos.indexOf(indexpos) === -1) {
        this._iframepos.push(framepos);
        this._indexpos.push(indexpos);
      }
    }
  }

  // 发送播放速度指令
  sendSpeedFrame(speed: any) {
    const self = this;
    const data = packed.packSpeedPlay(speed);
    self._Send(data);
  }
  
  // 发送暂停录像发送指令
  sendSuspend() {
    const self = this;
    const data = packed.packPausePlay();
    self._Send(data);
  }

  // 发送继续播放指令
  sendContinuing() {
    const self = this;
    const data = packed.packContinuePlay();
    self._Send(data);
  }

  // 发送跳帧指令
  sendJumpingFrame(skippoint: any) {
    const self = this;
    const data = packed.packProgressPlay(skippoint);
    self._Send(data);
  }

  sendStop() {
    const self = this;
    const data = packed.packStopPlay();
    self._Send(data);
  }

  // 获取总的帧数
  getFrameTotal() {
    const totalframe = this._totalframe;
    return totalframe;
  }

  getDQTZ() {
    return this._dqtzType;
  }

  _Send(cmd: any) {
    if (this._sock != null && this._sock.readyState === 1) {
      this._sock.send(cmd);
    }
  }

  _BytesToInt(bytes: any) {
    let result = 0;
    for (let i = 0; i < bytes.length; i++) {
      result += (parseInt(bytes[i], 10) & 0xff) << (8 * (bytes.length - i - 1));
    }
    return result;
  }
}
