/**
 *
 * @author    seagle
 * @date      2025-6-11
 * @Description
 *   TLV recv、check、package and response
 */
#include"TcPch.h"
#pragma hdrstop
#include"TlvSession.h"
#include"string.h"
#include"CRemoteLog.h"
#include"pmc_types.h"
#include MA_STR(MA_CONTACT(TASK_IO_MODULE,SUFFIX_SERVICES))
static unsigned short ntoh_us(unsigned short num) {
	if (USE_NET_SORT) {
		//网络字节序，找不到现成函数，自己转一下吧
		unsigned char tmp[2];
		tmp[0] = ((unsigned char*)&num)[1];
		tmp[1] = ((unsigned char*)&num)[0];
		return *(unsigned short *)tmp;
	}
	else {
		//主机字节顺序
		return num;
	}
}
static unsigned short hton_us(unsigned short num) {
	return ntoh_us(num);
}
void TlvData::getDataBytes(char* buffer, int begin, int length) {
	
	begin = begin % sizeof(data);
	if ((int)(begin + length) > sizeof(data)) {
		memcpy(buffer, data + begin, sizeof(data) - begin);
		memcpy(buffer + sizeof(data) - begin, data, length - (sizeof(data)- begin));
	}
	else {
		memcpy(buffer, data + begin, length);
	}
	
}
void TlvData::setDataBytes(char* buffer, int begin, int length) {

	begin = begin % sizeof(data);
	if ((int)(begin + length) > sizeof(data)) {
		memcpy( data + begin, buffer, sizeof(data) - begin);
		memcpy(data, buffer + sizeof(data) - begin, length - (sizeof(data) - begin));
	}
	else {
		memcpy( data + begin, buffer, length);
	}

}
int TlvData::popRawData(char* buffer)
{
	if (recordCount==0) {
		return 0;
	}
	getDataBytes(buffer, head, 2);
	int length = ntoh_us(*(unsigned short*)buffer);
	getDataBytes(buffer+2, head+2, length);
	head = (head + length + 2) % sizeof(data);
	recordCount--;
	if (recordCount <=0) {
		recordCount = 0;
		tail = free;
	}

	return length+2;
}
int TlvData::pop(char* buffer)
{
	while (TRUE) {
		if (recordCount==0) {
			return 0;
		}
		char tmp[2];
		getDataBytes(tmp, head, 2);
		int length = ntoh_us(*(unsigned short*)tmp);
		if (length <= 2) {
			getDataBytes(tmp, head + 2, length);
			head = (head + length + 2) % sizeof(data);
			recordCount--;
			if (recordCount <= 0) {
				recordCount = 0;
				tail = free;
			}
			//TODO
			continue;
		}
		getDataBytes(buffer, head + 4, length - 2);
		head = (head + length + 2) % sizeof(data);
		recordCount--;
		if (recordCount <= 0) {
			recordCount = 0;
			tail = free;
		}
		return length -2;
	}
}
void TlvData::pushRawData(char* buffer, int length)
{
	int dataFreeSpaceSize = 0;
	if (head < free) {
		dataFreeSpaceSize = sizeof(data) - free + head;
	}
	else if(head>free) {
		dataFreeSpaceSize = head - free;
	}
	else if (recordCount > 0) {
		dataFreeSpaceSize = 0;
	}
	else {
		dataFreeSpaceSize = sizeof(data);
	}
	if (length > dataFreeSpaceSize) {
		logger->error("Push raw data but not enough space[%d]<[%d]", dataFreeSpaceSize,length);
		return;
	}
	setDataBytes(buffer, free, length);
	tail = free;
	free = (free + length) % sizeof(data);
	recordCount++;
	 

}
void TlvData::push(char* buffer, int length)
{
	int dataFreeSpaceSize = 0;
	if (head < free) {
		dataFreeSpaceSize = sizeof(data) - free + head;
	}
	else if (head > free) {
		dataFreeSpaceSize = head - free;
	}
	else if (recordCount > 0) {
		dataFreeSpaceSize = 0;
	}
	else {
		dataFreeSpaceSize = sizeof(data);
	}
	if (length+4 > dataFreeSpaceSize) {
		logger->error("Push data but not enough space[%d]<[%d]", dataFreeSpaceSize,length+4);
		return;
	}
	char headBuffer[4];
	
	*(unsigned short*)headBuffer = hton_us(length + 2);
	
	headBuffer[2] = PACKAGE_MSGTYPE_ENQ;
	headBuffer[3] = (msgId++) % 128;
	setDataBytes(headBuffer, free, 4);
	setDataBytes(buffer, free+ 4,length);
	tail = free;
	free = (free + length+4) % sizeof(data);
	recordCount++;
}

int TlvData::getRecordCount()
{
	return recordCount;
}
void TlvData::clear()
{
	head = tail = free = 0;
	recordCount = 0;
}

