import { Message } from './Message'
import { PlatformLogger } from './PlatformLogger'
import { PlatformSettings } from './PlatformSettings'
import { IPackage } from './IPackage'

/**
 * 8583 128域类型报文，Tcp通讯方式的组包，解包处理。承德渠道
 */
export class Msg858301 implements IPackage {
    // 定义静态实例
    private static _instance: Msg858301

    /**
     * 静态实例初始化函数
     */
    public static getInstance(): Msg858301 {
        if (!this._instance) {
            this._instance = new Msg858301()
        }
        return this._instance
    }

    /**
     * 组包操作
     * @param msg 核心返回数据包
     * @returns 报文数据包
     */
    public integrate(msg: Message): Uint8Array {
        let returnData: Uint8Array | null = null

        try {
            returnData = this.doIntegrate(msg)
        } catch (ex) {
            // 写错误信息
            PlatformLogger.systemErrorInfo("组包发生异常：", ex)
            throw ex
        }
        return returnData
    }

    /**
     * 解包操作
     * @param msg 核心返回数据包
     * @param data 核心返回数据包
     * @returns 是否解包成功
     */
    public analyze(msg: Message, data: Uint8Array): boolean {
        try {
            // 进行解包处理
            this.doAnalyze(msg, data)
        } catch (ex) {
            return false
        }
        return true
    }

    // 组包处理
    private doIntegrate(msg: Message): Uint8Array {
        // 报文数据区
        let msgData: Uint8Array
        // 报文总长度
        let totalLen: number
        // 8位长度对应字符串
        let strLen: string
        // 报文数据区的长度
        let msgDataLen: number
        // 60位报文头
        let msgTitle: string
        // 5报文类型
        let msgKindByte: Uint8Array
        // 位图区域
        let bitMapByte = new Uint8Array(16)
        // 有效数据内容
        let bitDataByte: Uint8Array
        // 组包数据包
        let totalMsgData: Uint8Array

        // 文件标志 0xff==no file   0x7f==file
        let fileFlag: number
        // 根据当前交易附件标志设置文件标志
        fileFlag = msg.fileFlag ? 0x7f : 0xff

        try {
            // 报文类型
            msgKindByte = new TextEncoder().encode("00000")
            // 组织报文数据区域信息，位图区，数据区
            bitDataByte = msg.integrateFd(bitMapByte)

            // 报文数据区长度
            msgDataLen = msgKindByte.length + bitMapByte.length + bitDataByte.length
            // 报文总长度
            totalLen = msgDataLen + 68
            // 8位长度对应字符串
            strLen = totalLen.toString().padStart(8, '0')
            // 60位报文头
            msgTitle = msgDataLen.toString().padStart(4, '0').padStart(68, ' ')

            // 合并5位报文类型，位图，数据区域
            msgData = new Uint8Array(msgDataLen)
            // 合并操作
            for (let i = 0; i < msgData.length; i++) {
                if (i < msgKindByte.length) {
                    msgData[i] = msgKindByte[i]
                }

                if (i > msgKindByte.length - 1 && i < msgKindByte.length + bitMapByte.length) {
                    msgData[i] = bitMapByte[i - msgKindByte.length]
                }
                if (i > msgKindByte.length + bitMapByte.length - 1) {
                    msgData[i] = bitDataByte[i - msgKindByte.length - bitMapByte.length]
                }
            }

            // 合并组包数据
            // 8位的报文长度
            const len8 = new TextEncoder().encode(strLen)
            // 报文头字节数组
            const msgTitleByte = new TextEncoder().encode(msgTitle)
            totalMsgData = new Uint8Array(len8.length + msgTitleByte.length + msgData.length + 1)
            
            for (let j = 0; j < totalMsgData.length - 1; j++) {
                if (j < len8.length) {
                    totalMsgData[j] = len8[j]
                }
                if (j > len8.length - 1 && j < len8.length + msgTitleByte.length) {
                    totalMsgData[j] = msgTitleByte[j - len8.length]
                }
                if (j > len8.length + msgTitleByte.length - 1) {
                    totalMsgData[j] = msgData[j - len8.length - msgTitleByte.length]
                }
            }
            // 设置文件标志位
            totalMsgData[totalMsgData.length - 1] = fileFlag

            // 处理附件
            if (msg.fileFlag) {
                // 文件追加到数据后
                const file = new TextEncoder().encode(Message.cconv(msg.fileData))
                const lenData = new TextEncoder().encode(file.length.toString().padStart(8, '0'))
                const fileName = !msg._filename 
                    ? new TextEncoder().encode(msg._filename.padEnd(30)) 
                    : new TextEncoder().encode((msg.loginUserInfo.kinbrNo + msg.loginUserInfo.ttyName).padEnd(30))
                
                const ret = new Uint8Array(totalMsgData.length + fileName.length + lenData.length + file.length + 1)
                ret.set(totalMsgData, 0)
                ret.set(fileName, totalMsgData.length)
                ret.set(lenData, totalMsgData.length + fileName.length)
                ret.set(file, totalMsgData.length + fileName.length + lenData.length)
                // 补充一个结束字符
                ret[ret.length - 1] = 0xff
                totalMsgData = ret
            }
        } catch (ex) {
            // 写错误信息
            PlatformLogger.systemErrorInfo("组包发生异常！", ex)
            throw ex
        }
        return totalMsgData
    }

