#ifndef __FRAME_RECIEVE_H
#define __FRAME_RECIEVE_H

#include "framelib/basetype.h"

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <math.h>

#define ROUND_INT8(v) ((INT8)((floor)(v+0.5)))
#define ROUND_UINT8(v) ((UINT8)((floor)(v+0.5)))
#define ROUND_INT16(v) ((INT16)((floor)(v+0.5)))
#define ROUND_UINT16(v) ((UINT16)((floor)(v+0.5)))
#define ROUND_INT32(v) ((INT32)((floor)(v+0.5)))
#define ROUND_UINT32(v) ((UINT32)((floor)(v+0.5)))

const BYTE FLAG_PLAT = 0xE0;
const BYTE PLAT_Manual = 0x00 << 5;
const BYTE PLAT_Auto = 0x01 << 5;
const BYTE PLAT_Locking = 0x02 << 5;
const BYTE PLAT_Leading = 0x03 << 5;
const BYTE PLAT_Scaning = 0x04 << 5;
const BYTE PLAT_Reseting = 0x05 << 5;
const BYTE PLAT_Init = 0x06 << 5;

const BYTE FLAG_TRACKER = 0x1C;
const BYTE TRACKER_Normal = 0x00 << 2;
const BYTE TRACKER_Error = 0x01 << 2;
const BYTE TRACKER_Lost = 0x02 << 2;
const BYTE TRACKER_Corr = 0x03 << 2;
const BYTE TRACKER_GBlack = 0x04 << 2;
const BYTE TRACKER_GWhite = 0x05 << 2;
const BYTE TRACKER_ShowFreeze = 0x06 << 2;
const BYTE TRACKER_Freeze = 0x07 << 2;

const BYTE FLAG_LIFTER = 0x03;
const BYTE LIFTER_Top = 0x00;
const BYTE LIFTER_Bottom = 0x01;
const BYTE LIFTER_Uping = 0x02;
const BYTE LIFTER_Downing = 0x03;

const BYTE FLAG_EO = 0xC0;
const BYTE EO_Working = 0x00 << 6;
const BYTE EO_Error = 0x01 << 6;
const BYTE EO_Heating = 0x02 << 6;
const BYTE EO_Heated = 0x03 << 6;

const BYTE FLAG_PAYLOAD = 0x20;
const BYTE PAYLOAD_EO = 0x00 << 5;
const BYTE PAYLOAD_HW = 0x01 << 5;

const BYTE FLAG_HW = 0x18;
const BYTE HW_Working = 0x00 << 3;
const BYTE HW_Error = 0x01 << 3;
const BYTE HW_Manual = 0x02 << 3;
const BYTE HW_Auto = 0x03 << 3;

const BYTE FLAG_LASER = 0x07;
const BYTE LASER_Normal = 0x00;
const BYTE LASER_Error = 0x01;
const BYTE LASER_Close = 0x02;
const BYTE LASER_Standby = 0x03;
const BYTE LASER_On = 0x04;
const BYTE LASER_Off = 0x05;

const double AngRatiode = 360.0 / 65535.0;
const double AngRatioen = 65535.0 / 360.0;

typedef enum { ftFJu,   				   //���ɻ�ƽ̨����Э��У��
	ftFJd,  					//���ɻ�ƽ̨����Э��У��
	ftEOu,  					//���ȶ�ƽ̨����Э��У��
	ftEOd,  					//���ȶ�ƽ̨����Э��У��
	ftCJu,  					//���������������
	ftCJd,  					//���������������
	ftQBu,  					//���鱨����Э��У��
	ftQBd,  					//���鱨����Э��У��
	ftCKd,  					//�������������
	ftSFu, ftSFd, ftFKu, ftFKd, ftEOGCSu, ftEOSBu, ftTXd, ftTXd_8B, ftTXd_8B_SM, ftTXd_8B_SAR,				//ͼ�񸴽�����Э��
	ftEOU_8B,
	ftMIMUu,			//MIMU������������
	ftMIMUd,			//MIMU������������
	ftGPSu, 			//GPS������������
	ftGPSd, 			//GPS������������
	ftBDu,  			//����������������
	ftBDd,  			//����������������
	ftPOWERu,   //�ɿؼ�������͵���Դ������������֡
	ftPOWERd,   //��Դ���������͵��ɿؼ����������֡
	ftOILu, 			//�ɿؼ�������͵�����������������֡
	ftOILd, 			//�������������͵��ɿؼ����������֡
	ftMAGu, 			//�ɿؼ�������͵��������̵�����֡
	ftMAGd, 			//�������̷��͵��ɿؼ����������֡
	ftGKu,  			//�ɿؼ�������͵��߶�/���ٴ�����������֡
	ftGKd,  			//�߶�/���ٴ��������͵��ɿؼ����������֡
	ftNone  					//�Զ���У��
}   			TFrameType;

