#include "stdafx.h"
#include "TsEpgMgr.h"
#include <vector>
#include <algorithm>

CTsEPGMgr::CTsEPGMgr(void)
{
	CLock::CreateLockObj(&m_EpgLock);
}

CTsEPGMgr::~CTsEPGMgr(void)
{
	Clear();
	CLock::DestroyLockObj(&m_EpgLock);
}

// 全データを削除
void CTsEPGMgr::Clear()
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_ServiceMap::iterator itMap;
	for(itMap=m_EpgDB.begin();itMap!=m_EpgDB.end();itMap++)
	{
		TSEpg_Map *pEpg=itMap->second;
		TSEpg_Map::iterator itData;
		size_t i=pEpg->size();
		for(itData=pEpg->begin();itData!=pEpg->end();itData++)
		{
			// 動的確保データ開放処理
		}
		// メモリ最終開放
		pEpg->clear();
		delete pEpg;
	}
	m_EpgDB.clear();
}

// 指定サービスのデータを削除
void CTsEPGMgr::ClearEpg(WORD wServiceID)
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_ServiceMap::iterator itMap=m_EpgDB.find(wServiceID);
	if(itMap!=m_EpgDB.end())
	{
		TSEpg_Map *pEpg=itMap->second;
		TSEpg_Map::iterator itData;
		size_t i=pEpg->size();
		for(itData=pEpg->begin();itData!=pEpg->end();itData++)
		{
			// 動的確保データ開放処理
		}
		// メモリ最終開放
		pEpg->clear();
		delete pEpg;
		// リストから取り除く
		m_EpgDB.erase(wServiceID);
	}
}

// EPGデータベースに登録されているサービスの数を取得する。
int CTsEPGMgr::GetEpgServiceCount()
{
	CLock cEpgLock(&m_EpgLock);
	return static_cast<int>(m_EpgDB.size());
}

// EPGデータベースに登録されているサービスIDのリスト(WORD配列)を取得する。
// 取得したポインタは使用後に FreeEpgServiceList() にて開放する(実装の違いを吸収するため)
BOOL CTsEPGMgr::GetEpgServiceList(WORD **ppList,int *piNum)
{
	CLock cEpgLock(&m_EpgLock);
	WORD *pRet=new WORD[m_EpgDB.size()];
	if(pRet)
	{
		TSEpg_ServiceMap::iterator it;
		int iCount=0;
		for(it=m_EpgDB.begin();it!=m_EpgDB.end();it++)
		{
			pRet[iCount++]=it->first;
		}
		*ppList=pRet;
		*piNum=static_cast<int>(m_EpgDB.size());
		return TRUE;
	}
	return FALSE;
}

// GetEpgServiceList()で取得したデータの開放
void CTsEPGMgr::FreeEpgServiceList(WORD *pList,int iNum)
{
	if(pList) delete []pList;
}

// EPGマップに登録されれいるデータの数を取得する。
int CTsEPGMgr::GetEpgDataCount(TSEpg_Map *pEpg)
{
	CLock cEpgLock(&m_EpgLock);
	if(pEpg)
	{
		return static_cast<int>(pEpg->size());
	}
	return 0;
}

static int stl_sort_func_cmp(struct TSEPG_PROGRAM& a, struct TSEPG_PROGRAM& b)
{
	if(a.stStart.Date==b.stStart.Date)
	{
		// 同じ日付なら開始時刻でソート
		return a.stStart.Time < b.stStart.Time;
	} else {
		// 違う日付なら日付が大きいほうを正
		return a.stStart.Date < b.stStart.Date;
	}
}

