#include "stdafx.h"
#include "LineManage.h"
#include "Globe.h"

CLineManage::CLineManage(void)
{
	PtStruct pt;
	line.AddTail(pt);
	line.RemoveAll();
}


CLineManage::~CLineManage(void)
{
	//2015.11.27 防止内存泄漏
	MakeListNull();
}

void CLineManage::MakeListNull()
{
	if (line.GetCount()>0)
	{
		line.RemoveAll();
	}
}
//读取文件中的航线数据
//输入:航线文件名称strFileName
//输出:航线数据集合pLineData
//返回值:true——文件读取成功
//        false——文件读取失败
bool CLineManage::ReadLineDataFromFile(DrawLineDataStruct &pLineData, const CString strFileName)
{
	int ptNum = 0;

	//初始化
	memset(&pLineData, 0, sizeof(DrawLineDataStruct));

	//存储航线的航点数据
	PtStruct pts[257];
	memset(pts, 0, sizeof(PtStruct)*257);

	FILE *fpReadFlyLine = fopen(strFileName, "r");

	if (fpReadFlyLine != NULL)
	{
		while (!feof(fpReadFlyLine))
		{
			if (!ReadLinePtAndCheckData(pts[ptNum], fpReadFlyLine))
			{
				BCGPMessageBox(_T("航线文件不符合要求\r\n或航线号与要显示的航线不一致"));
				return false;
			}	

			ptNum ++;
		}

		//关闭文件
		fclose(fpReadFlyLine);
	}
	else  //空文件,航点数为0
	{
		return false;
	}

	//对读取的航线数据进行有效性检查
	if (CheckFlyLine(pts, ptNum))
	{
		//航点数据转换成标绘的航线数据集合
		LinePoint2DrawLinePoints(pLineData, pts, ptNum);

		return true;
	}
	else
	{
		return false;
	}
}

//功能;航点数据转换成能标绘的航线数据体
void CLineManage::LinePoint2DrawLinePoints(DrawLineDataStruct &lineDataArr, const PtStruct *pLinePoints, const int linePointNum)
{
	//航线编号
	lineDataArr.lineID = pLinePoints[0].nL;

	//判断第一个点是否为原点
	if (pLinePoints[0].nPt == 0)
	{
		//航点个数
		lineDataArr.pointNum = linePointNum-1;

		//拷贝航点数据
		memcpy(lineDataArr.pts, pLinePoints+1, sizeof(PtStruct)*lineDataArr.pointNum);

		//航线的航点个数
		lineDataArr.linePointNum = linePointNum-1;

		//拷贝航线的航点数据
		memcpy(lineDataArr.linePts, pLinePoints+1, sizeof(PtStruct)*lineDataArr.pointNum);

		//根据航路特征字,判断航线标注的闭合形状,是“闭合航路”还是“返回原点”
		if ((pLinePoints[linePointNum-1].ch2 == 0x01)||(pLinePoints[linePointNum-1].ch2 == 0x0B))
		{
/*
			if (lineDataArr.lineID>11)
			{
				lineDataArr.linePts[lineDataArr.linePointNum] = pLinePoints[1];
			}
			else
			{
				lineDataArr.linePts[lineDataArr.linePointNum] = pLinePoints[linePointNum-1/ *1* /];
			}*/

			if (pLinePoints[linePointNum-1].ch1 == 0x02)//航线最后一个点的倒数第二位是0x02是为不闭合标志
			{
				lineDataArr.linePts[lineDataArr.linePointNum] = pLinePoints[linePointNum - 1];
			}
			else
			{
				lineDataArr.linePts[lineDataArr.linePointNum] = pLinePoints[1];
			}
			
			//标绘的航点数加1
			lineDataArr.linePointNum ++;
		}
//		else if (pLinePoints[linePointNum-1].ch2&0X01 == 0x01)  //返回原点
		else if (pLinePoints[linePointNum-1].ch2 == 0x00)  //返回原点		2016.02.20
		{
			lineDataArr.linePts[lineDataArr.linePointNum].dX = g_gcsLon;
			lineDataArr.linePts[lineDataArr.linePointNum].dY = g_gcsLat;

			//标绘的航点数加1
			lineDataArr.linePointNum ++;
		}
	}
	else
	{
		//航点个数
		lineDataArr.pointNum = linePointNum;

		//拷贝航点数据
		memcpy(lineDataArr.pts, pLinePoints, sizeof(PtStruct)*lineDataArr.pointNum);

		//航线的航点个数
		lineDataArr.linePointNum = linePointNum;

		//拷贝航线的航点数据
		memcpy(lineDataArr.linePts, pLinePoints, sizeof(PtStruct)*lineDataArr.pointNum);

		//根据航路特征字,判断航线标注的闭合形状,是“闭合航路”还是“返回原点”
		if (pLinePoints[linePointNum-1].ch2 == 0)
		{
			lineDataArr.linePts[lineDataArr.linePointNum] = pLinePoints[0];

			//标绘的航点数加1
			lineDataArr.linePointNum ++;
		}
//		else if (pLinePoints[linePointNum-1].ch2&0X01 == 1)  //返回原点
		else if (pLinePoints[linePointNum-1].ch2 == 0x01)  //返回原点
		{
			lineDataArr.linePts[lineDataArr.linePointNum].dX = g_gcsLon;
			lineDataArr.linePts[lineDataArr.linePointNum].dY = g_gcsLat;

			//标绘的航点数加1
			lineDataArr.linePointNum ++;
		}
	}
}