inline double RoundMax(double v, double vmax)
{
	return fmod(v, vmax);
	//	while (v < 0)
	//		v += vmax;
	//	while (v > vmax)
	//		v -= vmax;
	//	return v;
}

inline void ChangeFileNameExt(char *name, const char *ext)
{
	char *p = strrchr(name, '.');
	if(p)	*(p+1) = 0;
	strcat(name, ext);
}

//ѭ����������
class CBufferLoop {
private:
	int FSize;  						//��������С
	int FStart; 						//��Ч����ͷ
	int FEnd;   						//��Ч����β
	int FLength;						//��Ч���ݳ���
	BYTE* FBuffer;						//��������ַ
protected:
	INT16 Append(const unsigned char* Src, const UINT32 alen)
	{
		INT16 len = (alen > (UINT32) FSize) ? FSize : (INT16) alen;
		assert(len > 0);
		//����ʣ��ռ䲻��Length
		if ((len + FLength) >= FSize)
			len = FSize - FLength;
		if ((len + FEnd) >= FSize) {
			//���������ݿ�󲿿ռ䲻��Length�������ݿ��Ƶ������׵�ַ
			memcpy(FBuffer, FBuffer + FStart, FLength);
			FStart = 0;
			FEnd = FLength;
		}
		memcpy(FBuffer + FEnd, Src, len);
		FEnd += len;
		FLength += len;
		return len;
	}
	void Drop(const UINT16 len)
	{
		assert(len > 0);
		if (len > FLength) {
			FStart = 0;
			FEnd = 0;
			FLength = 0;
		} else {
			FStart += len;
			FLength -= len;
		}
	}
	int Size(){return FSize;}
	int Length(){return FLength;}
public:
	CBufferLoop() : FSize(1000), FStart(0), FEnd(0), FLength(0), FBuffer(0)
	{
		FBuffer = new unsigned char[FSize];
		memset(FBuffer, 0, FSize);
	};
	CBufferLoop(const CBufferLoop& abl)
		: FSize(abl.FSize), FStart(abl.FStart), FEnd(abl.FEnd),
		FLength(abl.FLength), FBuffer(0)
	{
		FBuffer = new unsigned char[FSize];
		memcpy(FBuffer, abl.FBuffer, FSize);
	}
	virtual ~CBufferLoop(){
		delete[] FBuffer;
		FBuffer = 0;
	}
	CBufferLoop& operator=(const CBufferLoop& abl)
	{
		if (this == &abl)
			return *this;   				 // ������17
		if (FBuffer)
			delete[] FBuffer;
		FSize = abl.FSize;
		FStart = abl.FStart;
		FEnd = abl.FEnd;
		FLength = abl.FLength;
		FBuffer = new unsigned char[FSize];
		memcpy(FBuffer, abl.FBuffer, FSize);
		return *this;
	}
	BYTE* const Addr()	{return FBuffer + FStart;}
	void Reset()
	{
		memset(FBuffer, 0, FSize);
		FStart = 0;
		FEnd = 0;
		FLength = 0;
	}
};

class CSimpleCriticalSection {
private:
	CRITICAL_SECTION FSection;
public:
	CSimpleCriticalSection(){InitializeCriticalSection(&FSection);}
	virtual ~CSimpleCriticalSection(){DeleteCriticalSection(&FSection);}
	void Enter(){EnterCriticalSection(&FSection);}
	void Leave(){LeaveCriticalSection(&FSection);}
};

//�����¼��ص���������
class CFrameAbstract;
typedef void (CALLBACK *FLDropBYTECALLBACK)(CFrameAbstract* frm, UINT16 Count);
typedef void (CALLBACK *FLDropFrameCALLBACK)(CFrameAbstract* frm, UINT16 Count);
typedef void (CALLBACK *FLNotCheckCALLBACK)(CFrameAbstract* frm);
typedef void (CALLBACK *FLCheckCALLBACK)(CFrameAbstract* frm);

