//const unsigned char MSG_SUBSCRIPTION_REQ            = 0x20;
/************行情协议格式************************************
下标  标识	        类型	字节数	内容	说明
0    HeadTag	    byte	1	0xFF	头标记
1    Length	        uint	4		包总长度
4    TypeMain	    byte	1		大类
6    TypeSecond	    []byte	2		小类
8    SerialNumber	uint	4		通讯报文序号
12   Mode	        byte	1		内容类型，0, 自定义格式,没什么用
13   Version	    byte	1		版本号
     数据体			业务结构体，自定义格式
     FootTag	     byte	1	0x00	尾标记

     数据体前,包头长度=14, 空包长度=15
     行情订阅数据体格式
14   accountid       []byte  8       账户id(loginid) bigEnd
22   token           []byte  64      令牌
86   goodscount      uint    4       商品数量  bigEnd
     repeated{
        istatus      byte    1       订阅状态
        exchangeid   byte    1       交易所id
        goodscode    []byte  64      商品代码
     }
*******************************************************/

package packet

import (
	"fmt"
	"io"
	"mtp20access/utils"
	"net"
)

// MiQuotePacket 行情协议结构体
type MiQuotePacket struct {
	Length    uint32
	BigType   byte
	SmallType uint16
	SerialNum uint32
	Mode      byte
	Msg       []byte
	OriMsg    []byte // 原始包数据
}

// EnPack 重新打包数据
func (r *MiQuotePacket) EnPack() []byte {
	r.Length = uint32(len(r.Msg)) + 15                           // 空包长度15
	buf := make([]byte, 0)                                       // 缓存
	buf = append(buf, byte(0xFF))                                // HeadTag
	buf = append(buf, utils.UintTobytesBigEnd(r.Length)...)      // Length
	buf = append(buf, r.BigType)                                 // TypeMain
	buf = append(buf, utils.Uint16TobytesBigEnd(r.SmallType)...) // TypeSecond
	buf = append(buf, utils.UintTobytesBigEnd(r.SerialNum)...)   // SerialNumber
	buf = append(buf, byte(0))                                   // Mode
	buf = append(buf, byte(0))                                   // version
	buf = append(buf, r.Msg...)                                  // 数据体body
	buf = append(buf, byte(0))                                   // FootTag

	return buf
}

func (r *MiQuotePacket) HeaderLen() uint32 {
	return 14
}

// BodyLen 数据体长度, 含FootTag
func (r *MiQuotePacket) BodyLen() uint32 {
	return r.Length - 14
}

// UnPackHead 解包头
func (r *MiQuotePacket) UnPackHead(buf []byte) error {
	if len(buf) < 14 {
		return fmt.Errorf("行情包头长度错误")
	}

	if buf[0] != 0xFF {
		return fmt.Errorf("行情包头长度错误")
	}

	r.Length = utils.BytesBigEndToUint32(buf[1:5])
	r.BigType = buf[5]
	r.SmallType = utils.BytesBigEndToUint16(buf[6:8])
	r.SerialNum = utils.BytesBigEndToUint32(buf[8:12])
	r.Mode = buf[12]

	return nil
}

// SetOriMsg 保存原始数据包
func (r *MiQuotePacket) SetOriMsg(arg ...[]byte) {
	if r.OriMsg == nil {
		r.OriMsg = make([]byte, 0)
	}
	for i := range arg {
		r.OriMsg = append(r.OriMsg, arg[i]...)
	}
}

// ReadMessage 从指定tcp链接读取一个协议包
// @返回值 []byte 未解包的原始数据包, 如果需获取业务数据内容,
// 请调用UnPack方法后取成员变量 Data 的内容
func (r *MiQuotePacket) ReadMessage(conn *net.Conn) ([]byte, error) {
	r.OriMsg = make([]byte, 0)
	if conn == nil {
		return r.OriMsg, fmt.Errorf("当前未连接行情发布服务")
	}

	headerBuf := make([]byte, r.HeaderLen())
	nRead, err := io.ReadFull(*conn, headerBuf)
	if err != nil || nRead != len(headerBuf) {
		return r.OriMsg, fmt.Errorf("读取行情包头错误，可能连接已关闭:%v", err)
	}

	err = r.UnPackHead(headerBuf)
	if err != nil {
		return r.OriMsg, err
	}

	dataBuf := make([]byte, r.BodyLen())
	nRead, err = io.ReadFull(*conn, dataBuf)
	if err != nil || nRead != len(dataBuf) {
		return r.OriMsg, fmt.Errorf("读取行情包数据错误，可能连接已关闭:%v", err)
	}

	r.SetOriMsg(headerBuf, dataBuf)
	return r.OriMsg, nil
}

// HeaderInfo 头部信息, 功能号、sid、流水号、长度等
func (r *MiQuotePacket) HeaderInfo() string {
	return fmt.Sprintf("bigtype[%d] smalltype[%d] serial[%d] iLen:%d",
		r.BigType, r.SmallType, r.SerialNum, r.Length)
}
