#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();
}

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;
	}
}

// 指定したサービス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;
		else if(wEventID == 0 && stProg.wSecNo == 0) bFindFlg=TRUE;
	
		if(bFindFlg && !pFindProg)
		{
			pFindProg = new TSEPG_PROGRAM;
			if(pFindProg)
			{
				*pFindProg = stProg;
				// 動的メモリの確保、コピー
			}
		}
	}
	return pFindProg;
}

// 現在放送中と思われる番組を返す
struct TSEPG_PROGRAM* CTsEPGMgr::FindEpgDataLatest(WORD wServiceID)
{
	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;
	struct TSEPG_PROGRAM* pLatestProg=NULL;
	for(itProg=pEpg->begin();itProg!=pEpg->end();itProg++)
	{
		struct TSEPG_PROGRAM &stProg=itProg->second;
		// 判定
		if(stProg.wSecNo == 0){
			bFindFlg=TRUE;
			pLatestProg = &stProg;
		}	
	
	}
	if(bFindFlg){
		pFindProg = new TSEPG_PROGRAM;
		if(pFindProg){
			*pFindProg = *pLatestProg;
			// 動的メモリの確保、コピー
		}
	}
	return pFindProg;
}



int CTsEPGMgr::Is2ByteChar(unsigned char c)
{
    int esc = 0; /* 最終バイトの状態 */
    int rtn = 0; /* 返却値 */
	
	if (esc == 0) { /* ESC以外 */
		if ((c >= 0x20) && (c <= 0x7E)) {
			/* ASCII */
		} else if ((c <= 0x06) || (c == 0x7f) || (c == 0xff)) {
			rtn = 1; /* Binary */
		} else if (c == 0x1B) {
			esc = 1; /* ESC (1B) */
			rtn = 1; /* Not ASCII */
		} else if ((c >= 0x07) && (c <= 0x0d)) {
			/* ctrl */
		} else if ((c >= 0x0e) && (c <= 0x1F)) {
			rtn = 0; /* Binary */
		} else if (((c >= 0x80) && (c <= 0x8D))
			|| ((c >= 0x90) && (c <= 0xA0))) {
			rtn = 1; /* SJIS */
		} else if (c == 0xFE) {
			rtn = 1; /* EUC */
		} else {
			rtn = 0; /* Not ASCII */
		}
	} else if (esc == 1) { /* ESC (1B) */
		if (c == 0x24) {
			esc = 1; /* ESC (1B 24) */
		} else if (c == 0x28) {
			esc = 1; /* ESC (1B 28) */
		} else {
			esc = 0;
		}
	} else if (esc == 2) { /* ESC (1B 24) */
		esc = 0;
		if ((c == 0x40) || (c == 0x42)) {
			rtn = 1; /* JIS */
		}
		
	} else { /* ESC (1B 28) */
		esc = 0;
		if ((c == 0x42) || (c == 0x49) || (c == 0x4A)) {
			rtn = 1; /* JIS */
		}
	}
	
    return(rtn);
}