//读取航线某航点 //2017.07.05
 int CLineManage::ReadAirLinePoint(FILE *fp, PtStruct &pt)
{
	return fscanf(fp, "%d, %d, %lf, %lf, %lf, %d, %02X, %02X\n", &pt.nL,
		&pt.nPt, &pt.dX, &pt.dY, &pt.nH,  &pt.nV, &pt.ch1, &pt.ch2);
}


//功能:读取航路文件的一行数据,并对该行数据进行检查
//输入:航路文件指针fp
//输出:航点数据体pt
//返回值:true——成功
//		  false——失败
bool CLineManage::ReadLinePtAndCheckData(PtStruct &pt, FILE *fp)
{
	int redFlag = 0;     //航路文件是否导入正确的标识
	int nums = 8;	

	redFlag = ReadAirLinePoint(fp, pt);

	if (redFlag != nums)    //航路文件不对,返回
	{
		return false;
	}
	else
	{
		return true;
	}		
}


//功能:对航路文件进行严格的数据检查
//输入:航路文件数据体pts,航点个数ptNum
//输出:更改航路特征后的航路文件数据体pts

//返回值:true——该航路文件数据正确
//        false——该航路文件数据不正确
//检查项:
//      1、所有航点的航线编号是否一样;
//      2、所有航点的航点编号是否不一样;
//      3、除最后一个航点外,其余航点的航路特征字是否为“还有航点”;
//		4、最后一个航点的航路特征字是否为“闭合航路”,若不是更改成“闭合航路”
bool CLineManage::CheckFlyLine(PtStruct *pts, const int ptNum)
{
	//航路点个数的有效范围为[0,255]共256个
	//检测的有效范围为【2,256】
	if ((ptNum>257) || (ptNum<2))
	{
		return false;
	}

	int i=0;
	int j=0;

	//对单个航点的数据进行检查
	for (i=0; i<ptNum; i++)
	{
		if (!CheckOnePointValue(pts[i]))
		{
			return false;
		}
	}

	//对航点的航线编号进行严格检查
	//当存在航线编号不一样时,返回false
	int ptLineID = pts[0].nL;
	for (i=1; i<ptNum; i++)
	{
		if (ptLineID != pts[i].nL)
		{
			return false;
		}
	}	
	
	//对航线的航点编号进行严格检查,判断规则为,起点为0或1,依次递增1
	//当存在航点编号不符合规则时,返回false
	if ( (pts[0].nPt != 0) && (pts[0].nPt != 1) )
	{
		return false;
	}
	int toComparePtId = pts[0].nPt + 1;
	for (i=1; i<ptNum; i++)
	{
		if (pts[i].nPt != toComparePtId)
		{
			return false;
		}
		else
		{
			toComparePtId++;
		}
	}

	return true;		//2016.02.17
	
	//-------------delete in 2016.02.17-------------------//
	//不对航点特征字进行判断
/*
// 	//对除最后一个航点进行验证,看其是否为“还有航点”;
// 	for (i=0; i<ptNum-1; i++)
// 	{
// 		if ((pts[i].ch2 & 0x02) == 0)   //“闭合航路”时返回false
// 		{
// 			return false;
// 		}
// 	}
// 	
// 	//对最后一个航点进行验证,看其是否为“航点结束”,且航路结束特征为“闭合航路”
// 	//若是“航点结束”,但航路结束特征不为“闭合航路”,返回false
// 	if ((pts[ptNum-1].ch2 & 0x02) == 0)
// 	{
// 		//2015.12.02
// // 		if ((pts[ptNum-1].ch2 & 0x01) != 0)    //航路结束特征不是“闭合航路”
// // 		{
// // 			return false;
// // 		}
// // 		else								   //航路结束特征为“闭合航路”
// // 		{
// // 			return true;
// // 		}
// 
// 		return true;
// 	}
// 	else
// 	{
// 		return false;
// 	}*/
}



