// 协议栈模块
// 秒寻科技
// zt 2024-09-15

package ap

import (
	"encoding/binary"
	"errors"
	"ipsomc/module/ps/psmodel"
)

type Ap struct {
}

// 全局变量
var (
	s_crc_table = [16]uint16{0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef}
)

// AP层上行处理单元
func (obj *Ap) ApUl(dataList []byte, dataListLen *int) (*psmodel.PS_HEAD_T, *psmodel.PS_TAIL_T, error) {
	newLen := *dataListLen
	var wCrc uint16 = 0
	var psCrc uint16 = 0
	var psHeadModel *psmodel.PS_HEAD_T
	var psTailModel *psmodel.PS_TAIL_T
	var wStopIndex uint16 = 0

	//长度容错检查
	if newLen < psmodel.PS_FRAME_MIN_LEN {
		return nil, nil, errors.New("帧长度不合法")
	}

	//帧头帧尾检查
	if dataList[0] != psmodel.PS_AP_END_FLAG || dataList[newLen-1] != psmodel.PS_AP_END_FLAG {
		return nil, nil, errors.New("数据错误")
	}

	//逆向转义处理
	if err := obj.ApTransferReverse(dataList, &newLen); err != nil {
		return nil, nil, err
	}
	*dataListLen = newLen

	//解析数据到结构(协议头，协议尾)
	psHeadModel, psTailModel = obj.ApParseSlicToStruct(dataList, int32(newLen))

	//CRC校验
	psCrc = psTailModel.Crc //数据报文中的CRC校验码
	wStopIndex = uint16(newLen - 3)
	wCrc = obj.ApGenCrc16(dataList[1:wStopIndex], uint16(newLen), 0) //基于数据报文生成CRC校验码
	if wCrc != psCrc {
		return psHeadModel, psTailModel, errors.New("CRC校验错误")
	}

	return psHeadModel, psTailModel, nil
}

// 对输入数据实施逆向转义处理
// byData:待逆转义数据，返回参数
// pdwLen:数据长度，返回参数
func (obj *Ap) ApTransferReverse(byData []byte, pdwLen *int) error {
	outData := make([]byte, 0)
	wCounter := 0

	// 逆向转义处理
	for i := 1; i < (*pdwLen - 1); i++ {
		//处理0x5E和0x5D两个连续字符
		if byData[i] == 0x5E && byData[i+1] == 0x5D {
			outData = append(outData, 0x5E)
			i++
			wCounter++
		} else if byData[i] == 0x5E && byData[i+1] == 0x7D { //处理0x5E和0x7D两个连续字符
			outData = append(outData, 0x7E)
			i++
			wCounter++
		} else { //处理其它字符
			outData = append(outData, byData[i])
			wCounter++
		}
	}

	// 将临时数据拷贝回byData切片中
	byData = byData[:0]                 //清空切片
	byData = append(byData, 0x7E)       //保存帧头
	byData = append(byData, outData...) //保存数据
	byData = append(byData, 0x7E)       //保存帧尾

	*pdwLen = wCounter + 2

	return nil
}

// 将切片数据解析到结构体中
// dataList:数据切片
func (obj *Ap) ApParseSlicToStruct(dataList []byte, dwLen int32) (*psmodel.PS_HEAD_T, *psmodel.PS_TAIL_T) {
	var psHeadModel psmodel.PS_HEAD_T
	var psTailModel psmodel.PS_TAIL_T
	var wTailIndex uint16 = 0
	var wStopIndex uint16 = 0

	//AP层
	psHeadModel.StApHead.StartFlag = dataList[0] //协议头

	//VP层
	psHeadModel.StVpHead.ProjectID = int(binary.LittleEndian.Uint32(dataList[1:5])) //项目编号                       //项目编号
	psHeadModel.StVpHead.PacketNo = dataList[5]                                     //协议包号
	psHeadModel.StVpHead.DeviceID = int(binary.LittleEndian.Uint32(dataList[6:10])) //设备编号
	psHeadModel.StVpHead.VpFlag = dataList[10]                                      //VP层标识符
	psHeadModel.StVpHead.McpType = dataList[11]                                     //MCP层协议类型

	//MCP层
	psHeadModel.StMcpHead.Comd = dataList[12] //MCP命令标识符
	psHeadModel.StMcpHead.Resp = dataList[13] //MCP响应标识符

	////帧尾
	wTailIndex = uint16(dwLen - 3)
	wStopIndex = uint16(dwLen - 1)
	psTailModel.Crc = uint16(binary.LittleEndian.Uint16(dataList[wTailIndex:wStopIndex])) //CRC校验码
	psTailModel.StopFlag = dataList[wStopIndex]                                           //结束标识符

	return &psHeadModel, &psTailModel
}

// 生成CRC16校验码
// data:数据
// len:数据长度
// def_crc
func (obj *Ap) ApGenCrc16(data []byte, len uint16, def_crc uint16) uint16 {
	var crc uint16 = def_crc
	var crc_h4 uint8 = 0

	for _, v := range data {
		crc_h4 = (uint8)(crc >> 12)
		crc <<= 4
		crc ^= s_crc_table[crc_h4^(v>>4)]
		crc_h4 = (uint8)(crc >> 12)
		crc <<= 4
		crc ^= s_crc_table[crc_h4^(v&0x0f)]
	}

	return crc
}

// AP层下行处理单元
func (obj *Ap) ApDl(dataList []byte, dataListLen int) ([]byte, int, error) {
	newLen := dataListLen

	//长度容错检查
	if newLen < psmodel.PS_FRAME_MIN_LEN {
		return nil, 0, errors.New("帧长度不合法")
	}

	//帧头帧尾检查
	if dataList[0] != psmodel.PS_AP_END_FLAG || dataList[newLen-1] != psmodel.PS_AP_END_FLAG {
		return nil, 0, errors.New("数据错误")
	}

	//转义处理
	apFrame, err := obj.ApTransfer(dataList, &newLen)
	if err != nil {
		return nil, 0, err
	}

	return apFrame, newLen, nil
}

// 对输入数据实施转义处理
// byData:待逆转义数据，返回参数
// pdwLen:数据长度，返回参数
func (obj *Ap) ApTransfer(byData []byte, pdwLen *int) ([]byte, error) {
	outData := make([]byte, 0)

	//帧头
	outData = append(outData, 0x7E)

	// 转义处理
	for i := 1; i < (*pdwLen - 1); i++ {
		if byData[i] == 0x5E { //将0x5E转义成0x5E,0x5D
			outData = append(outData, 0x5E)
			outData = append(outData, 0x5D)
		} else if byData[i] == 0x7E { //将0x7E转义成0x5E,0x7D
			outData = append(outData, 0x5E)
			outData = append(outData, 0x7D)
		} else { //其它字符
			outData = append(outData, byData[i])
		}
	}

	//帧尾
	outData = append(outData, 0x7E) //保存帧头

	*pdwLen = len(byData) //队列长度

	return outData, nil
}
