/* vim:set ft=cpp ts=4 sw=4 sts=4 sta ai si cin bs=2: */
// ReceiveDataParse.cpp: implementation of the CReceiveDataParse class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ReceiveDataParse.h"

#include <winsock2.h>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CReceiveDataParse::CReceiveDataParse()
{
	m_dwRemainBufferSize = 0;
	m_tempBuffer = NULL;
	memset(&m_payloaddata, 0, sizeof(PAYLOAD));
}

CReceiveDataParse::~CReceiveDataParse()
{

}

/* 입력된 데이터를 가지고 Start, End code를 찾아 Parsing하는 함수
   return value : TRUE(남은 버퍼를 다시 Parsing해야한다.), FALSE(남은 버퍼를 다시 Parsing 하지 않아도 된다.)
   ParseData[OUT] : Start, End code를 찾아 Parsing된 데이터를 넘겨준다.
   pbyReceiveData[IN] : DVR에서 받은 데이터
   dwReceiveDataLength[IN] : pbyReceiveData의 크기

   *** pbyReceiveData, dwReceiveDataLenght를 입력하지 않으면 Start, End code를 찾고 남은 데이터 버퍼를 가지고
   다시 Parsing 한다.
*/
bool CReceiveDataParse::PacketParse(PARSE_DATA* ParseData, const BYTE *pbyReceiveData, DWORD dwReceiveDataLength)
{
	enum {MAX_FRAMEHEADER_SIZE = 1024};

	// PACKET_START_CODE(0xFB, 0xFB, 0xFB, 0xFC), PACKET_END_CODE(0xFB, 0xFB, 0xFB, 0xFD)
	const int MARKER_CODE_SIZE = 4;
	
	DWORD dwPacketLen;
	DWORD dwDataStartPoint = 0;

	if(dwReceiveDataLength > 0){
		memcpy(m_tempBuffer + m_dwRemainBufferSize, pbyReceiveData, dwReceiveDataLength);
		m_dwRemainBufferSize += dwReceiveDataLength;
	}

	if(m_dwRemainBufferSize > sizeof(PAYLOAD) + MARKER_CODE_SIZE)
	{
		for(DWORD i = 0 ; i < m_dwRemainBufferSize - MARKER_CODE_SIZE - sizeof(PAYLOAD); i++){
			/* StartCode를 찾았을 경우 */
			if(m_tempBuffer[i] == PACKET_FIRST_BYTE && m_tempBuffer[i+1] == PACKET_SECOND_BYTE &&
				m_tempBuffer[i+2] == PACKET_THIRD_BYTE && m_tempBuffer[i+3] == PACKET_START_BYTE)
			{
				memcpy(&m_payloaddata, m_tempBuffer + i + MARKER_CODE_SIZE, sizeof(PAYLOAD));
				dwDataStartPoint = i + MARKER_CODE_SIZE + sizeof(PAYLOAD);
				dwPacketLen = ntohl(m_payloaddata.dwPacketLen);
				m_dwTotalSize = dwPacketLen + MARKER_CODE_SIZE;

				if(m_dwTotalSize > ( MAX_PES_SIZE + MAX_FRAMEHEADER_SIZE))
				{
					/* DVR로부터 전송되는 패킷은 다음과 같다.
					*   SMAGIC(4) + PAYLOAD_HEADER(6) + FRAME_HEADER + PES_DATA(MAX_PES_SIZE) + EMAGIC(4)
					*   PAYLOAD_HEADER->dwPacketLen = FRAME_HEADER + PES_DATA 를 의미한다.
					* 따라서 m_dwTotalSize가 위 값보다 크다면 에러다. */
					TRACE(_T("TotalSize %u\n"), m_dwTotalSize);

					return FALSE;
				}

				if(m_dwTotalSize <= m_dwRemainBufferSize - dwDataStartPoint)
				{
					if(m_tempBuffer[dwDataStartPoint + dwPacketLen] == PACKET_FIRST_BYTE &&
						m_tempBuffer[dwDataStartPoint + dwPacketLen + 1] == PACKET_SECOND_BYTE &&
						m_tempBuffer[dwDataStartPoint + dwPacketLen + 2] == PACKET_THIRD_BYTE &&
						m_tempBuffer[dwDataStartPoint + dwPacketLen + 3] == PACKET_END_BYTE)
					{
        				ParseData->nDataInfo = m_payloaddata.nDataType;
        				ParseData->nDataSize = m_dwTotalSize - MARKER_CODE_SIZE;
						memcpy(ParseData->DataBuf, m_tempBuffer + dwDataStartPoint, ParseData->nDataSize);
						m_dwRemainBufferSize = m_dwRemainBufferSize - (dwDataStartPoint + ParseData->nDataSize);
						memmove(m_tempBuffer, m_tempBuffer + dwDataStartPoint + ParseData->nDataSize, m_dwRemainBufferSize);
						return TRUE;
					}
				}
			}
		}	// end for
	}

	return FALSE;
}

/* Parsing할 메모리를 할당하고 초기화 하는 함수*/
void CReceiveDataParse::InitParse()
{
	m_tempBuffer = new BYTE[MAX_PES_SIZE];
}

/* 할당된 메모리를 삭제하는 함수*/
void CReceiveDataParse::DestroyParse()
{
	if(m_tempBuffer){
		delete m_tempBuffer;
		m_tempBuffer = NULL;
	}
}

/*  ClientID를 반환하는 함수
    return value : Payload 구조체의 Client ID 값
*/
int CReceiveDataParse::GetClientID()
{
	return m_payloaddata.nClientID;
}
