// //////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2016-present  All Rights Reserved.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Github Home: https://github.com/AlexWang1987
//  Author: AlexWang
//  Date: 2016-08-26 11:19:56
//  QQ Email: 1669499355@qq.com
//  Last Modified time: 2017-01-04 14:38:20
//  Description: LiveClass-Ape
//
// //////////////////////////////////////////////////////////////////////////////

import pdu from 'pdus';
import Emiter from 'Emiter';
import mcu from 'mcu';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import ApeConsts from './ApeConsts';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import PduConsts from 'pdus/PduConsts';
import GlobalConfig from 'GlobalConfig';

// 日志对象
const loger = Loger.getLoger('Ape');

export default class Ape extends Emiter {
  constructor(
    session_id,
    session_name,
    session_tag
  ) {
    super();
    this._session_id = session_id;
    this._channel_id = session_id; // session_id === channel_id
    this._session_name = session_name;
    this._session_tag = session_tag;
    this._session_channels = {};
    this._adapter_pdu = new pdu['RCAdapterPdu'];
    this._classInfo = null;
    this._rCArrayBufferUtil = ArrayBufferUtil;
    this._apeDelayed = false;
    this._apeDelayedMsgs = [];
    this._apeDelayedTimer = 0;

    //Ape 通用消息处理
    this.on(pdu.RCPDU_SESSION_JOIN_RESPONSE, this._joinSessionHandler.bind(this));
    this.on(pdu.RCPDU_CHANNEL_JOIN_RESPONSE, this._joinChannelHandler.bind(this));
    this.on(pdu.RCPDU_REG_ADAPTER, this._pduMessageHandler.bind(this));

    //先收到onJoinSessionHandlerSuccess   后收到 onJoinChannelHandlerSuccess

    // 监听底层MCU会议
    this.mcu = mcu;
    this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this));
    this.mcu.registerApe(this);
  }

  regResponsePduHandler() {

  }

  // 消息处理
  _pduMessageHandler(regBuffer) {
    //loger.log("RCPDU_REG_ADAPTER==============================");
    if (this._apeDelayed) {
      // this._apeDelayedMsgs.push(regBuffer);
      // this._apeDelayedStart();
      setTimeout(() => {
        this._pduRegAdapterHandler(regBuffer);
      },GlobalConfig.mcuDelay|| 2000);
      return;
    }
    this._pduRegAdapterHandler(regBuffer);
  }

  // _apeDelayedStart() {
  //   if (this._apeDelayed && !this._apeDelayedTimer) {
  //     this._apeDelayedTimer = setInterval(this._delayedMsgHandler.bind(this), this._classInfo['mcuDelay'] || 10000);
  //   }
  // }

  // _apeDelayedStop() {
  //   clearInterval(this._apeDelayedTimer);
  //   this._apeDelayedTimer = 0;
  // }

  // // 延迟消息处理
  // _delayedMsgHandler() {
  //   if (this._apeDelayedMsgs.length) {
  //     this._pduRegAdapterHandler(this._apeDelayedMsgs.pop());
  //     if (!this._apeDelayedMsgs.length) this._apeDelayedStop();
  //   }
  // }

  // 数据同步处理
  _pduRegAdapterHandler(regBuffer) {
    let regPdu = pdu['RCAdapterPdu'].decode(regBuffer);
    let regItems = regPdu.item;
    let regItemSize = regItems.length;
    //loger.log(this._session_name + '数据同步消息');
    loger.log(this._session_name + '数据同步消息.同步条数', regItemSize);
    //console.log(regPdu);

    for (var i = 0; i < regItemSize; ++i) {
      let regItem = regItems[i];
      let regItemType = regItem.type;
      let regItemData = regItem.itemData;

      //根据数据包中的type处理数据是否同步

      if (pdu.RCPDU_REG_UPDATE_OBJ !== regItemType) {
        if (pdu.RCPDU_REG_RESPONSE_OBJ == regItemType) {
          let regResponsePdu = pdu['RCRegistryResponseObjPdu'].decode(regItemData);
          this.regResponsePduHandler(regResponsePdu);
        }
        // 只处理两种类型
        continue;
      }

      //具体的数据包
      let regUpdatedItem = pdu['RCRegistryUpdateObjPdu'].decode(regItemData);
      let sub_type = regUpdatedItem.subType;
      let object_id = regUpdatedItem.objId;
      let user_data = regUpdatedItem.userData;

      loger.log('REG OBJECT EVENT ->', pdu.id2type(sub_type));
      switch (sub_type) {
      case pdu.RCPDU_REG_ROSTER_INSERT_PDU:
        let rosterInsertData = pdu['RCRegstryRosterInsertItemPdu'].decode(user_data);
        let rosterInsertItems = rosterInsertData.items;
        let rosterInsertItemsLen = rosterInsertItems.length;
        for (let i = 0; i < rosterInsertItemsLen; ++i) {
          let record = rosterInsertItems[i];
          let recordId = record.item_id;
          let recordData = pdu['RCNodeInfoRecordPdu'].decode(record.item_data);
          this.rosterInsertHandler(recordId, recordData);
        }
        break;
      case pdu.RCPDU_REG_ROSTER_DELETE_PDU:
        let rosterDelData = pdu['RCRegistryRosterDeleteItemPdu'].decode(user_data);
        this.rosterDelHandler(rosterDelData.nodeId);
        break;
      case pdu.RCPDU_REG_ROSTER_UPDATE_PDU:
        let rosterUpdateData = pdu['RCRegistryRosterUpdateItemPdu'].decode(user_data);
        let rosterUpdateItems = rosterUpdateData.items;
        let rosterUpdateItemsLen = rosterUpdateItems.length;
        for (let i = 0; i < rosterUpdateItemsLen; ++i) {
          let node = rosterUpdateItems[i];
          let nodeId = node.nodeId;
          let nodeData = pdu['RCNodeInfoRecordPdu'].decode(node.nodeData);
          this.rosterUpdateHandler(nodeId, nodeData);
        }
        break;
      case pdu.RCPDU_REG_TABLE_INSERT_PDU:
        let tableInsertData = pdu['RCRegistryTableInsertItemPdu'].decode(user_data);
        let tableInsertItems = tableInsertData.items;
        let tableInsertItemsLen = tableInsertItems.length;
        for (let i = 0; i < tableInsertItemsLen; ++i) {
          let insertItem = tableInsertItems[i];
          //loger.log("insertItem",insertItem);
          this.tableInsertHandler(insertItem.owner, insertItem.itemIdx, insertItem.itemData);
        }
        break;
      case pdu.RCPDU_REG_TABLE_DELETE_PDU:
        let tableDeleteData = pdu['RCRegistryTableDeleteItemPdu'].decode(user_data);
        //console.log("tableDeleteData",object_id,tableDeleteData);
        this.tableDeleteHandler(object_id, tableDeleteData);
        break;
      case pdu.RCPDU_REG_TABLE_UPDATE_PDU:
        let tableUpdateData = pdu['RCRegistryTableUpdateItemPdu'].decode(user_data);
        let tableUpdateItems = tableUpdateData.items;
        let tableUpdateItemsLen= tableUpdateItems.length;
        loger.log("RCRegistryTableUpdateItemPdu "+tableUpdateItemsLen);
        console.log(tableUpdateData);

        for (let i = 0; i < tableUpdateItemsLen; ++i) {
          let tableItem = tableUpdateItems[i];
          this.tableUpdateHandler(tableItem.owner, tableItem.itemIdx, tableItem.itemData);
        }
        break;
      case pdu.RCPDU_REG_QUEUE_UPDATE_PDU:
      case pdu.RCPDU_REG_QUEUE_DELETE_PDU:
      case pdu.RCPDU_REG_QUEUE_INSERT_PDU:
        loger.warn('REG QUEUE ARE IGNORED');
        break;

      }
    }
  }

  rosterInsertHandler(recordId, recordData) {
    loger.warn(this._session_name + ' rosterInsertHandler 应有子类具体覆盖处理.');
  }
  rosterUpdateHandler(nodeId, nodeData) {
    loger.warn(this._session_name + ' rosterUpdateHandler 应有子类具体覆盖处理.');
  }
  rosterDelHandler(recordData) {
    loger.warn(this._session_name + ' rosterDelHandler 应有子类具体覆盖处理.');
  }
  tableInsertHandler(tableId, record) {
    loger.warn(this._session_name + ' tableInsertHandler 应有子类具体覆盖处理.');
  }
  tableUpdateHandler(ownerId, recordId, recordData) {
    loger.warn(this._session_name + ' tableUpdateHandler 应有子类具体覆盖处理.');
  }
  tableDeleteHandler(tableId, record) {
    loger.warn(this._session_name + ' tableDelHandler 应有子类具体覆盖处理.');
  }
  onJoinChannelHandlerSuccess(){
    loger.warn(this._session_name + ' onJoinChannelHandlerSuccess 应有子类具体覆盖处理.');
  }
  onJoinSessionHandlerSuccess(){
    loger.warn(this._session_name + ' onJoinSessionHandlerSuccess 应有子类具体覆盖处理.');
  }
  // 加入Session处理
  _joinSessionHandler(data) {
    loger.log(this._session_name, ' -> 加入Session');
    this.onJoinSessionHandlerSuccess();
  }

  // 加入Channel处理
  _joinChannelHandler(data) {
    let joinedChannel = pdu['RCChannelJoinResponsePdu'].decode(data);
    if (joinedChannel.result === pdu.RET_SUCCESS) {
      loger.log(this._session_name, ' -> 加入Channel成功. ChannelId', joinedChannel.requestedChannelId);
      this._session_channels[joinedChannel.requestedChannelId] = ApeConsts.CJS_JOINNED;
      this.onJoinChannelHandlerSuccess();
    } else {
      loger.log(this._session_name, ' -> 加入Channel失败.', joinedChannel);
    }
  }

  // 依赖的会议创建完毕 - 发起Ape加入
  _mcuConferenceJoinSuccessHandler(_data) {
    loger.log('创建Ape->',
      'SessionId',
      this._session_id,
      'SessionName',
      this._session_name,
      'SessionTag',
      this._session_tag);

    // 会议依赖底层会议信息
    //this._classInfo = classInfo;
    this._classInfo = GlobalConfig.getClassInfo();

    var joinSessionPdu = new pdu['RCSessionJoinRequestPdu'];
    joinSessionPdu.id = this._session_id;
    joinSessionPdu.name = this._session_name;
    joinSessionPdu.tag = this._session_tag;
    joinSessionPdu.sessionData = this._adapter_pdu.toArrayBuffer();
    this.sendUniform(joinSessionPdu, true);

    var joinChannelPdu = new pdu['RCChannelJoinRequestPdu'];
    joinChannelPdu.initiator = this.mcu.classInfo.nodeId;
    joinChannelPdu.channelId = this._session_id;
    this.send(joinChannelPdu);
  }

  // 注册Key对象
  registerKey(id, name, tag, user_data) {
    let adapterItemPdu = new pdu['RCAdapterItemPdu'];
    adapterItemPdu.type = pdu.RCPDU_REG_REGISTER_KEY;

    // pack register key pdus
    let registerKeyPdu = new pdu['RCRegistryRegisterKeyPdu'];
    registerKeyPdu.id = id;
    registerKeyPdu.name = name;
    registerKeyPdu.tag = tag;
    if (user_data.length) {
      registerKeyPdu.userData = user_data;
    }

    adapterItemPdu.itemData = registerKeyPdu.toArrayBuffer();
    this._adapter_pdu.item.push(adapterItemPdu);
  }

  // 注册Object对象  等同于flash中的 RCRegistryOperator
  registerObj(type, id, name, tag, owner, user_data) {
    let adapterItemPdu = new pdu['RCAdapterItemPdu'];
    adapterItemPdu.type = pdu.RCPDU_REG_REGISTER_OBJ;

    let registerObjPdu = new pdu['RCRegistryRegisterObjPdu'];
    registerObjPdu.type = type;
    registerObjPdu.objId = id;
    registerObjPdu.name = name;
    registerObjPdu.tag = tag;
    if (owner) {
      registerObjPdu.owner = owner;
    }
    if (user_data.length) {
      registerObjPdu.userData = user_data;
    }

    adapterItemPdu.itemData = registerObjPdu.toArrayBuffer();
    this._adapter_pdu.item.push(adapterItemPdu);
  }

  send(appPdu) {
    loger.log('Ape发送数据NORMAL PDU');
    console.log(appPdu);
    //loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
    if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
      this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
      return;
    }
    let normalPdu = pdu.create_normal_pdu(
      appPdu.type,
      this._classInfo.nodeId,
      this._classInfo.classId,
      this._session_id,
      this._channel_id,
      true,
      true,
      PduConsts.DP_TOP,
      this._classInfo.topNodeID,
      PduConsts.SEG_ONCE
    );
    normalPdu.data = appPdu.toArrayBuffer();
    // Mcu发送
    this.mcu.send(normalPdu);
  }

  // 发送当前APE(session uniform包)
  sendUniform(appPdu, top) {
    loger.log('Ape发送数据UNIFORM PDU');
    console.log(appPdu);
    //loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
    if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
      this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
      return;
    }

    let uniformPdu = pdu.create_uniform_pdu(
      appPdu.type,
      this._classInfo.nodeId,
      this._classInfo.classId,
      this._session_id,
      top ? ApeConsts.BROADCAST_CHANNEL_ID : this._channel_id,
      true,
      PduConsts.DP_TOP,
      top ? this._classInfo.topNodeID : (appPdu.peer || 0),
      PduConsts.SEG_ONCE
    );
    uniformPdu.data = appPdu.toArrayBuffer();
    // Mcu发送
    this.mcu.send(uniformPdu);
  }

  sendChatUniform(appPdu, top) {
    loger.log('Ape发送数据UNIFORM PDU');
    console.log(appPdu);
    //loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
    if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
      this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
      return;
    }

    let uniformPdu = pdu.create_uniform_pdu(
        appPdu.type,
        this._classInfo.nodeId,
        this._classInfo.classId,
        this._session_id,
        top ? ApeConsts.BROADCAST_CHANNEL_ID : this._channel_id,
        true,
        PduConsts.DP_TOP,
        0,//flash中这个值设置为0
        PduConsts.SEG_ONCE
    );
    uniformPdu.data = appPdu.toArrayBuffer();
    // Mcu发送
    this.mcu.send(uniformPdu);
  }
}