//����֡��֡������������
class CFrameAbstract : public CBufferLoop {
public:
	CFrameAbstract() :
		  FrameLength(32), 
		  HeadLength(2),
		  CheckLength(1), 
		  CheckPos(31), 
		  FrameType(ftNone),
		  bphrasing(FALSE),
		  bFileOpen(FALSE),
		  nFlushCount(0), 
		  cs(new CSimpleCriticalSection()),
		  hFileOrg(NULL),
		  hFileCheck(NULL), 
		  hFileNotCheck(NULL),
		  funcDropBYTE(NULL),
		  funcDropFrame(NULL), 
		  funcNotCheck(NULL), 
		  funcCheck(NULL),
		  CountBYTEAll(0),
		  CountBYTEDrop(0),
		  CountFrameAll(0),
		  CountFrameCheck(0),
		  CountFrameNotCheck(0),
		  CountFrameDrop(0),
		  funcDropBYTEParam(NULL), 
		  funcDropFrameParam(NULL), 
		  funcNotCheckParam(NULL), 
		  funcCheckParam(NULL)
	  {};
	  virtual ~CFrameAbstract(){
		  funcDropBYTE = NULL;
		  funcDropFrame = NULL;
		  funcNotCheck = NULL;
		  funcCheck = NULL;
		  funcDropBYTEParam = NULL;
		  funcDropFrameParam = NULL;
		  funcNotCheckParam = NULL;
		  funcCheckParam = NULL;
		  while (TRUE == bphrasing){
			  Sleep(100);
		  }
		  if(bFileOpen){
			  fclose(hFileOrg);
			  fclose(hFileCheck);
			  fclose(hFileNotCheck);
			  bFileOpen = FALSE;
		  }
		  delete cs;
	  }

protected:
	UINT16 FrameLength; 		   //֡��
	UINT16 HeadLength;  		   //֡ͷ����
	UINT16 CheckLength; 		   //֡�ڱ���У���ֽڵĸ���
	UINT16 CheckPos;			   //֡�ڱ���У���ֽڵ�λ��
	TFrameType FrameType;			//֡��ʽ����
public:
	char Name[20];
	BYTE Head[12];


	TFrameType GetFrameType(){return FrameType;}
	UINT16 GetFrameLength(){return FrameLength;}
	UINT16 GetHeadLength(){return HeadLength;}
private:
	BOOL bphrasing;
	BOOL bFileOpen;
	INT32 nFlushCount;
	CSimpleCriticalSection* cs;

	char strModuleName[1024];
	char strAppPath[1024];
public:
	char strDataPath[1024];
protected:
	char strDataName[1024];
	FILE * hFileOrg;
	FILE * hFileCheck;
	FILE * hFileNotCheck;

