/*
 * Emunation Plugin for MD-API 
 *
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 */
 
/* Replace "dll.h" with the name of your header */
#include "main.h"
#include "EmuNation_Impl.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "misc.h"
#include "common.h"
#include <process.h>
#include ".\\dvbparser\\dvbsectiondata.h"
#include ".\\DVBCore\\DVBCoreWrapper.h"

//#define THREADED_STATE_CONTROL
#define THREADED_START_FILTER
#define THREADED_DATA_FLOW
//#define MAIN_LOOP_THREADED
//Prototypes
BOOL APIENTRY DllMainDlgFunc(HWND hDlg,UINT message,UINT wParam,LONG lParam);
BOOL APIENTRY DllAboutDlgFunc(HWND hDlg,UINT message,UINT wParam,LONG lParam);
void STATE_CONTROL(void* impl);
void DATA_FLOW(void* impl);

#define LOG_DEBUG_PLG(X) Log("%s Func: %s Line:%d\n",X,__FUNCTION__,__LINE__);
DllClass m_DLLInstance;
CAPI_Impl *g_API_Impl=&m_DLLInstance;

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

DllClass::DllClass()
{
	m_prevecmdata=NULL;
	m_hwnd_console=NULL;
	remove("emulog.txt");
	m_flow=0;
	ThreadState=true;
	PluginEvent=EVENT_IDLE;
	IsInitialized=false;
	DVBCoreFlag=false;
	strcpy(m_infotext,"No information provided.");
	strcpy(m_keystr,"No keys");
	
	m_isecmfilter = false;
	m_isemmfilter = false;
	m_ispmtfilter = false;
	
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

DllClass::~DllClass ()
{
	
}
#define INI_FILE_NAME "EmuNation.ini"
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
void DllClass::OnDVBCoreInit(HWND Handle)
{
	m_MultiDecWindow=Handle;
	DVBCoreFlag=true;
	OnEmunationInit();
}
void DllClass::OnEmunationInit()
{
	//   char dllshortpath[_MAX_PATH];
	//	  GetShortPathName (dlldirPath,dllshortpath,sizeof(dllshortpath));
	sprintf(INI_FILE,"%s\\%s",dlldirPath,INI_FILE_NAME);
	InitializeOptions();
	//Menu Initialization
	InitializeMenu();
	//System
	keys.Load(dlldirPath);
	cSystems::Init(dlldirPath);
	filemaps.SetCfgDir(dlldirPath);
	
	//ECM Filter Initialization
	m_ecmfilter.DLL_ID=m_MultiDec_DLL_ID;
	m_ecmfilter.Filter_ID=ECM_FILTER_ID;
	m_ecmfilter.Irq_Call_Adresse=0; 
	strcpy((char*)m_ecmfilter.Name,ECM_FILTER_NAME);
	m_ecmfilter.Running_ID=-1;
	m_ecmfilter.m_ExtSize=0;
	m_ecmfilter.m_SectionMask=0;
	m_ecmfilter.m_SectionData=0;
	m_ecmfilter.m_185Mode=false;
	//EMM Filter Initialization
	m_emmfilter.DLL_ID=m_MultiDec_DLL_ID;
	m_emmfilter.Filter_ID=EMM_FILTER_ID;
	m_emmfilter.Irq_Call_Adresse=0; 
	strcpy((char*)m_emmfilter.Name,EMM_FILTER_NAME);
	m_emmfilter.Running_ID=-1;
	//DATA filter
	m_datafilter.DLL_ID=m_MultiDec_DLL_ID;
	m_datafilter.Filter_ID=DATA_FILTER_ID;
	m_datafilter.Irq_Call_Adresse=0; 
	strcpy((char*)m_datafilter.Name,"PMT FILTER");
	m_datafilter.Running_ID=-1;
	m_datafilter.m_ExtSize=0;
	m_datafilter.m_SectionMask=0;
	m_datafilter.m_SectionData=0;
	m_datafilter.m_185Mode=false;
	
	
	m_emmfilter.m_ExtSize=0;
	m_emmfilter.m_SectionMask=0;
	m_emmfilter.m_SectionData=0;
	m_emmfilter.m_185Mode=false;  
	//	  Log("API Version:%s\n",Api_Version);
	//	  Log("MDWnd %p\n",MDWnd);
#ifdef THREADED_STATE_CONTROL
	_beginthread( STATE_CONTROL, 0, this );
#endif
	
#ifdef THREADED_DATA_FLOW
	_beginthread( DATA_FLOW, 0, this );
#endif
	IsInitialized=true;
}
HINSTANCE DllClass::GetDLLInstance()
{
	return m_hDLL;
}
BOOL DllClass::DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
	CAPI_Impl::DllMain(hDLL,dwReason,lpReserved);
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

#define ACT_START_FILTER 0
#define ACT_STOP_FILTER 1

typedef struct __FilterArgs
{
	int action;
	CAPI_Impl* owner;
	TSTART_FILTER* sf;
	int filterid;
}FilterArgs;

FilterArgs fargs;

void FILTER_CONTROL (void* args)
{
	FilterArgs* f=(FilterArgs*) args;
	if (f->action == ACT_START_FILTER)
	{
		f->owner->Start_Filter(f->sf);
	}
	else
	{
		f->owner->Stop_Filter(f->filterid);
	}
}
int DllClass::Start_Filter(struct TSTART_FILTER *sf)
{
	if (!DVBCoreFlag)
	{
#ifdef THREADED_START_FILTER
		//	  Log("Threaded Start %X\n",sf->Filter_ID);
		fargs.action=ACT_START_FILTER;
		fargs.owner=this;
		fargs.sf=sf;
		fargs.filterid=0;
		_beginthread( FILTER_CONTROL, 0, &fargs );
		Sleep(100);
		return 1;
#else
		
		return CAPI_Impl::Start_Filter(sf);
#endif
	}
	
	return DVBCORE_Start_Filter(sf);
}
int DllClass::Stop_Filter(int filterid)
{
	if (!DVBCoreFlag)
	{
#ifdef THREADED_START_FILTER
		fargs.action=ACT_STOP_FILTER;
		fargs.owner=this;
		fargs.sf=NULL;
		fargs.filterid=filterid;
		_beginthread( FILTER_CONTROL, 0, &fargs );
		Sleep(100);
		return 1;
#else
		return CAPI_Impl::Stop_Filter(filterid);
#endif
	}  
	return DVBCORE_Stop_Filter(filterid); 
}
void DllClass::On_Send_Dll_ID_Name(char *Name)
{
	strcpy(Name,EMUNATION_PLG_NAME);
}

bool DllClass::DVBCORE_Stop_Filter(int flt_id)
{
	DWORD* Filter;
	if(flt_id<=0) return false;
	if (flt_id == DVBCORE_ECM_FILTER)
	{
		Filter = &DVBCORE_ECM_FILTER;
		m_ecmfilter.Running_ID = 0;
		
	}
	else
		if (flt_id == DVBCORE_EMM_FILTER)
		{
			Filter = &DVBCORE_EMM_FILTER;
			m_emmfilter.Running_ID = 0;
		}
		else
			if (flt_id == DVBCORE_PMT_FILTER)
			{
				Filter = &DVBCORE_PMT_FILTER;
				m_datafilter.Running_ID = 0;
			}
			
			_DVBDelFilter(flt_id);	
			*Filter=0;
			return true;  
}

bool DllClass::DVBCORE_Start_Filter(struct TSTART_FILTER *sf)
{
	int flt_id = sf->Filter_ID;
	
	if(flt_id == ECM_FILTER_ID)
	{
		DVBCORE_ECM_FILTER = _DVBAddFilter(sf->Pid,(LPCB_STREAMHOOK)STREAM_FILTER,FT_STREAMING_FILTER,NULL,NULL,0);
		sf->Running_ID = DVBCORE_ECM_FILTER;
		//Log("\n\nStart ECM: %d \n\n",DVBCORE_ECM_FILTER);
	}
	else
		if(flt_id == EMM_FILTER_ID)
		{
			DVBCORE_EMM_FILTER = _DVBAddFilter(sf->Pid,(LPCB_STREAMHOOK)STREAM_FILTER,FT_STREAMING_FILTER,NULL,NULL,0);
			sf->Running_ID = DVBCORE_EMM_FILTER;
			//Log("\n\nStart EMM: %d \n\n",DVBCORE_EMM_FILTER);
		}
		else
			if(flt_id == DATA_FILTER_ID)
			{
				DVBCORE_PMT_FILTER = _DVBAddFilter(sf->Pid,(LPCB_STREAMHOOK)STREAM_FILTER,FT_STREAMING_FILTER,NULL,NULL,0);
				sf->Running_ID = DVBCORE_PMT_FILTER;
				//Log("\n\nStart PMT: %d \n\n",DVBCORE_PMT_FILTER);
			}
	return true;
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
bool DllClass::StopECMFilter_TH()
{
	if(m_isecmfilter){
		if (!Stop_Filter(m_ecmfilter.Running_ID))
			Log("!!BUG!!Host program cannot stop filter!\n");
		m_isecmfilter=false;
		//		  Log("Fnc :%s Line:%d\n",__FUNCTION__,__LINE__);
		if(m_prevecmdata)
		{ 
			delete[] m_prevecmdata;
			m_prevecmdata=NULL;
		}
	}
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
bool DllClass::StartDataFilter_TH()
{
	m_datafilter.Pid=m_curprg.PMT_pid;
	return Start_Filter(&m_datafilter);
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
bool DllClass::StartECMFilter_TH(TProgramm82* CurrentProgramm)
{
	char text[60];
	if(m_prevecmdata)
		delete [] m_prevecmdata;
	m_prevecmdata=NULL;
	m_cursys=NULL;
	m_flow=0;
	m_cursys=cSystems::FindBySysId(CurrentProgramm->CA_System[m_curecmindex].CA_Typ,false,0);
	//	if (m_cursys)
	//	{
	
	sprintf(text,"Ch:%.15s System:%s  Provider:0X%.4X",CurrentProgramm->Name,m_cursys?m_cursys->Name():"Unsupported",CurrentProgramm->CA_System[m_curecmindex].Provider_Id);
	PushMessage(MSG_INFO,text);
	// Log("[INFO] System found: %s\n",m_cursys->Name());
	
	m_ecmfilter.Pid=CurrentProgramm->CA_System[m_curecmindex].ECM;
	
	if(m_cursys&&strcmp(m_cursys->Name(),"ConstCW")==0)
	{
		cEcmInfo ecminfo(m_curprg.Name,m_curprg.CA_System[m_curecmindex].ECM,m_curprg.CA_System[m_curecmindex].CA_Typ,m_curprg.CA_System[m_curecmindex].Provider_Id);	
		ecminfo.SetSource(m_curprg.SID_pid,0,m_curprg.freq/1000);
		if(m_cursys->ProcessECM(&ecminfo,NULL))
		{ 
			sprintf(m_keystr,"Key :%s",m_cursys->CurrentKeyStr());
			PushMessage(MSG_KEY,m_keystr);	 
			SendDCW(m_cursys->CW());
		}
		return true;
	}
	
	if(Start_Filter(&m_ecmfilter))
	{
		// 	  Log("Fnc :%s Line:%d m_cursys :%p\n",__FUNCTION__,__LINE__,m_cursys);
		m_isecmfilter=true;
		m_logger.OnChannelChange(m_ecmfilter.Pid,m_emmfilter.Pid);	 
	}
	else
	{
		m_isecmfilter=false;
		
		return false;
	}
	
	//}else
	//{
	if (!m_cursys)
		PushMessage(MSG_INFO,"Unsupported CA Type.");
	//}
	return true;
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StopEMMFilter_TH()
{
	if(m_isemmfilter){
		Stop_Filter(m_emmfilter.Running_ID);
		m_isemmfilter=false;
	}
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StartEMMFilter_TH(TProgramm82* CurrentProgramm)
{
	char text[60];
	m_cursys=cSystems::FindBySysId(CurrentProgramm->CA_System[m_curecmindex].CA_Typ,false,0);
	if (m_cursys)
	{
		sprintf(text,"%s AU Provider:(0X%.4X)",m_cursys->Name(),CurrentProgramm->CA_System[m_curecmindex].Provider_Id);
		PushMessage(MSG_INFO,text);
		
		m_emmfilter.Pid=CurrentProgramm->CA_System[m_curecmindex].EMM;
		m_emmcount=0;
		if(Start_Filter(&m_emmfilter))
		{
			m_logger.OnChannelChange(m_ecmfilter.Pid,m_emmfilter.Pid);	 
			m_isemmfilter=true;
			m_emmcount=0;
		}
		else
		{
			m_isemmfilter=false;
			return false;
		}
		
	}
	return true;
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StopDataFilter_TH()
{
	return Stop_Filter(m_datafilter.Running_ID);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StopECMFilter()
{
#ifdef THREADED_STATE_CONTROL
	return SignalStopFilter(EVENT_STOPECMFILTER);
#else
	return StopECMFilter_TH();
#endif
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StopEMMFilter()
{
#ifdef THREADED_STATE_CONTROL
	return SignalStopFilter(EVENT_STOPEMMFILTER);
#else
	return StopEMMFilter_TH();
#endif
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::On_Exit(HINSTANCE MDInstance, HWND MDWnd, BOOL Log_Set)
{
	StopEMMFilter();
	//	StopECMFilter();
	SaveOptions();
	ThreadState=false;
	//	  Log("On Exit\n");
	if(m_hwnd_console)EndDialog(m_hwnd_console,0);;
	
}
void DllClass::On_Filter_Close(unsigned int FilterOffset )
{
	// Log("OnFilterClose: %d\n",FilterOffset);
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::Log(const char* format,...)
{
	char in_buffer[256];
	char out_buffer[512];
	char time_str[20];
	FILE* f=fopen("emulog.txt","at");
	va_list argptr; 
	va_start( argptr, format );
	vsprintf(in_buffer,format,argptr);
	va_end(argptr);
	_strtime(time_str);
	sprintf(out_buffer,"[%s]%s",time_str,in_buffer);
	fprintf(f,out_buffer);
	fclose(f);
	
	PushMessage(MSG_MESSAGE,out_buffer);
}

//------------------------------------------------------------------------------
//This function handles menu calls....
//------------------------------------------------------------------------------

void DllClass::On_Menu_Select(unsigned int MenuID )
{
	HMENU EmuMenu;	  
	if(m_DLLInstance.DVBCoreFlag)
	{
		EmuMenu = GetMenu(m_hwnd_console);
	}
	else
	{
		EmuMenu = GetMenu(m_MultiDecWindow);
	}
	
	switch(MenuID)
	{
	case IDM_ACTIVE:
		m_plg_active=!m_plg_active;
		CheckMenuItem(EmuMenu,IDM_ACTIVE,m_plg_active? MF_CHECKED:MF_UNCHECKED);
		if(!m_plg_active){
			StopECMFilter();  
			StopEMMFilter();
			ClearAllData();
		}else
		{
			TProgramm82 curprg;
			Get_Programm_Detail(&curprg);
			StartECMFilter(&curprg);
		}
		
		
		break;
	case IDM_SHOW:
		ShowDialog(IDD_DLG_MAIN);
		break;
	case IDM_ABOUT:
		ShowDialog(IDD_DLG_ABOUT);
		break;
	case IDM_AUTO_PID:
		m_isautoecm=!m_isautoecm;
		CheckMenuItem(EmuMenu,IDM_AUTO_PID,m_isautoecm? MF_CHECKED:MF_UNCHECKED);
		break;
	case IDM_READPMT:
		m_readpmt=!m_readpmt;
		CheckMenuItem(EmuMenu,IDM_READPMT,m_readpmt? MF_CHECKED:MF_UNCHECKED);
		break;
		
		///Logger Menu Selections
	case IDM_LOGECMTEXT:
		
		CheckMenuItem(EmuMenu,IDM_LOGECMTEXT,m_logger.ToggleActive(cLogger::ECM_Text)? MF_CHECKED:MF_UNCHECKED);
		break;
		
	case IDM_LOGECMBIN:
		
		CheckMenuItem(EmuMenu,IDM_LOGECMBIN,m_logger.ToggleActive(cLogger::ECM_Bin)? MF_CHECKED:MF_UNCHECKED);
		break;
		
	case IDM_LOGEMMTEXT:
		
		CheckMenuItem(EmuMenu,IDM_LOGEMMTEXT,m_logger.ToggleActive(cLogger::EMM_Text)? MF_CHECKED:MF_UNCHECKED);
		break;
		
	case IDM_LOGEMMBIN:
		
		CheckMenuItem(EmuMenu,IDM_LOGEMMBIN, m_logger.ToggleActive(cLogger::EMM_Bin)? MF_CHECKED:MF_UNCHECKED);
		break;
		
	case IDM_LOGCW:
		
		CheckMenuItem(EmuMenu,IDM_LOGCW,m_logger.ToggleActive(cLogger::DCW)? MF_CHECKED:MF_UNCHECKED);
		break;
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::On_Hot_Key()
{
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
#define TOLOG
void DllClass::to_log(char *x)
{
#ifdef TOLOG
	FILE *f=fopen("emunation.txt","at");
	if(f)
	{
		fprintf(f,"%s\n",x);
		fclose(f);
	}
#endif
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::On_Start(HINSTANCE MDInstance, HWND MDWnd, BOOL Log_Set, int DLL_ID, char *My_Hot_Key,char *Api_Version, int *Keep_me_running )
{
	if(IsInitialized)return;
	CAPI_Impl::On_Start(MDInstance,MDWnd,Log_Set,DLL_ID,My_Hot_Key,Api_Version,Keep_me_running);
	//State variables..
	OnEmunationInit();
	*Keep_me_running=1;
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::ShowDialog(int dlgID)
{
	switch (dlgID){
	case IDD_DLG_MAIN:
		if(!m_hwnd_console)
			CreateDialog(m_hDLL,MAKEINTRESOURCE(dlgID),DVBCoreFlag?NULL:m_MultiDecWindow,DllMainDlgFunc);  
		break;
		
	case IDD_DLG_ABOUT:
		DialogBox(m_hDLL,MAKEINTRESOURCE(dlgID),m_MultiDecWindow,DllAboutDlgFunc);	
		break;
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::PushMessage(int msgtype,char* msg)
{
	switch(msgtype)
	{
	case MSG_INFO:
		strncpy(m_infotext,msg,sizeof(m_infotext));
		if(m_hwnd_console){
			SetDlgItemText(m_hwnd_console,IDC_SYS,m_infotext);
		}
		
		break;
	case MSG_MESSAGE:
		if(m_hwnd_console)
		{
			if(msg[strlen(msg)-1]=='\n')msg[strlen(msg)-1]='\0';
			SendMessage(GetDlgItem(m_hwnd_console,IDC_LST_MSG),LB_ADDSTRING,0,(LPARAM)msg);
			int count=SendMessage(GetDlgItem(m_hwnd_console,IDC_LST_MSG),LB_GETCOUNT,0,0);
			if(count>12)
				SendMessage(GetDlgItem(m_hwnd_console,IDC_LST_MSG),LB_SETTOPINDEX,(WPARAM)count-12,0);
			
		}
		break;
	case MSG_ECM:
		if(m_hwnd_console)
		{
			SetDlgItemText(m_hwnd_console,IDC_ECM,msg);
		}
		break;
	case MSG_KEY:
		if(m_hwnd_console)
		{
			SetDlgItemText(m_hwnd_console,IDC_KEY,msg);
		}
		break;
	case MSG_DATAFLOW:
		if(m_hwnd_console)
		{
			SetDlgItemText(m_hwnd_console,IDC_DATAFLOW,msg);
		}
		break;
	case MSG_PIDINFO:
		if(m_hwnd_console)
		{
			SetDlgItemText(m_hwnd_console,IDC_STC_PID,msg);
		}
		break;
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StartECMFilter(TProgramm82* CurrentProgramm)
{
#ifdef THREADED_STATE_CONTROL
	return SignalStartFilter(EVENT_STARTECMFILTER);
#else
	return StartECMFilter_TH(CurrentProgramm);
#endif
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StartEMMFilter(TProgramm82* CurrentProgramm)
{
#ifdef THREADED_STATE_CONTROL
	return SignalStartFilter(EVENT_STARTEMMFILTER);
#else
	return StartEMMFilter_TH(CurrentProgramm);
#endif
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StartDataFilter()
{
#ifdef THREADED_STATE_CONTROL
	return SignalStartFilter(EVENT_STARTPMTFILTER);
#else
	return StartDataFilter_TH();
#endif
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::UpdatePIDInfo(int FilterID)
{
	if(!m_hwnd_console) return;
	char txt[20];
	switch(FilterID)
	{
	case DATA_FILTER_ID:
		sprintf(txt,"PMT:0X%.4X(%d)",m_curprg.PMT_pid,m_curprg.PMT_pid);
		break;
	case ECM_FILTER_ID:
		sprintf(txt,"ECM:0X%.4X(%d)",m_curprg.CA_System[m_curecmindex].ECM,m_curprg.CA_System[m_curecmindex].ECM);
		break;
	case EMM_FILTER_ID:
		sprintf(txt,"EMM:0X%.4X(%d)",m_curprg.CA_System[0].EMM,m_curprg.CA_System[0].EMM);
		break;
	};
	PushMessage(MSG_PIDINFO,txt);
}

void DllClass::InitializeMenu()
{
	HMENU EmuMenu;	  
	if(m_DLLInstance.DVBCoreFlag)
	{
		EmuMenu = GetMenu(m_hwnd_console);
	}
	else
	{
		EmuMenu = GetMenu(m_MultiDecWindow);
	}
	
	CheckMenuItem(EmuMenu,IDM_ACTIVE,m_plg_active? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(EmuMenu,IDM_AUTO_PID,m_isautoecm? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(GetMenu(m_MultiDecWindow),IDM_READPMT,m_readpmt? MF_CHECKED:MF_UNCHECKED);
	
	CheckMenuItem(EmuMenu,IDM_LOGECMTEXT,m_logger.GetActive(cLogger::ECM_Text)? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(EmuMenu,IDM_LOGECMBIN,m_logger.GetActive(cLogger::ECM_Bin)? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(EmuMenu,IDM_LOGEMMTEXT,m_logger.GetActive(cLogger::EMM_Text)? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(EmuMenu,IDM_LOGEMMBIN,m_logger.GetActive(cLogger::EMM_Bin)? MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(EmuMenu,IDM_LOGCW,m_logger.GetActive(cLogger::DCW)? MF_CHECKED:MF_UNCHECKED);
	
	
	
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
void DllClass::On_Channel_Change_TH( const struct TProgramm82 &CurrentProgramm )
{
	
	StopEMMFilter();
	StopECMFilter();  
	StopDataFilter();
	m_pmtok=false;
	// m_clearfilter_event = true;
	ClearAllData();
	
	//Menu Initialization
	InitializeMenu();
	
	m_curecmindex=0;
	PushMessage(MSG_KEY,"Key: None"); 
	
	m_logger.OnChannelChange((char*)CurrentProgramm.Name,CurrentProgramm.ECM_PID,m_emmfilter.Pid);
	
	if(m_plg_active&&m_readpmt)
	{
		StartDataFilter();
		//Log("Fnc :%s Line:%d\n",__FUNCTION__,__LINE__);
		
	}else
	{
		if(m_plg_active&&CurrentProgramm.CA_Anzahl>0)
		{
			// Log("Fnc :%s Line:%d\n",__FUNCTION__,__LINE__);
			if(!StartECMFilter((TProgramm82*)&CurrentProgramm))
			{
				Log("[ERROR] Cannot start pid filter!\n");
			}
			
		}
	} 
}
void MAIN_CTRL(void* impl)
{
	DllClass* imp=(DllClass*)impl;
	imp->On_Channel_Change_TH(imp->m_curprg);
	imp->Log("OnChannelChange Thread\n");
	while (!imp->IsChChanged) Sleep(50);
	imp->StopEMMFilter();
	imp->StopECMFilter();  
	imp->StopDataFilter();
	imp->m_pmtok=false;
	// m_clearfilter_event = true;
	imp->ClearAllData();
}
void DllClass::On_Channel_Change( const struct TProgramm82 &CurrentProgramm )
{
	if(!DVBCoreFlag)
	{	 
		CAPI_Impl::On_Channel_Change(CurrentProgramm);
		Get_Programm_Detail(&m_curprg);
	}
#ifdef MAIN_LOOP_THREADED
	IsChChanged = true;
	Sleep(100);
	IsChChanged = false;
	_beginthread( MAIN_CTRL, 0, this );
#else
	On_Channel_Change_TH( CurrentProgramm );
#endif
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::FoundKey()
{	 
	TProgramm82 curprg;
	Log("[INFO] Found Keys!\n");
	StopEMMFilter();
	ClearAllData();
	if(!DVBCoreFlag)
		Get_Programm_Detail(&curprg);
    m_curecmindex=0;

	StartECMFilter(&curprg);
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

char* TrimSpaces(char* line,char* trimmed)
{
	int tind=0;
	
	char* len =line +strlen(line);
	
	memset(trimmed,0,sizeof(trimmed));
	while(line!=len)
	{
		if(*line==';'||*line=='\0')break;
		trimmed[tind]=*line;
		tind++;line++;
		if(isspace(*line)){
			line=skipspace(line);
			trimmed[tind]=' ';
			tind++;
		}
	}
	if(trimmed[tind-1]==' ')tind--;
	trimmed[tind]='\0';
	return trimmed;
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::SaveKey(char type,int keyid,int keynr,unsigned char* key,int keylen,unsigned char* oldkey)
{
	if(oldkey==NULL) return;
    char keyfilestr[_MAX_PATH];
    char tempfilestr[_MAX_PATH];

    sprintf(keyfilestr,"%s\\%s",dlldirPath,"EmuKeys.key");
    sprintf(tempfilestr,"%s\\%s",dlldirPath,"~tempkeys.key");

    m_DLLInstance.Log("%s\n",keyfilestr);
    m_DLLInstance.Log("%s\n",tempfilestr);

	FILE* keyfile=fopen(keyfilestr,"r");
	FILE* ft=fopen(tempfilestr,"w");
	char oldkeystr[128];
	char newkeystr[128];
	char skeystr[128];
	char date_str[30];
	char cur_key[300];
	bool updated=false;
	const char* _upt_str="%s ; Updated by EmuNation %s\n";
	char _key_str[100];
	
	if (type == 'N')
		strcpy(_key_str,"%c %.4X %.2X %s");
	else
		if (type == 'V')
			strcpy(_key_str,"%c %.6X %.2X %s");
		_strdate(date_str);
		HexStr(skeystr,oldkey,8);
		sprintf(oldkeystr,_key_str,type,keyid,keynr,skeystr);
		HexStr(skeystr,key,8);
		sprintf(newkeystr,_key_str,type,keyid,keynr,skeystr);
		
		if(keyfile)
		{
			char* line;
			char buff[300];
			memset(buff,0,sizeof(buff));
			while(fgets(buff,sizeof(buff),keyfile)) 
			{
				
				line=skipspace(stripspace(buff));	
				if(updated){fprintf(ft,"%s\n",line);continue;}	
				if(line[0]==';'||line[0]=='#')
				{
					fprintf(ft,"%s\n",line);			 
					continue;
				}
				TrimSpaces(line,cur_key);
				
				if(strncmp(cur_key,oldkeystr,strlen(oldkeystr))==0)
				{
					fprintf(ft,_upt_str,newkeystr,date_str);  
					updated=true;
				}
				else
				{
					fprintf(ft,"%s\n",line);  
				}
				
				memset(buff,0,sizeof(buff));
			}
		}
		if(!updated)fprintf(ft,_upt_str,newkeystr,date_str);
		fclose(keyfile);
		fclose(ft);
		remove(keyfilestr);
		rename(tempfilestr,keyfilestr);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::to_binlog(char* filename,unsigned char* data,int length)
{
	FILE* f=fopen(filename,"atb");
	if(f)
	{
		fwrite(data,length,1,f);
		fclose(f);
	}
	
}


//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


void DllClass::InitializeOptions()
{
	m_plg_active=GetPrivateProfileInt("EmuNation","Active",1,INI_FILE);
	m_isautoecm=GetPrivateProfileInt("EmuNation","AutoECM",1,INI_FILE);
	m_readpmt=GetPrivateProfileInt("EmuNation","ReadPMT",1,INI_FILE);
	m_logger.SetActive(GetPrivateProfileInt("Logger","LogDCW",1,INI_FILE),cLogger::DCW);
	m_logger.SetActive(GetPrivateProfileInt("Logger","LogECMBin",1,INI_FILE),cLogger::ECM_Bin);
	m_logger.SetActive(GetPrivateProfileInt("Logger","LogEMMBin",1,INI_FILE),cLogger::EMM_Bin);
	m_logger.SetActive(GetPrivateProfileInt("Logger","LogECMText",1,INI_FILE),cLogger::ECM_Text);
	m_logger.SetActive(GetPrivateProfileInt("Logger","LogEMMText",1,INI_FILE),cLogger::EMM_Text);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::SaveOptions()
{
	WritePrivateProfileInt("EmuNation","Active",m_plg_active,INI_FILE);
	WritePrivateProfileInt("EmuNation","AutoECM",m_isautoecm,INI_FILE);
	WritePrivateProfileInt("EmuNation","ReadPMT",m_readpmt,INI_FILE);
	WritePrivateProfileInt("Logger","LogDCW",m_logger.GetActive(cLogger::DCW),INI_FILE);
	WritePrivateProfileInt("Logger","LogECMBin",m_logger.GetActive(cLogger::ECM_Bin),INI_FILE);
	WritePrivateProfileInt("Logger","LogEMMBin",m_logger.GetActive(cLogger::EMM_Bin),INI_FILE);
	WritePrivateProfileInt("Logger","LogECMText",m_logger.GetActive(cLogger::ECM_Text),INI_FILE);
	WritePrivateProfileInt("Logger","LogEMMText",m_logger.GetActive(cLogger::EMM_Text),INI_FILE);
	
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
unsigned char SAA_COMMAND_DW1[16]={0x07,0x00,0x10,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char SAA_COMMAND_DW2[16]={0x07,0x00,0x10,0x04,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

#define SIZE_HOLD_DATA 26
bool DllClass::IsCWNecessary(unsigned char* _Data)
{
	if(m_prevecmdata)
	{
		if(memcmp(m_prevecmdata,_Data,SIZE_HOLD_DATA)==0) return false;
		else 
		{
			delete [] m_prevecmdata;
			m_prevecmdata=new unsigned char[SIZE_HOLD_DATA];
			memcpy(m_prevecmdata,_Data,SIZE_HOLD_DATA);
			return true;
		}
	}
	else
	{
		m_prevecmdata=new unsigned char[SIZE_HOLD_DATA];
		memcpy(m_prevecmdata,_Data,SIZE_HOLD_DATA);
		return true;
	}
	return true;
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::WriteECM(unsigned char* _Data)
{
	if(m_hwnd_console)
	{
		HexStrSpaced(m_ecmtext,_Data,SCT_LEN((&_Data[1]))&0xBC );
		PushMessage(MSG_ECM,m_ecmtext);
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::Turn(int count)
{
	char str[20];
	const char turn[4]={'-','\\','|','/'};
	
	sprintf(str,"Processing: %c",turn[count%4]);
	PushMessage(MSG_KEY,str);
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void STATE_CONTROL(void* impl)
{
	DllClass* imp=(DllClass*)impl;
	
	while(true)
	{
		if(imp->m_FilterEvents.empty())
		{
			Sleep (10);
			continue;
		}
		if(imp->m_clearfilter_event)
		{
			while(!imp->m_FilterEvents.empty()) imp->m_FilterEvents.pop();
			imp->m_clearfilter_event = false;
			continue;
		}
		imp->PluginEvent = imp->m_FilterEvents.front();
		imp->m_FilterEvents.pop();
		
		switch(imp->PluginEvent)
		{
		case EVENT_STOPPMTFILTER:
			imp->StopDataFilter_TH();
			break;
		case EVENT_STOPEMMFILTER:
			imp->StopEMMFilter_TH();
			break;
		case EVENT_STOPECMFILTER:
			imp->StopECMFilter_TH();
			break;
			//Start events
		case EVENT_STARTPMTFILTER:
			imp->StartDataFilter_TH();
			Sleep(100);
			break;
		case EVENT_STARTEMMFILTER:
			imp->StartEMMFilter_TH(&(imp->m_curprg));
			
			break;
		case EVENT_STARTECMFILTER:
			imp->StartECMFilter_TH(&(imp->m_curprg));
			Sleep(100);
			break;
		}
		imp->PluginEvent=EVENT_IDLE;
		Sleep(10);
	}
	_endthread();
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::StopDataFilter()
{
#ifdef THREADED_STATE_CONTROL
	return SignalStopFilter(EVENT_STOPPMTFILTER);
#else
	return StopDataFilter_TH();
#endif
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::SignalStartFilter (int type)
{
	//PluginEvent=type;
	//while(PluginEvent!=EVENT_IDLE)Sleep(1);
	m_FilterEvents.push(type);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::SignalStopFilter (int type)
{
	//PluginEvent=type;
	//while(PluginEvent!=EVENT_IDLE)Sleep(1);
	m_FilterEvents.push(type);
}
//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

bool DllClass::ProcessPMT(unsigned char* _Data,int DataLen)
{
#ifdef PMT_PROCESSING
	m_dvbp.SetBuffer(&_Data[1],DataLen,cDVBParser::DVB_PACKETTYPE_MDAPI);
	
	if(m_dvbp.AnalyzePacket(cDVBParser::DVB_PACKETMODE_SECTION))
	{
		cPMT* pmt=(cPMT*)m_dvbp.GetPacketData();
		if(pmt->program_number!=m_curprg.SID_pid)return false;
		Log("Channel:%s SID:%d\n",m_curprg.Name,m_curprg.SID_pid);
		StopDataFilter();
		ClearAllData();
		//SignalStopFilter(EVENT_STOPPMTFILTER);
		cMPEGCADescriptor* data;
		Log("------------CA TABLE------------\n");
		//if(m_curprg.CA_Anzahl==0) return true;
		for(int i=0;i<pmt->Count();i++)
		{
			data=(cMPEGCADescriptor*)pmt->Get(i);
			Log("System:%.4X PID:%.4X PRV:%.6X\n",data->CA_system_ID,data->CA_PID,data->prov_id);
			m_curprg.CA_System[i].ECM=data->CA_PID;
			m_curprg.CA_System[i].CA_Typ=data->CA_system_ID;
			m_curprg.CA_System[i].Provider_Id=data->prov_id;
		}
		m_curprg.CA_Anzahl=pmt->Count();
		if(m_curprg.CA_Anzahl>0)
			StartECMFilter(&m_curprg);
		return true;
		
	}
	return false;
#endif
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

unsigned char cw_p[16]={0};

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::SendDCW(unsigned char* cw)
{
	//Fix Checksum
	cw[3]=cw[0]+cw[1]+cw[2]; 
	cw[7]=cw[4]+cw[5]+cw[6];
	cw[11]=cw[8]+cw[9]+cw[10]; 
	cw[15]=cw[12]+cw[13]+cw[14];
	
	for(int i=0,j=1;i<8;i+=2,j+=2)
	{
		SAA_COMMAND_DW1[j+8]=cw[i];
		SAA_COMMAND_DW2[j+8]=cw[i+8];
		
		SAA_COMMAND_DW1[j-1+8]=cw[i+1];
		SAA_COMMAND_DW2[j-1+8]=cw[i+9];
		
	}
	
	TDVB_COMMAND dw1,dw2;
	memcpy(&dw1,SAA_COMMAND_DW1,sizeof(SAA_COMMAND_DW1));
	memcpy(&dw2,SAA_COMMAND_DW2,sizeof(SAA_COMMAND_DW2));
	//SendMessage(m_MultiDecWindow,WM_USER,MDAPI_DVB_COMMAND,(LONG)&SAA_COMMAND_DW1);
	//SendMessage(m_MultiDecWindow,WM_USER,MDAPI_DVB_COMMAND,(LONG)&SAA_COMMAND_DW2);
	m_logger.LogData(cw,16,cLogger::DCW);
	if(memcmp(cw_p,cw,8)!=0)
	{
		if(!DVBCoreFlag)
		{
			SendMDCommand(dw1);
			SendTTCommand(dw1);
		}
		else
			_DVBSendSAACmd(dw1.Cmd_Buffer,dw1.Cmd_laenge);
		
	}
	
	if(memcmp(cw_p+8,cw+8,8)!=0)
	{
		if(!DVBCoreFlag)
		{
			SendMDCommand(dw2);
			SendTTCommand(dw2);
		}
		else
			_DVBSendSAACmd(dw2.Cmd_Buffer,dw2.Cmd_laenge);
	}
	memcpy(cw_p,cw,16);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------
bool DllClass::GetState()
{
	return ThreadState;
}

void DATA_FLOW(void* impl)
{
	
	DllClass* imp=(DllClass*)impl;
	FILTERDATA d,d1,d2;
	// imp->LOG_DEBUG_PLG("Start")
	while(imp->GetState())
	{
		if(imp->m_clearevent)
		{
			while(!imp->m_PMTq.empty())imp->m_PMTq.pop();
			while(!imp->m_ECMq.empty())imp->m_ECMq.pop();
			while(!imp->m_EMMq.empty())imp->m_EMMq.pop();
			imp->m_clearevent=false;
			continue;
		}
		if(!imp->m_PMTq.empty())
		{
			
			d=imp->m_PMTq.front();
			imp->ProcessPMTData(&d);
			imp->m_PMTq.pop();
			imp->UpdatePIDInfo(DATA_FILTER_ID);
			
		}
		if(!imp->m_EMMq.empty())
		{
			d1=imp->m_EMMq.front();
			imp->ProcessEMMData(&d1);
			imp->m_EMMq.pop();
			imp->UpdatePIDInfo(EMM_FILTER_ID);
		}
		if(!imp->m_ECMq.empty())
		{
			d2=imp->m_ECMq.front();
			imp->ProcessECMData(&d2);
			imp->m_ECMq.pop();
			imp->UpdatePIDInfo(ECM_FILTER_ID);
		}
		
		Sleep(10);
	}
	// imp->LOG_DEBUG_PLG("END")
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------

void DllClass::ClearAllData()
{
	m_clearevent=true;
	Sleep(50);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


void DllClass::ProcessPMTData(FILTERDATA* fltdata)
{
	unsigned char* _Data=fltdata->Data;
	
	if(!m_pmtok)
	{
		if(ProcessPMT(_Data,184))m_pmtok=true;
	}
	
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


void DllClass::ProcessECMData(FILTERDATA* fltdata)
{
	unsigned char* _Data=fltdata->Data;
	int DataLen=184;
	
	cEcmInfo ecminfo(m_curprg.Name,m_curprg.CA_System[m_curecmindex].ECM,m_curprg.CA_System[m_curecmindex].CA_Typ,m_curprg.CA_System[m_curecmindex].Provider_Id);	
	ecminfo.SetSource(m_curprg.SID_pid,0,m_curprg.freq/1000);
	PushMessage(MSG_DATAFLOW,(char*)(m_flow%2?"*":" "));
	m_flow++;
	
	
	if (m_cursys)
	{	
		if(!IsCWNecessary(_Data)) return;
		
		
		if(m_cursys->ProcessECM(&ecminfo,&_Data[1]))
		{
			SendDCW(m_cursys->CW());
			
			m_logger.LogData(_Data,184,cLogger::ECM_Text);
			m_logger.LogData(_Data,184,cLogger::ECM_Bin);
			
			WriteECM(_Data);
			sprintf(m_keystr,"Key :%s",m_cursys->CurrentKeyStr());
			PushMessage(MSG_KEY,m_keystr);	
			
			return; 	
		}
		else
		{
			//If cannot decode
			if(strcmp("Nagra",m_cursys->Name())==0
				//				 ||strcmp("Viaccess",m_cursys->Name())==0
				//				 ||strcmp("Seca",m_cursys->Name())==0
				)
			{
				//If nagra need auto update
				StopECMFilter();
				ClearAllData();
				//SignalStopFilter(EVENT_STOPECMFILTER);
				StartEMMFilter(&m_curprg);
				strcpy(m_ecmtext,"No data present for saving CPU time!");
				PushMessage(MSG_ECM,m_ecmtext);
				return;
			}
		}
	}
	
	
	if(m_isautoecm&&m_curprg.CA_Anzahl>m_curecmindex+1)
	{
		m_curecmindex++;
		StopECMFilter();
		ClearAllData();
		//SignalStopFilter(EVENT_STOPECMFILTER);
		//Sleep(50);
		StartECMFilter(&m_curprg);					 
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


void DllClass::ProcessEMMData(FILTERDATA* fltdata)
{
	unsigned char* _Data=fltdata->Data;
	int DataLen=184;
	
	if (m_cursys)
	{
		if(++m_emmcount> 10000)
		{
			Log("[ERROR]EMM Filter Time Out.\n");
			StopEMMFilter();
			ClearAllData();
			//SignalStopFilter(EVENT_STOPEMMFILTER);
		}
		cEcmInfo emminfo(m_curprg.Name,m_curprg.CA_System[0].EMM,m_curprg.CA_System[0].CA_Typ,m_curprg.CA_System[0].Provider_Id);	
		m_cursys->ProcessEMM(m_curprg.CA_System[0].EMM,&emminfo,&_Data[1],183);
		
		m_logger.LogData(_Data,184,cLogger::EMM_Text);
		m_logger.LogData(_Data,184,cLogger::EMM_Bin);
		
		Turn(m_emmcount);
	}
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


void DllClass::On_Filter_Data_Arrival(int MyFilter, int DataLen, unsigned char *_Data)
{
	FILTERDATA d;
	//	  Log("Filter data: %x\n Data Len:%d",MyFilter,DataLen);
	for(int i=0;i<DataLen/184;i++)
	{
		d.FilterID=MyFilter;
		memcpy(d.Data,&_Data[184*i],184);
		switch(d.FilterID)
		{
		case DATA_FILTER_ID:
#ifdef THREADED_DATA_FLOW
			m_PMTq.push(d);
#else
			ProcessPMTData(&d);
			UpdatePIDInfo(DATA_FILTER_ID);
#endif
			break;
		case EMM_FILTER_ID:
#ifdef THREADED_DATA_FLOW
			m_EMMq.push(d);
#else
			ProcessEMMData(&d);
			UpdatePIDInfo(EMM_FILTER_ID);
#endif
			break;
		case ECM_FILTER_ID:
#ifdef THREADED_DATA_FLOW
			m_ECMq.push(d);
#else
			ProcessECMData(&d); 		   
			UpdatePIDInfo(ECM_FILTER_ID);
#endif
			break;
		};
		
	}
	
	
}
////////////////////////////////////////////////////////////////////////////
//Globals																  //
////////////////////////////////////////////////////////////////////////////


BOOL APIENTRY DllAboutDlgFunc(HWND hDlg,UINT message,UINT wParam,LONG lParam)
{
	switch (message) 
	{
	case WM_INITDIALOG:
		break;
	case WM_COMMAND:
		if ((LOWORD(wParam) == IDOK ) || (LOWORD(wParam) == IDCANCEL )) 
		{
			EndDialog(hDlg,TRUE);
		}
		break;	   
	}
	return(FALSE);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


BOOL APIENTRY DllMainDlgFunc(HWND hDlg,UINT message,UINT wParam,LONG lParam)
{
	static HMENU DVBCoreMenu=NULL;
	switch (message) 
	{
	case WM_INITDIALOG:
		{
			char txt[1024]="";
			char item[256]="";
			if (m_DLLInstance.DVBCoreFlag)
			{
				sprintf(txt,"DVBCore");
				DVBCoreMenu=LoadMenu(m_DLLInstance.GetDLLInstance(),"DVBCOREMENU");
				SetMenu(hDlg,DVBCoreMenu);
				RECT rc;
                GetWindowRect(hDlg,&rc);
                SetWindowPos(hDlg,NULL,0,0,rc.right-rc.left,rc.bottom-rc.top+15,
                SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE);
			}
			else
			{
				
				if(g_API_Impl->MDAPIFlag())
					sprintf(item,"MDAPI (8.2): %02d.%02d  ",g_API_Impl->MDVersionMajor(),g_API_Impl->MDVersionMinor());
				else 
					sprintf(item,"MDAPI (<=8.1b)  ");
				strcpy(txt,item);
				if(g_API_Impl->WTVPAPIFlag())
					sprintf(item,"WTVP API: %02d.%02d  ",g_API_Impl->WTVPVersionMajor(),g_API_Impl->WTVPVersionMinor());
				else
					sprintf(item,"");
				strcat(txt,item);
				if(g_API_Impl->PROGAPIFlag())
				{
					sprintf(item,"PROG API: %02d.%02d  ",g_API_Impl->PROGVersionMajor(),g_API_Impl->PROGVersionMinor());
					strcat(txt,item);
				}
			}
			m_DLLInstance.m_hwnd_console=hDlg;
			SetDlgItemText(hDlg,IDC_VERSION,txt);
			SetDlgItemText(hDlg,IDC_SYS,m_DLLInstance.m_infotext);
			SetDlgItemText(hDlg,IDC_KEY,m_DLLInstance.m_keystr);
			m_DLLInstance.InitializeMenu();
			char line[256];
			FILE* f=fopen("emulog.txt","r");
			if(f)
			{
				while(fgets(line,sizeof(line),f))
				{
					line[strlen(line)-1]='\0';
					SendMessage(GetDlgItem(hDlg,IDC_LST_MSG),LB_ADDSTRING,0,(LPARAM)line);
					
				}
				int count=SendMessage(GetDlgItem(hDlg,IDC_LST_MSG),LB_GETCOUNT,0,0);
				if(count>12)
					SendMessage(GetDlgItem(hDlg,IDC_LST_MSG),LB_SETTOPINDEX,(WPARAM)count-12,0);
			}
			
		}
		break;
	case WM_COMMAND:
		if ((LOWORD(wParam) == IDOK ) || (LOWORD(wParam) == IDCANCEL )) 
		{
			m_DLLInstance.m_hwnd_console=NULL;
			if (m_DLLInstance.DVBCoreFlag)
				DestroyMenu(DVBCoreMenu);
			EndDialog(hDlg,TRUE);
		}
        if(m_DLLInstance.DVBCoreFlag)
            switch(LOWORD(wParam))
            {
                case IDM_ACTIVE ... IDM_LOGCW :
                    m_DLLInstance.On_Menu_Select(LOWORD(wParam));
                break;
            };

		break;
	case WM_SYSCOMMAND:
		if (wParam==SC_CLOSE)
		{
			m_DLLInstance.m_hwnd_console=NULL;
			EndDialog(hDlg,TRUE);
		}
		break;
	}
	
	return(FALSE);
}

//------------------------------------------------------------------------------
//Private member variables
//------------------------------------------------------------------------------


extern "C" __declspec (dllexport) BOOL APIENTRY DllMain (HINSTANCE hInst	 /* Library instance handle. */ ,DWORD reason		 /* Reason this function is being called. */ ,LPVOID reserved	  /* Not used. */ )
{
	m_DLLInstance.DllMain(hInst,reason,reserved);
	return TRUE;
}
