// //////////////////////////////////////////////////////////////////////////////
//
//  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 McuObj 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';
import RecordPlayBackParse from 'RecordPlayBackParse';

// 日志对象
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 = true;
        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 = McuObj;
        this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this));
        this.mcu.registerApe(this);

        //录制回放
        this.recordPlayBackParse = RecordPlayBackParse;
        this.recordPlayBackParse.on(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, this._joinRecordPlaybackSuccessHandler.bind(this));
        this.recordPlayBackParse.registerApe(this);

    }

    regResponsePduHandler() {

    }

    //停止APE一切操作
    stopApe() {
        loger.log("stopApe==============================");
    }

    // 消息处理
    _pduMessageHandler(regBuffer,_seekTime) {
        let seekTime=_seekTime||0;//这个只有在录制回放的时候才有
  /*      loger.warn('APE->收到消息处理->',GlobalConfig.mcuDelay,GlobalConfig.messageDelay);
        //延迟处理消息(3个条件--->ape允许延迟&&客户端设置需要延迟&&Sass设置的延迟时间大于0)
        if (this._apeDelayed&&GlobalConfig.messageDelay&&GlobalConfig.mcuDelay>0) {
            loger.warn('延迟处理消息->',GlobalConfig.mcuDelay);
            setTimeout(() => {
                this._pduRegAdapterHandler(regBuffer,seekTime);
            }, GlobalConfig.mcuDelay*1000);//mcuDelay单位是秒,这里需要换算为毫秒
            return;
        }
*/
        //不延迟,立即处理
        this._pduRegAdapterHandler(regBuffer,seekTime);
    }

    // 数据同步处理
    _pduRegAdapterHandler(regBuffer,seekTime) {
        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,"seekTime->",seekTime);
        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);
                    //loger.log(tableUpdateData);


                    for (let i = 0; i < tableUpdateItemsLen; ++i) {
                        let tableItem = tableUpdateItems[i];
                        this.tableUpdateHandler(tableItem.owner, tableItem.itemIdx, tableItem.itemData,seekTime);
                    }

                    //白板数据内部自己处理数组
                    this.tableUpdateApeHandler(tableUpdateItems);
                    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,seekTime) {
        loger.warn(this._session_name + ' tableUpdateHandler 应有子类具体覆盖处理.');
    }
    tableUpdateApeHandler(tableUpdateItems,seekTime){

    }
    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);
    }

    // 依赖的录制回放创建完毕 - 发起Ape加入
    _joinRecordPlaybackSuccessHandler(_data) {
        loger.log('录制回放->Ape已经创建完毕->',
            'SessionId',
            this._session_id,
            'SessionName',
            this._session_name,
            'SessionTag',
            this._session_tag);
    }

    // 注册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);
    }
}