	virtual BOOL FullFrame()
	{
		int HeaderPos, HeaderPos2;
		HeaderPos = FindHead(0, Length() - HeadLength);
		if (0 == HeaderPos){
			//֡ͷ����ǰ��
			if (OnCheck()){
				DoCheck();
			}
			else //У��ûͨ��
			{
				HeaderPos2 = FindHead(HeadLength, Length() - HeadLength);
				if ((HeaderPos2 >= 0) && (HeaderPos2 < FrameLength))
				{
					DoDropFrame((UINT16) HeaderPos2);
				}
				else if (HeaderPos2 < 0) 
				{
					if (Length() <= FrameLength + (HeadLength - 1)) 
					{
						if (HeadLength == 1)
							DoNotCheck();
						else 
						{
							BYTE* p = Addr();
							if (p[FrameLength - (HeadLength - 1)] != Head[0])
								DoNotCheck();
							else
								return TRUE;
						}
					} else
						DoNotCheck();
				}
				else
				{
					DoNotCheck();
				}
			}
		} else if (HeaderPos < 0) {
			//û�ҵ�֡ͷ
			DoDropBYTE((UINT16) (FrameLength - HeadLength));
		} else {
			//����֡ͷǰ������
			DoDropBYTE((UINT16) HeaderPos);
		}
		return FALSE;
	}
	void DoCheck()
	{
		assert(FrameLength > 0);
		++CountFrameAll;
		++CountFrameCheck;
		OnDataCheck();
		Drop(FrameLength);
	}
	void DoNotCheck()
	{
		assert(FrameLength > 0);
		++CountFrameAll;
		CountBYTEDrop += FrameLength;
		++CountFrameNotCheck;
		OnDataNotCheck();
		Drop(FrameLength);
	}
	void DoDropFrame(const UINT16 Count)
	{
		assert(Count > 0);
		++CountFrameAll;
		CountBYTEDrop += Count;
		++CountFrameDrop;
		OnDataDropFrame(Count);
		Drop(Count);
	}
	void DoDropBYTE(const UINT16 Count)
	{
		assert(Count > 0);
		CountBYTEDrop += Count;
		OnDataDropBYTE(Count);
		Drop(Count);
	}
	int FindHead(int Start, const int Length)
	{
		assert((Start >= 0) && (Length > 0));
		BYTE* p = Addr() + Start;
		while (Start < Length) {
			if (memcmp(p, Head, HeadLength) == 0)
				return Start;
			++p;
			++Start;
		}
		return -1;
	}
	virtual BOOL OnCheck() 											 //֡У�麯��
	{
		BYTE* p = Addr();
		struCHECK ck=CheckCRC(p);
		if (1 == CheckLength)
		{
			return (ck.C0== p[CheckPos]) ? TRUE : FALSE;
		}
		else if (2 == CheckLength)
		{
			return ((p[CheckPos]==ck.C0)&&(p[CheckPos+1]==ck.C1));
		}
		else
		{
			return false;
		}
	}

protected:
	FLDropBYTECALLBACK funcDropBYTE;
	FLDropFrameCALLBACK funcDropFrame;
	FLNotCheckCALLBACK funcNotCheck;
	FLCheckCALLBACK funcCheck;