DWORD CTsEPGMgr::CompChar(BYTE* str1,BYTE* str2)
{

	static const BYTE SjisToAscii[][3]={
		{	0x81,0x46,0x3a },{	0x81,0x47,0x3b },{	0x81,0x48,0x3f },
		{	0x81,0x49,0x21 },{	0x82,0x4F,0x30 },{	0x82,0x50,0x31 },
		{	0x82,0x51,0x32 },{	0x82,0x52,0x33 },{	0x82,0x53,0x34 },
		{	0x82,0x54,0x35 },{	0x82,0x55,0x36 },{	0x82,0x56,0x37 },
		{	0x82,0x57,0x38 },{	0x82,0x58,0x39 },{	0x82,0x60,0x41 },
		{	0x82,0x61,0x42 },{	0x82,0x62,0x43 },{	0x82,0x63,0x44 },
		{	0x82,0x64,0x45 },{	0x82,0x65,0x46 },{	0x82,0x66,0x47 },
		{	0x82,0x67,0x48 },{	0x82,0x68,0x49 },{	0x82,0x69,0x4a },
		{	0x82,0x6a,0x4b },{	0x82,0x6b,0x4c },{	0x82,0x6c,0x4d },
		{	0x82,0x6d,0x4e },{	0x82,0x6e,0x4f },{	0x82,0x6f,0x50 },
		{	0x82,0x70,0x51 },{	0x82,0x71,0x52 },{	0x82,0x72,0x53 },
		{	0x82,0x73,0x54 },{	0x82,0x74,0x55 },{	0x82,0x75,0x56 },
		{	0x82,0x76,0x57 },{	0x82,0x77,0x58 },{	0x82,0x78,0x59 },
		{	0x82,0x79,0x5a },{	0x82,0x81,0x61 },{	0x82,0x82,0x62 },
		{	0x82,0x83,0x63 },{	0x82,0x84,0x64 },{	0x82,0x85,0x65 },
		{	0x82,0x86,0x66 },{	0x82,0x87,0x67 },{	0x82,0x88,0x68 },
		{	0x82,0x89,0x69 },{	0x82,0x8a,0x6a },{	0x82,0x8b,0x6b },
		{	0x82,0x8c,0x6c },{	0x82,0x8d,0x6d },{	0x82,0x8e,0x6e },
		{	0x82,0x8f,0x6f },{	0x82,0x90,0x70 },{	0x82,0x91,0x71 },
		{	0x82,0x92,0x72 },{	0x82,0x93,0x73 },{	0x82,0x94,0x74 },
		{	0x82,0x95,0x75 },{	0x82,0x96,0x76 },{	0x82,0x97,0x77 },
		{	0x82,0x98,0x78 },{	0x82,0x99,0x79 },{	0x82,0x9a,0x7a },
	};
	DWORD i=0,j=0,k=0;
	DWORD hit=0;
	//			０ １ ２ ３ ４ ５ ６ ７ ８ ９ Ａ Ｂ Ｃ Ｄ Ｅ Ｆ
	//	8140: 　　 、 。 ， ． ・ ： ； ？ ！ ゛ ゜ ´ ｀ ¨ ＾ 
	//  8240:   ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ０ 
	//　8250:   １ ２ ３ ４ ５ ６ ７ ８ ９ ・ ・ ・ ・ ・ ・ ・ 
	//  8260:   Ａ Ｂ Ｃ Ｄ Ｅ Ｆ Ｇ Ｈ Ｉ Ｊ Ｋ Ｌ Ｍ Ｎ Ｏ Ｐ 
	//  8270:   Ｑ Ｒ Ｓ Ｔ Ｕ Ｖ Ｗ Ｘ Ｙ Ｚ ・ ・ ・ ・ ・ 　 
	//  8280:   ・ ａ ｂ ｃ ｄ ｅ ｆ ｇ ｈ ｉ ｊ ｋ ｌ ｍ ｎ ｏ 
	//  8290:   ｐ ｑ ｒ ｓ ｔ ｕ ｖ ｗ ｘ ｙ ｚ ・ ・ ・ ・ ぁ 
	BYTE s1,s2;

	while(str1[i] != NULL && str2[	j] != NULL){
		s1 = str1[i];
		s2 = str2[j];
		for(k=0 ; k < sizeof(SjisToAscii)/sizeof(SjisToAscii[0]) ; k ++){
			if(str1[i] == SjisToAscii[k][0] && str1[i+1] == SjisToAscii[k][1]){
				s1 = SjisToAscii[k][2];
				i++;
			}
			if(str2[j] == SjisToAscii[k][0] && str2[j+1] == SjisToAscii[k][1]){
				s2 = SjisToAscii[k][2];
				j++;
			}
		}
		if(s1 == s2){
			hit++;
		} else if(hit) {
			break;
		}
		i++;
		j++;
	}
	
	return hit;
}


struct TSEPG_PROGRAM* CTsEPGMgr::FindEpgDataByTitle(LPCTSTR title,DWORD len,WORD wServiceID)
{
	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;
		// 判定

		DWORD i,j,hit;
		DWORD hit_len;

		char* str1;				// 実際の番組名
		char* str2;				// 保存する番組名
		char str1_buff[100];
		char str2_buff[100];

		strcpy(str1_buff,stProg.szTitle);
		strcpy(str2_buff,title);

		str1 = str1_buff;
		str2 = str2_buff;

		DWORD str1_start = 0,str2_start = 0;
		DWORD str1_end = (DWORD)strlen(str1),str2_end = (DWORD)strlen(str2);

		BOOL bFindFlg = FALSE;
		
		if(str1_end && str1[str1_end-1] == ']') str1_end--;
		if(str2_end && str2[str2_end-1] == ']') str2_end--;

		while(str1[str1_start] == '['){
			while(str1[str1_start] != ']' && str1[str1_start] != 0) str1_start++;
			if(str1[str1_start] != 0) str1_start ++;
		}
		while(str1_end && str1[str1_end] == ']'){
			while(str1[str1_end] != '[' && str1[str1_end] != 0) str1_end--;
			if(str1_end && str1[str1_end-1] != ']') break;
			str1_end--;
		}
		while(str2[str2_start] == '['){
			while(str2[str2_start] != ']' && str2[str2_start] != 0) str2_start++;
			if(str2[str2_start] != 0) str2_start ++;
		}
		while(str2_end && str2[str2_end] == ']'){
			while(str2[str2_end] != '[' && str2[str2_end] != 0) str2_end--;
			if(str2_end && str2[str2_end] != ']') break;
			str2_end--;
		}
		str1[str1_end] = NULL;
		str2[str2_end] = NULL;
		str1+=str1_start;
		str2+=str2_start;

		hit_len = (str2_end - str2_start) / 2 + 1;
		if(hit_len>12) hit_len=12;

//		if(hit_len < 6) hit_len = str2_end - str2_start;

		for(i = 0; ; i++){
			for(j = 0 ; ; j ++){
				hit = 0;
				hit = CompChar((BYTE*)&str1[i],(BYTE*)&str2[j]);
				if(hit >= hit_len){
					bFindFlg = true;
					break;
				} else if (str2[j+hit] == 0&& j ==0){
					bFindFlg = true;
					break;
				}
				if(str2[j] == 0){
					break;
				}
				if(Is2ByteChar(str2[j])) j++;
			}
			if(str1[i] == 0 || bFindFlg){
				break;
			}
			if(Is2ByteChar(str1[i])) i++;
		}
		
		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;
}