//功能:对单个航点的数据的有效范围进行检查
//输入:航点数据体pt
//返回值:true——航点数据位于有效范围内
//        false——航点数据超限
bool CLineManage::CheckOnePointValue(const PtStruct pt)
{
	//航点数据的数据范围进行检查,看其是否符合要求
	//对导入的数据进行判读,超限就弹出错误,并返回
	if (   (pt.nL<1)	|| (pt.nL>14) 
		|| (pt.nPt<0)	|| (pt.nPt>255)
		|| (pt.dX<-180) || (pt.dX>180)
		|| (pt.dY<-90)	|| (pt.dY>90)
		|| (pt.nH<-500) || (pt.nH>10000) 
		|| (pt.nV<0)	|| (pt.nV>360)
		|| (pt.ch1<0)	|| (pt.ch1>255) 
		|| (pt.ch2<0)	|| (pt.ch2>255) ) 
	{
		return false;
	}
	else
	{
		return true;
	}
}



//功能:打开无人机航路文件
//输入:航路文件的绝对路径str
//		航线编号nL:1、2、3、4、5
//		航线的来源,是否来自软件安装路径的标识bFromLocalDir:true——是;false——不是
//		其中:1、从软件安装目录下加载的航线文件需要对原点是否存在进行判断;航线导入不需要判断
//			  2、从软件安装目录下加载的航线文件需要对航线ID进行检查,航线导入不需要检查

//输出:航点数据存储于类的的成员line中
//返回值:成功——返回true
//        失败——返回false
bool CLineManage::OpenFlyLineFile(const CString &str, const int &nL, const bool &bFromLocalDir)
{
	MakeListNull();                  //清空已有的数据
	FILE* fp;
	PtStruct pt;
	//读取航线文件
	fp = fopen(str, "r");
	if (fp == NULL)
	{
		return false;
	}

	int linePtNum = 0;	
	while(!feof(fp))
	{
		if (!ReadLinePtAndCheckData(pt, fp))
		{

			return WrongLineDataProcess(fp);
		}			
		AddPt(pt);
		linePtNum++;	

	}
	//return true;
	PtStruct *linePts = new PtStruct[LINEPTNUM];
	memset(linePts, 0, sizeof(PtStruct)*LINEPTNUM);
	ListData2ArrayData(linePts, linePtNum, 1);

	//对航线数据进行严格的检查
	if (CheckFlyLine(linePts, linePtNum))
	{
		if (bFromLocalDir)   //本地路径加载的航线文件
		{
			if (CheckOrgPtIsExisted(linePts, linePtNum) &&
				CheckFlyLineIDCorrect(linePts, linePtNum, nL))
			{
				fclose(fp);
				if (linePts != NULL)
				{
					delete []linePts;
					linePts = NULL;
				}
				return true; 
			}
			else
			{
				if (linePts != NULL)
				{
					delete []linePts;
					linePts = NULL;
				}	
				return WrongLineDataProcess(fp);
			}
		}
		else
		{
			//航路文件读取成功,数据验证均正确
			if (linePts != NULL)
			{
				delete []linePts;
				linePts = NULL;
			}
			fclose(fp);
			return true;
		}
	}
	else
	{
		if (linePts != NULL)
		{
			delete []linePts;
			linePts = NULL;
		}
		return WrongLineDataProcess(fp);
	}	
}