// EPGデータベースに登録されているサービスIDのリスト(struct TSEPG_PROGRAM 配列)を取得する。
// 取得したポインタは使用後に FreeEpgDataList() にて開放する(実装の違いを吸収するため)
BOOL CTsEPGMgr::GetEpgDataList(TSEpg_Map *pEpg,struct TSEPG_PROGRAM **ppList,int *piNum)
{
	CLock cEpgLock(&m_EpgLock);
	if(pEpg)
	{
		struct TSEPG_PROGRAM *pRet=new TSEPG_PROGRAM[pEpg->size()];
		if(pRet)
		{
			TSEpg_Map::iterator it;
			int iCount=0;
			for(it=pEpg->begin();it!=pEpg->end();it++)
			{
				memcpy(&pRet[iCount++],&it->second,sizeof(struct TSEPG_PROGRAM));
				// 動的メモリの確保、コピー
			}
		}
		std::sort(pRet,pRet+pEpg->size(),stl_sort_func_cmp);
		*ppList = pRet;
		*piNum = static_cast<int>(pEpg->size());		
		return TRUE;
	}
	return FALSE;
}

// GetEpgDataList()で取得したデータの開放
void CTsEPGMgr::FreeEpgDataList(TSEpg_Map *pEpg,struct TSEPG_PROGRAM *pList,int iNum)
{
	if(pList)
	{
		for(int i=0;i<iNum;i++)
		{
			// 動的確保メモリの開放
		}
		delete []pList;
	}
}

// 指定したサービスIDのEPGマップへのポインタを取得する。
// bFlg=TRUE 時、存在しないデータの場合、そのデータを作成
// 存在しない場合はNULL
TSEpg_Map* CTsEPGMgr::GetEpgMap(WORD wServiceID,BOOL bNewFlg)
{
	TSEpg_ServiceMap::iterator it = m_EpgDB.find(wServiceID);
	if(it!=m_EpgDB.end())
	{
		return it->second;
	}
	else if(bNewFlg)
	{
		TSEpg_Map *pNew = new TSEpg_Map;
		if(!pNew) return NULL;
		m_EpgDB.insert(TSEpg_ServiceMapPair(wServiceID,pNew));
		it = m_EpgDB.find(wServiceID);
		if(it!=m_EpgDB.end())
		{
			// 正常に追加
			return it->second;
		}
	}
	return NULL;
}

// 指定したイベントIDのEPGデータへのポインタを取得する。
// 存在しない場合はNULL
struct TSEPG_PROGRAM* CTsEPGMgr::GetEpgData(TSEpg_Map *pEpg,WORD wEventID)
{
	if(pEpg)
	{
		TSEpg_Map::iterator it = pEpg->find(wEventID);
		if(it!=pEpg->end())
		{
			return &it->second;
		}
	}
	return NULL;
}

// 指定したサービスIDのデータを追加、または更新
BOOL CTsEPGMgr::SetEpgData(WORD wServiceID,struct TSEPG_PROGRAM *pstNewData)
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_Map *pEpg = GetEpgMap(wServiceID,TRUE);
	if(!pEpg) return FALSE;

	struct TSEPG_PROGRAM *pData=GetEpgData(pEpg,pstNewData->wEventID);
	if(pData)
	{
		// 更新(優先度の高いものであれば、強制更新)
		if(pData->byType>pstNewData->byType || (pData->byType==pstNewData->byType && pData->byVersion!=pstNewData->byVersion))
		{
			*pData = *pstNewData;
			return TRUE;
		}
	} else {
		// 新規追加
		pEpg->insert(TSEpg_MapPair(pstNewData->wEventID,*pstNewData));
		return TRUE;
	}
	return FALSE;
}