    // 解包处理
    private doAnalyze(msg: Message, returnData: Uint8Array): void {
        try {
            // 丢弃前8位
            const ret = new Uint8Array(returnData.length - 8)
            ret.set(returnData.subarray(8), 0)
            returnData = ret

            // 报文前68位内容       
            const msg60 = new Uint8Array(68)
            // 报文数据区长度        
            let msgDataLen = 0
            // 报文数据区内容
            let msgData: Uint8Array

            // 报文前60位（60位报文头）
            msg60.set(returnData.subarray(0, 68), 0)

            // 报文数据区长度 
            const tmpLen = new Uint8Array(4)
            tmpLen.set(msg60.subarray(64, 68), 0)
            msgDataLen = parseInt(new TextDecoder().decode(tmpLen))

            // 取得报文数据区内容
            msgData = new Uint8Array(msgDataLen)
            msgData.set(returnData.subarray(68, 68 + msgDataLen), 0)
            
            if (!msg.anilyzeFd(msgData)) {
                // 解包失败
                throw new Error("8583通讯解包操作失败！具体情况请查看日志！")
            }

            // 有文件附件的处理
            const fileLen = returnData.length - 68 - msgDataLen - 38 - 1
            if (fileLen > 0) {
                // 报文文件内容               
                const fileData = new Uint8Array(fileLen)
                fileData.set(returnData.subarray(68 + msgDataLen + 38 + 1, 68 + msgDataLen + 38 + 1 + fileLen), 0)
                // 返回解包后文件数据
                msg.fileData = Message.cconv(new TextDecoder().decode(fileData), false)
                // 写调试日志
                PlatformLogger.communicationInfo("\n文件数据:\n" + new TextDecoder().decode(fileData))
            }
        } catch (ex) {
            // 写错误信息
            PlatformLogger.systemErrorInfo("解析报文失败！", ex)
            throw ex
        }
    }

    // 生成TUXEDO方式报文头
    private getMsgT(msg: Message, msgDataLen: string): string {
        const clnm = "".padStart(5, ' ')         //5位   空串
        const svcnm = "".padStart(15, ' ')        //15位  Tuxedo交易服务名
        const reqtype = "4"                       //1位   "4"
        const branchNo = msg.fd3.padStart(10, ' ') //10位   机构编号
        const tty = msg.fd10.padStart(12, ' ')    //12位   终端号
        const titaOr8583 = "8"                    //1位   代码中的值 8'
        const cbs = "".padStart(10, ' ')          //10位  空串
        const macflg = "".padStart(1, ' ')        //1位   空串
        const mac = "".padStart(8, ' ')           //8位   空串
        const result = "0"                        //1位   '0'
        const len = msgDataLen.padStart(4, '0')   //4位   8583数据区长度

        // TUXEDO方式报文头
        return clnm + svcnm + reqtype + branchNo + tty + titaOr8583 + 
               cbs + macflg + mac + result + len
    }
}