//功能:文件读取错误时采取的操作
bool CLineManage::WrongLineDataProcess(FILE *fp)
{
	//删除原有的数据
	MakeListNull();	
	//关闭文件
	fclose(fp);
	return false;
}

//拷贝航线数据
void CLineManage::AddPt(PTLIST *other)
{
	MakeListNull();

	POSITION pos = other->GetHeadPosition();
	for (int i=0; i<other->GetCount(); i++)
	{
		PtStruct pt = other->GetNext(pos);
		//航线编号都置为0
		pt.nL = 0;
		line.AddTail(pt);         //往每块数据里添加航点数据
	}
}

//增加航点
void CLineManage::AddPt(PtStruct pt)
{
	//拷贝一份数据
	line.AddTail(pt);         //往每块数据里添加航点数据
}

//增加原点航点
void CLineManage::AddPt(const double &L, const double &B,const float& H, const int &ptId)
{
	PtStruct pt;
	memset(&pt,0,sizeof(PtStruct));

	pt.ch2 = 0x03; //航点特征字为“还有航点”
	pt.dX = L;
	pt.dY = B;
	pt.nPt = ptId;
	pt.nH = H;
	

	//WGS84坐标转BJ54坐标
	if (ptId == 0)        //原点坐标
	{
		//wgs84AndBj54.Wgs84TransToBj54(&pt.dX, &pt.dY);    //WGS84转BJ54坐标
	}

	line.AddTail(pt);         //往每块数据里添加航点数据
}


//功能:将链表里存储的数据转化成指定坐标系的数组存储
//      如coordType=0——输出wgs84坐标系的坐标数组
//      如coordType=1——输出bj54坐标系的坐标数组

//输入:坐标系coordType:0为wgs84;1为bj54坐标系
//输出:航点数组pts,航点总数ptNum
void CLineManage::ListData2ArrayData(PtStruct *pts, int &ptNum, const int &coordType)
{
	ptNum = line.GetCount();
	int i=0;
	POSITION ps = line.GetHeadPosition();
	for (i=0; i<ptNum; ++i)
	{
		pts[i] = line.GetNext(ps);
	}

	//输出WGS84坐标系的坐标,需进行BJ54到WGS84间的变换
	if (coordType == 0)   
	{
		for (i=0; i<ptNum; ++i)
		{
			//wgs84AndBj54.Bj54TransToWgs84(&pts[i].dX, &pts[i].dY);
		}
	}
}


//功能:判断航线数据的第一个点是否为原点
//输入:航点数组pts,航点总数ptNum
//返回值:true——存在;
//		  false——不存在
bool CLineManage::CheckOrgPtIsExisted(const PtStruct *pts, const int &ptNum)
{
	if (pts[0].nPt == 0)  //原点点号为0
	{
		return true;
	}
	else
	{
		return false;
	}
}

//功能:判断航线数据的航线编号是否为设置的航线编号
//输入:航点数组pts,航点总数ptNum
//返回值:true——存在;
//		  false——不存在
bool CLineManage::CheckFlyLineIDCorrect(const PtStruct *pts, const int &ptNum, const int &nL)
{
	for (int i=0; i<ptNum; ++i)
	{
		if (pts[i].nL != nL)
		{
			return false;
		}
	}

	return true;
}