// 指定日時、時刻の番組イベントを検索。見つからない場合はNULL
// bDeleteMode=TRUEの時、指定日時時刻以前のデータは削除する
struct TSEPG_PROGRAM* CTsEPGMgr::FindEpgDataByTime(WORD wServiceID,DateTime &stSearch,BOOL bDeleteMode)
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_Map *pEpg = GetEpgMap(wServiceID);
	if(!pEpg) return NULL;

	TSEpg_Map::iterator itProg;
	std::vector<WORD> EpgDeleteEventIDList;
	bool bFindFlg=FALSE;
	struct TSEPG_PROGRAM* pFindProg=NULL;

	for(itProg=pEpg->begin();itProg!=pEpg->end();itProg++)
	{
		struct TSEPG_PROGRAM &stProg=itProg->second;
		// 判定
		if(stProg.stEnd.Time != TimeVal_Unknown)
		{
			// 開始〜終了の１秒前(終了時間は次の番組の開始時間のため)
			bFindFlg=CDateTime::Check_Time(stProg.stStart,0,stProg.stEnd,-1,stSearch,0);
		} else {
			// 開始〜
			bFindFlg=CDateTime::Compare_Time(stProg.stStart,0,stSearch,0)<0?true:false;
		}
		if(bFindFlg)
		{
			if(pFindProg)
			{
				// 今の検索結果の終了時刻が未定の場合
				if(pFindProg->dwDuration==TimeVal_Unknown)
				{
					// 他の終了時間未定
					if(stProg.dwDuration==TimeVal_Unknown)
					{
						// より遅い開始時間で終了時間未定を使う
						if(CDateTime::Compare_Time(pFindProg->stStart,0,stProg.stStart,0)<0)
						{
							// 削除リストに追加
							EpgDeleteEventIDList.push_back(pFindProg->wEventID);
							// 更新のため削除
							delete pFindProg;
							pFindProg = NULL;
						}
					}
				}
			}
			if(!pFindProg)
			{
				pFindProg = new TSEPG_PROGRAM;
				if(pFindProg)
				{
					*pFindProg = stProg;
					// 動的メモリの確保、コピー
				}
			}
		}
		// 見つかっている
		if(pFindProg)
		{
			// Deleteしない設定で終了時刻が未定でないなら検索終了
			if(!bDeleteMode && pFindProg->dwDuration!=TimeVal_Unknown) break;
		}
		// 削除するか
		if(bDeleteMode)
		{
			BOOL bDeleteFlg=FALSE;
			if(stProg.stEnd.Time != TimeVal_Unknown)
			{
				bDeleteFlg=CDateTime::Compare_Time(stProg.stEnd,0,stSearch,0)<0?true:false;
			}
			if(bDeleteFlg)
			{
				EpgDeleteEventIDList.push_back(itProg->first);
			}
		}
	}
	// 削除フラグのあるものを取り除く
	for(unsigned int i=0;i<EpgDeleteEventIDList.size();i++)
	{
		pEpg->erase(EpgDeleteEventIDList[i]);
#ifdef TSEITPARSER_DEBUG_PRINT
//		char buf[80];
//		sprintf(buf,"DELETE EPG Service=%d Event=0x%04X DataNum=%d\n",wServiceID,EpgDeleteEventIDList[i],pEpg->size());
//		OutputDebugStr(buf);
#endif
	}
	return pFindProg;
}

// 今の実装ではNetworkIDとStreamIDでの判定はない
struct TSEPG_PROGRAM* CTsEPGMgr::FindEpgDataByEventID(WORD wNetworkID,WORD wStreamID,WORD wServiceID,WORD wEventID)
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_Map *pEpg = GetEpgMap(wServiceID);
	if(!pEpg) return NULL;

	TSEpg_Map::iterator itProg;
	bool bFindFlg=FALSE;
	struct TSEPG_PROGRAM* pFindProg=NULL;
	for(itProg=pEpg->begin();itProg!=pEpg->end()&&!pFindProg;itProg++)
	{
		struct TSEPG_PROGRAM &stProg=itProg->second;
		// 判定
		if(wEventID==stProg.wEventID) bFindFlg=TRUE;
	
		if(bFindFlg && !pFindProg)
		{
			pFindProg = new TSEPG_PROGRAM;
			if(pFindProg)
			{
				*pFindProg = stProg;
				// 動的メモリの確保、コピー
			}
		}
	}
	return pFindProg;
}

