

/*=============================================================================================
    author:ZhaoJun
    version:1.2
    email:2732810281@qq.com
=============================================================================================*/


//严格模式
/*-------------------------------------------------------------------------------------------*/ 
'use strict';
/*-------------------------------------------------------------------------------------------*/


// 分解包
/*-------------------------------------------------------------------------------------------*/ 
    class packages
    {  

        static escape(data)
        {
            let tag=$ExtendNet.package.tag
            let end=$ExtendNet.package.end
            return data.replace(tag.reg,tag.init+tag.val)
            .replace(end.reg,tag.init+end.val)
        }

        static unescape(data)
        {
            let tag=$ExtendNet.package.tag
            let end=$ExtendNet.package.end
            return data.replace(tag.regU,tag.init)
            .replace(end.regU,end.init)
        }

        /**
         * 打包
         */
        static encode(data)
        {
            let end=$ExtendNet.package.end
            try 
            {
                if(typeof data === 'object')
                {
                    data=JSON.stringify(data)
                }
                return [packages.escape(data),end.init].join('');
            } 
            catch (error) 
            {
                console.error('[jsonn]解析失败',data)
                return '';
            }
        }

        /**
         * 解包
         */
        static decode(data)
        {
            let end=$ExtendNet.package.end
            let arr=data.split(end.reg)
            let index=arr.length-1

            if(index===0)
            {
                this.$str+=data
            }
            else
            {
                if(this.$str)arr[0]=this.$str+arr[0]
                this.$str=arr[index]
            }
            arr.pop()

            let arrBack=[]
            for (let index = 0; index < arr.length; index++) 
            {
                let cur=arr[index]
                if(cur)arrBack.push(cur)
                arr[index]=packages.unescape(cur)
            }

            return arrBack
        }



        static reset()
        {
            this.$stat = null;
            this.$str = '';
            this.$len = 0;
			this.$datas = [];
        };


        static pong(tag)
        {
            if(tag)
            {
                if($ExtendNet.twHeartPrint)console.white(`[${this.tagName}客户端数据]------`,'心跳包');
                if(!$ExtendNet.twResponse)return
                this.request.sender($ExtendNet.heartTag);
                return;
            }
            else
            {
                this.request.write(new Buffer(['0x8A', '0x0']))
            }
        };
        
        

        /**
         * 解包
         */
        static decodeWsBack(data,tag)
        {
			if (!this.$stat || tag) 
			{
				var dataIndex = 2; //数据索引，因为第一个字节和第二个字节肯定不为数据，所以初始值为2
				var secondByte = data[1]; //代表masked位和可能是payloadLength位的第二个字节
				var hasMask = secondByte >= 128; //如果大于或等于128，说明masked位为1
				secondByte -= hasMask ? 128 : 0; //如果有掩码，需要将掩码那一位去掉
			
				var dataLength, maskedData;


				//如果为126，则后面16位长的数据为数据长度，如果为127，则后面64位长的数据为数据长度
				if (secondByte == 126) 
				{
                    dataIndex += 2;
                    dataLength = data.readUInt16BE(2);
				} 
				else if (secondByte == 127) 
				{
                    dataIndex += 8;
                    dataLength = data.readUInt32BE(2) + data.readUInt32BE(6);
				} 
				else 
				{
				    dataLength = secondByte;
				}

				//如果有掩码，则获取32位的二进制masking key，同时更新index
				if (hasMask) 
				{
                    maskedData = data.slice(dataIndex, dataIndex + 4);
                    dataIndex += 4;
				}
			

				this.$stat = {
					index: dataIndex,
					totalLength: dataLength,
					length: dataLength,
					maskedData: maskedData,
					fin:data[0] >> 7,
					opcode: data[0] & parseInt(1111, 2) //获取第一个字节的opcode位
                };
            
			} 
			else 
			{     
			    this.$stat.index = 0;
			}
        }

        /**
         * 解包拼接
         */
        static decodeWs(data,tag,arr=[])
        {
            let stat,result;
            packages.decodeWsBack.call(this,data,tag);
        
            if (!(stat = this.$stat)) return;
            
            //如果opcode为9，则发送pong响应，如果opcode为10则置pingtimes为0
            if (stat.opcode === 9) 
            {
                packages.pong.call(this);
                packages.reset.call(this);
                return;
            }
            else if(stat.opcode==8)
            {
                this.request.end(); 
                return;
            }
            else if(stat.opcode !==1)
            {
                packages.reset.call(this);
                return ;
            }

            this.$len+=(data.length-stat.index)

			this.$datas.push(data.slice(stat.index));
            
            stat.length -= (data.length - stat.index);
            //当长度为0，说明当前帧为最后帧,为负数说明本帧包含其他数据
            if (stat.length <= 0) 
            {
                let buf = Buffer.concat(this.$datas, stat.totalLength);

                if (stat.maskedData) 
                {
                    result = new Buffer(buf.length);
                    for (let i = 0, j = 0; i < buf.length; i++, j++) 
                    {
                        //对每个字节进行异或运算，masked是4个字节，所以%4，借此循环
                        result[j] = buf[i] ^ stat.maskedData[j % 4];
                    }
                }
                else 
                {
                    result = data.slice(stat.index, data.length);
                }

                let curs=result.toString()

                if(curs)arr.push(curs)
                
              
                packages.reset.call(this)

                if(stat.length<0)
                {
                    packages.decodeWs.call(this,data.slice(stat.index+stat.totalLength),true,arr)
                }
            }
            return arr
        }

        /**
         * ws封包
         */
		static encodeWs (frame)
		{
		  	var preBytes = [];
		  	var payBytes = Buffer.from(frame['Payload_data']);
		  	var dataLength = payBytes.length;
		
		  	preBytes.push((frame['FIN'] << 7) + frame['Opcode']);
		
		  	if (dataLength < 126)
		    	preBytes.push((frame['MASK'] << 7) + dataLength);
		 	else if (dataLength < Math.pow(2, 16))
			    preBytes.push(
			      (frame['MASK'] << 7) + 126, 
			      (dataLength & 0xFF00) >> 8,
			      dataLength & 0xFF
			    );
		  	else
			    preBytes.push(
			      (frame['MASK'] << 7) + 127,
			      0, 0, 0, 0,
			      (dataLength & 0xFF000000) >> 24,
			      (dataLength & 0xFF0000) >> 16,
			      (dataLength & 0xFF00) >> 8,
			      dataLength & 0xFF
				);
		 	preBytes = Buffer.from(preBytes);
			return Buffer.concat([preBytes, payBytes]);
		}  
        
    }
/*-------------------------------------------------------------------------------------------*/   
    
module.exports=packages;