void TlvSession::recv(unsigned long  socketId, const char* buffer, const int length)
{
	//logger->info("[%d][%d,%d,%d,%d][%d]", socketId, buffer[0], buffer[1], buffer[2], buffer[3], length);
	if(this->socketId > 0 && this->socketId != socketId) {
		//断线重连了
		this->clear();
	}
	this->socketId = socketId;
	
	int freeSpaceSize = sizeof(recvBuffer) - recvLength;
	if (length > freeSpaceSize) {
		logger->error("Recv package too large[%d+%d]", recvLength,length);
		recvTotalLength = recvLength = 0;
		return;
	}
	if (length == 0) {
		recvTotalLength = recvLength = 0;
		return;
	}
	if (recvLength == 0) {
		//first package
		if (length ==1) {
			//至少要接收2个字节才好处理，1个字节的情况要等下次
			recvBuffer[recvLength] = buffer[0];
			recvLength++;
			recvTotalLength = 0;
			return;
		}
		//length>1
		recvTotalLength = ntoh_us(*(unsigned short*)buffer) + 2;
	}
	else if (recvLength == 1) {
		//之前只接收了1个字符
		recvBuffer[recvLength] = buffer[0];
		recvLength++;
		recvTotalLength = ntoh_us(*(unsigned short*)recvBuffer) + 2;
		recv(socketId, buffer + 1, length - 1);
		return;
	}
	//到此recvTotalLength肯定大于0了,且recvLength为已到达并缓冲的报文长度
	if (recvTotalLength <= length + recvLength) {
		//至少一个完整报文
		memcpy(recvBuffer + recvLength, buffer, recvTotalLength - recvLength);
		if (recvBuffer[PACKAGE_MSGTYPE_POSITION] != PACKAGE_MSGTYPE_ENQ) {
			if (recvBuffer[PACKAGE_MSGTYPE_POSITION] != PACKAGE_MSGTYPE_ACK) {
				logger->error("Recv invalid package,msgtype[0x%x]", recvBuffer[PACKAGE_MSGTYPE_POSITION]);
			}
			recvTotalLength = recvLength = 0;
			return;
		}
		if (PACKAGE_TAIL_CHECK) {
			if (memcmp(recvBuffer + recvTotalLength + PACKAGE_TAIL_FLAG_POSITION, PACKAGE_TAIL_FLAG, PACKAGE_TAIL_FLAG_LENGTH) != 0) {
				logger->error("Recv invalid package,tail[0x%x,0x%x]", recvBuffer[recvTotalLength + PACKAGE_TAIL_FLAG_POSITION], recvBuffer[recvTotalLength + PACKAGE_TAIL_FLAG_POSITION] + 1);
				recvTotalLength = recvLength = 0;
				return;
			}

		}
		recvData.pushRawData(recvBuffer, recvTotalLength);
		char response[4];
		response[0] = 0x00;
		response[1] = 0x02;
		response[2] = PACKAGE_MSGTYPE_ACK;
		response[3] = recvBuffer[3];
		sendData.pushRawData(response, 4);
		if (recvTotalLength  < length + recvLength) {
			int bakRecvTotalLength = recvTotalLength;
			int bakRecvLength = recvLength;
			recvTotalLength = recvLength = 0;
			//报文末尾粘连后续报文
			recv(socketId, buffer + bakRecvTotalLength  - bakRecvLength, length - (bakRecvTotalLength  - bakRecvLength));
			return;
		}
		else {
			recvTotalLength = recvLength = 0;
		}
		
	}
	else {
		memcpy(recvBuffer + recvLength, buffer, length);
		recvLength += length;
		return;
	}
	
	
}
void TlvSession::send() {
	while (TRUE) {
		if (sendLength == 0 && sendTotalLength == 0) {
			sendTotalLength = sendData.popRawData(sendBuffer);
		}
		if (sendTotalLength <= 0) {
			break;
		}
		if (sendLength < sendTotalLength) {
			unsigned long onceLength = 0;
			if (sockSend(socketId, sendTotalLength - sendLength, sendBuffer + sendLength, onceLength) != 0) {
				sendLength = 0;
				break;
			}
			if (onceLength < sendTotalLength - sendLength) {
				//send uncompleted
				sendLength += onceLength;
				break;
			}
			sendTotalLength = sendLength = 0;			
		}
	}
}


void TlvSession::clear()
{
	recvTotalLength = recvLength = sendTotalLength = sendLength = 0;
	sendData.clear();
	recvData.clear();
}

int TlvSession::sockSend(unsigned long socketId, unsigned long nData, void* pData, unsigned long& nSendData)
{
	//TODO:Please implement this function
	MA_CONTACT(C, TASK_IO_MODULE)* module = (MA_CONTACT(C, TASK_IO_MODULE) * )ioModule;
	return module->SendClientData(socketId, nData, pData, nSendData);
		 
}