// 取得したEPGデータメモリの開放
void CTsEPGMgr::FreeEpgDataMemory(struct TSEPG_PROGRAM *pData,int iCount )
{
	for(int i=0;i<iCount;i++)
	{
		// 動的メモリの開放
	}
	delete pData;
}

// 指定した時間より前のデータを削除(Service=0xFFFFなら全サービスが対象)
void CTsEPGMgr::DeleteEpgDataByTime(DateTime &stDeleteTime,WORD wServiceID)
{
	CLock cEpgLock(&m_EpgLock);
	if(wServiceID!=0xFFFF)
	{
		// サービス限定
		TSEpg_Map *pEpg = GetEpgMap(wServiceID);
		if(!pEpg) return;

		TSEpg_Map::iterator itProg;
		std::vector<WORD> EpgDeleteEventIDList;
		for(itProg=pEpg->begin();itProg!=pEpg->end();itProg++)
		{
			struct TSEPG_PROGRAM &stProg=itProg->second;
			if(stProg.stEnd.Time != TimeVal_Unknown)
			{
				if(CDateTime::Compare_Time(stProg.stEnd,0,stDeleteTime,0)<0)
				{
					// 削除対象(終了時刻を経過)
					EpgDeleteEventIDList.push_back(itProg->first);
				}
			}
		}
		// 削除フラグのあるものを取り除く
		for(unsigned int i=0;i<EpgDeleteEventIDList.size();i++)
		{
			pEpg->erase(EpgDeleteEventIDList[i]);
#ifdef TSEITPARSER_DEBUG_PRINT
//			char buf[80];
//			wsprintf(buf,"DELETE EPG Service=%d Event=0x%04X DataNum=%d\n",wServiceID,EpgDeleteEventIDList[i],pEpg->size());
//			OutputDebugStr(buf);
#endif
		}		
	} else {
		// 全サービス
		TSEpg_ServiceMap::iterator it;
		for(it=m_EpgDB.begin();it!=m_EpgDB.end();it++)
		{
			DeleteEpgDataByTime(stDeleteTime,it->first);
		}
	}
}

#ifdef _DEBUG
void CTsEPGMgr::DebugDump(WORD wServiceID,char *lpszOutputPath)
{
	CLock cEpgLock(&m_EpgLock);
	TSEpg_Map *pEpg = GetEpgMap(wServiceID);
	if(!pEpg) return;

	TSEpg_Map::iterator itProg;
	TsEpg_Vector vec;

	int i;
	vec.resize(pEpg->size());
	for(itProg=pEpg->begin(),i=0;itProg!=pEpg->end();itProg++)
	{
		vec[i++]=itProg->second;
	}
	std::sort(vec.begin(),vec.end(),stl_sort_func_cmp);

	FILE *fp=fopen(lpszOutputPath,"wt");
	if(fp)
	{
		fprintf(fp,"ServiceNo=%d\n",wServiceID);
		int i,n=static_cast<int>(vec.size());		
		for(i=0;i<n;i++)
		{
			TSEPG_PROGRAM &stItem=vec[i];
			long year,month,day,hour,min,sec,e_hour,e_min,e_sec;

			CDateTime::ConvertFrom_MJD(stItem.stStart.Date,year,month,day);
			CDateTime::ConvertFrom_TimeSec(stItem.stStart.Time,hour,min,sec);
			CDateTime::ConvertFrom_TimeSec(stItem.stEnd.Time,e_hour,e_min,e_sec);
			fprintf(fp,"%d(%02x) %04d/%02d/%02d(%s) %02d:%02d:%02d-%02d:%02d:%02d[%04X:%04X]",
				stItem.byType,stItem.byVersion,
				year,month,day,CDateTime::GetWeekDayString(stItem.stStart.Date),
				hour,min,sec,e_hour,e_min,e_sec,
				stItem.wServiceID,stItem.wEventID
				);
			fprintf(fp,"[%-80s][%s]\n",stItem.szTitle,stItem.szText);
		}
		fclose(fp);
	}
}
#endif