	INT32 CountBYTEAll; 												  //���յ���ȫ���ֽ���
	INT32 CountBYTEDrop;												  //�������ֽ���
	INT32 CountFrameAll;												  //ȫ��֡����
	INT32 CountFrameCheck;  											  //��Ч֡����
	INT32 CountFrameNotCheck;   										  //У�����֡����
	INT32 CountFrameDrop;   											  //��֡����
	virtual void OnDataDropBYTE(const UINT16 Count)	 //��Ч�ֽڶ��¼����������û����б��ƴ�������
	{
		if (funcDropBYTE != NULL)	funcDropBYTE(this, Count);
	}
	virtual void OnDataDropFrame(const UINT16 Count)    //��֡�¼����������û����б��ƴ�������
	{
		if (funcDropFrame != NULL)	funcDropFrame(this, Count);
	}
	virtual void OnDataNotCheck()  					 //֡У����¼����������û����б��ƴ�������
	{
		//Decode();
		if (funcNotCheck != NULL)	funcNotCheck(this);
		//Distribute();
		//Show();
		if(bFileOpen)	fwrite(Addr(), FrameLength, 1, hFileNotCheck);
	}
	virtual void OnDataCheck()					 //��Ч֡�¼����������û����б��ƴ�������
	{
		Decode();
		if (funcCheck != NULL)	funcCheck(this);
		Distribute();
		Show();
		if(bFileOpen)	fwrite(Addr(), FrameLength, 1, hFileCheck);
	}

public:
	UINT32 funcDropBYTEParam;
	UINT32 funcDropFrameParam;
	UINT32 funcNotCheckParam;
	UINT32 funcCheckParam;
	void SetDropBYTECallback(FLDropBYTECALLBACK fun, UINT32 Param = 0){		funcDropBYTE = fun;		funcDropBYTEParam = Param;}
	void SetDropFrameCallback(FLDropFrameCALLBACK fun, UINT32 Param = 0){	funcDropFrame = fun;	funcDropFrameParam = Param;}
	void SetNotCheckCallback(FLNotCheckCALLBACK fun, UINT32 Param = 0){		funcNotCheck = fun;		funcNotCheckParam = Param;}
	void SetCheckCallback(FLCheckCALLBACK fun, UINT32 Param = 0){			funcCheck = fun;		funcCheckParam = Param;}
	void SetSaveStatus(BOOL IsSave, const char *name = NULL)
	{
		if(IsSave){
			GetModuleFileName(GetModuleHandle(NULL), strModuleName, 1024);
			char *p = strrchr(strModuleName, '\\');
			if(p)		strncpy(strAppPath, strModuleName, p - strModuleName);
			else		strcpy(strAppPath, strModuleName);

			time_t ltime;
			struct tm *t;
			time( &ltime );
			t = localtime( &ltime );

			sprintf(strDataPath, "%s\\RecordOrg-%04d%02d%02d", strAppPath, t->tm_year, t->tm_mon, t->tm_mday);
			char temp[1024];
			sprintf(temp, "%04d%02d%02d %02d%02d%02d", t->tm_year + 1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
			CreateDirectory((LPCSTR)strDataPath, NULL);

			if(name == NULL){
				sprintf(strDataName, "%s\\%s-%s.dat", strDataPath, temp, Name);
			}
			else{
				sprintf(strDataName, "%s\\%s-%s.dat", strDataPath, temp, name);
			}

			if((hFileOrg = fopen(strDataName, "wb")) != NULL){
				strcpy(temp, strDataName);
				ChangeFileNameExt(temp,"chk");
				if((hFileCheck = fopen(temp, "wb")) != NULL){
					strcpy(temp, strDataName);
					ChangeFileNameExt(temp,"err");
					if((hFileNotCheck = fopen(temp, "wb")) != NULL){
						bFileOpen = TRUE;
					}
					else{
						fclose(hFileCheck);
						fclose(hFileOrg);
					}
					bFileOpen = TRUE;
				}
				else{
					fclose(hFileOrg);
				}
			}
		}
		else{
			if(bFileOpen){
				fclose(hFileOrg);
				fclose(hFileCheck);
				fclose(hFileNotCheck);
				bFileOpen = FALSE;
			}
		}
	}

	void ResetCount()
	{
		//���ڼ�������
		CountBYTEAll = 0L;
		CountBYTEDrop = 0L;
		CountFrameAll = 0L;
		CountFrameCheck = 0L;
		CountFrameNotCheck = 0L;
		CountFrameDrop = 0L;
	}
	void Phrase(const BYTE* Src, const UINT32 Count)
	{
		cs->Enter();
		int ReadCount;
		UINT32 LeftCount = Count;
		const BYTE* psrc = Src;
		bphrasing = TRUE;
		while (LeftCount > 0) 
		{
			ReadCount = Append(psrc, LeftCount);
			psrc += ReadCount;
			LeftCount -= ReadCount;
			CountBYTEAll += ReadCount;
			while (Length() >= FrameLength)
				if (FullFrame())
					break;
		}
		try{
			if(bFileOpen)
			{
				fwrite(Src, Count, 1, hFileOrg);
				if((CountBYTEAll - nFlushCount) > 40960)
				{
					fflush(hFileOrg);
					fflush(hFileCheck);
					fflush(hFileNotCheck);
					nFlushCount = CountBYTEAll;
				}
			}
		}
		catch (...) 
		{
			cs->Leave();
			bphrasing = FALSE;
		}
		cs->Leave();
		bphrasing = FALSE;
	}
	INT32 GetCountBYTEAll(){return CountBYTEAll;}
	INT32 GetCountBYTEDrop(){return CountBYTEDrop;}
	INT32 GetCountFrameAll(){return CountFrameAll;}
	INT32 GetCountFrameCheck(){return CountFrameCheck;}
	INT32 GetCountFrameNotCheck(){return CountFrameNotCheck;}
	INT32 GetCountFrameDrop(){return CountFrameDrop;}
	//output
protected:
	virtual void FrameCrc(BYTE* p)
	{
		struCHECK ck=CheckCRC(p);
		if (CheckLength==1)
		{
			p[CheckPos]=ck.C0;
		}
		if (CheckLength==2)
		{
			p[CheckPos] = ck.C0;
			p[CheckPos+1]=ck.C1;
		}
	}
public:
	virtual BYTE* SendPrepare()
	{
		BYTE* po;
		po = Addr();
		Encode();
		FrameCrc(po);
		return(po);
	}
	virtual struCHECK CheckCRC(BYTE* const p) = 0;
protected:
	virtual void Decode(){}
	virtual void Distribute(){}
	virtual void Encode(){}
public:
	virtual void Show(){}
};

#endif // !defined(AFX_FRAMERECIEVE_H__79D92644_4FC6_49FB_A28B_59EF7305C25A__INCLUDED_)