// RealPlayDlg.cpp : implementation file
//
#include "stdafx.h"
#include "dhnetsdk.h"
#include "RealPlay.h"
#include "RealPlayDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRealPlayDlg dialog

CRealPlayDlg::CRealPlayDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRealPlayDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRealPlayDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_nThreadNum = 0;
	m_nTimerId = 0;
	m_nSeletItem = 0;
	InitializeCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRealPlayDlg)
	DDX_Control(pDX, IDC_LIST_DEVINFO, m_ctlDevInfo);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CRealPlayDlg, CDialog)
	//{{AFX_MSG_MAP(CRealPlayDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_LOADCONFIG, OnButtonLoadconfig)
	ON_BN_CLICKED(IDC_BUTTON_PLAY, OnButtonPlay)
	ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
	ON_BN_CLICKED(IDC_BUTTON_STOPALL, OnButtonStopall)
	ON_WM_TIMER()
	ON_NOTIFY(NM_CLICK, IDC_LIST_DEVINFO, OnClickListDevinfo)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRealPlayDlg message handlers

void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser) 
{ 
    CRealPlayDlg * pThis = (CRealPlayDlg *)dwUser; 
    if(NULL == pThis) 
    { 
        return; 
    }

	pThis->OnDisConnect(lLoginID, pchDVRIP, nDVRPort);
    return; 
}

void CALLBACK RealDataCallBackEx(LLONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, LONG param, LDWORD dwUser)
{
	Channel_Info* pChannelInfo = (Channel_Info*)dwUser;
	if (pChannelInfo != NULL)
	{
		pChannelInfo->dwStatistic = dwBufSize;
	}
}

void CRealPlayDlg::RoutineLoginThread(void* lParam)
{	
	Thread_Info* pThreadInfo = (Thread_Info*)lParam;
	if (pThreadInfo != NULL)
	{
		CRealPlayDlg* pDlg = (CRealPlayDlg*)pThreadInfo->dwUserInfo;
		if (pDlg != NULL)
		{
			pDlg->LogDevs(pThreadInfo->nThreadIndex);
		}
	}
	if (NULL != pThreadInfo)
	{
		delete pThreadInfo;
		pThreadInfo = NULL;
	}

}

BOOL CRealPlayDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	g_SetWndStaticText(this);

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	m_ctlDevInfo.SetExtendedStyle(m_ctlDevInfo.GetExtendedStyle() | LVS_EX_FULLROWSELECT);
	m_ctlDevInfo.InsertColumn(0, ConvertString(_T("No.")), LVCFMT_LEFT, 30, -1);
	m_ctlDevInfo.InsertColumn(1, ConvertString(_T("IP")), LVCFMT_LEFT, 100, -1);
	m_ctlDevInfo.InsertColumn(2, ConvertString(_T("On Line")), LVCFMT_LEFT, 80, -1);
	m_ctlDevInfo.InsertColumn(3, ConvertString(_T("Channel Count")), LVCFMT_LEFT, 80, -1);
	char szTemp[16] = {0};
	for (int i = 1; i <= 16; i++)
	{
		itoa(i, szTemp, 10);
		m_ctlDevInfo.InsertColumn(3 + i, szTemp, LVCFMT_LEFT, 80, -1);
	}

	// init sdk
	CLIENT_Init(DisConnectFunc, (LDWORD)this);

	// set timer
	SetTimer(0, 1000, NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CRealPlayDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CRealPlayDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CRealPlayDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

DWORD CRealPlayDlg::GetPrivateProfileString(
											  LPCTSTR lpAppName,        // section name
											  LPCTSTR lpKeyName,        // key name
											  LPCTSTR lpDefault,        // default string
											  LPTSTR lpReturnedString,  // destination buffer
											  DWORD nSize,              // size of destination buffer
											  LPCTSTR lpFileName        // initialization file name
											  )
{
	if(NULL == lpReturnedString || nSize <= 0)
	{
		return -2;
	}
	memset(lpReturnedString, 0, nSize);
	
	fpos_t pos = {0};
	char*  pBuf = NULL;
	FILE* pFile = fopen(lpFileName, "r");
	
	if(NULL == pFile)
	{
		return -3;
	}
	fseek(pFile, 0, SEEK_END);
	if(	fgetpos(pFile, &pos) != 0)
	{
		fclose(pFile);
		return -1;
	}
	
	int npos = 0;
	npos = pos+1;
	
	
	if(npos <= 0)
	{
		fclose(pFile);
		return -1;
	}
	pBuf = new char[npos];
	if(NULL == pBuf)
	{
		fclose(pFile);
		return -1;
	}
	memset(pBuf, 0, npos);
	fseek(pFile, 0, SEEK_SET);
	int nRead = fread(pBuf, sizeof(char), (int)npos, pFile);
	fclose(pFile);
	_strlwr(pBuf);
	
	char szAppName[128] = {0};
	char szKeyName[128] = {0};
	strcpy(szAppName, lpAppName);
	strcpy(szKeyName, lpKeyName);
	_strlwr(szAppName);
	_strlwr(szKeyName);
	char* pLeftSeciton = NULL;
	char* pRightSection = NULL;
	char* pKeySection = NULL;
	DWORD dwSize = 0;
	pLeftSeciton = strstr(pBuf, szAppName);
	if(pLeftSeciton != NULL)
	{
		pRightSection = strstr(pLeftSeciton, "[");
		if(pRightSection == NULL)
		{
			pRightSection = pBuf + nRead;
		}
		pKeySection = strstr(pLeftSeciton, szKeyName);
	}
	
	if(NULL == pLeftSeciton || NULL == pKeySection || pKeySection < pLeftSeciton || pKeySection >pRightSection)//关键字不在范围之内
	{
		dwSize = nSize<strlen(lpDefault) ? nSize-1 : strlen(lpDefault);
		memcpy(lpReturnedString, lpDefault, dwSize);
		delete []pBuf;
		return dwSize;
	}
	pLeftSeciton = strstr(pKeySection, "=");
	pRightSection = strstr(pKeySection, "\n");

	if(NULL != pRightSection && NULL != pLeftSeciton && pRightSection > pLeftSeciton)
	{
		dwSize = (nSize -1) < (pRightSection-pLeftSeciton-1) ? (nSize-1) : (pRightSection-pLeftSeciton-1);
		memcpy(lpReturnedString, pLeftSeciton+1, dwSize);
	}
	delete []pBuf;
	return dwSize;
}

BOOL CRealPlayDlg::ReadConfigFile()
{
	char szSection[128]; 
    char ip[64]; 
    char port[8]; 
    char username[16]; 
    char password[16]; 
    char connect_num[8]; 
    char thread_num[8] ={0}; 
    
	CString strFilePath;
	const char fileDialogFilter[] = 
		"dav Files (*.ini)|*.ini|All Files (*.*)|*.*||";
	CFileDialog fileDialog(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,fileDialogFilter,NULL);//);
	
	if(fileDialog.DoModal() == IDOK)
	{
		strFilePath = fileDialog.GetPathName();
	}
	else
	{
		return FALSE;
	}
	
    GetPrivateProfileString("thread", "threadnum", "", thread_num, 8, strFilePath); 
    
    m_nThreadNum = atoi(thread_num); 
    
    int nIndexCount = 0;
    
    for(int i = 0; i < m_nThreadNum; i++) 
    {	 
        for(int j = 0; ; j++) 
        { 
            sprintf(szSection, "thread%d.device%d", i, j); 
			char szInternalTime[8] = {0};
            int nSize = GetPrivateProfileString(szSection, "ip", "", ip, 64, strFilePath);
            if(strcmp(ip, "") == 0) 
            {    
                break; 
            } 
            
            nSize = GetPrivateProfileString(szSection, "port", "", port, 8, strFilePath); 
            nSize = GetPrivateProfileString(szSection, "username", "", username, 16, strFilePath); 
			
            nSize = GetPrivateProfileString(szSection, "password", "", password, 16, strFilePath); 
            
            nSize = GetPrivateProfileString(szSection, "connectnum", "", connect_num, 8, strFilePath); 
            int nConnectCount = atoi(connect_num); 
            
            for(int k = 0; k < nConnectCount; k++) 
            { 
                Device_Info* device_info = new Device_Info; 
                if(NULL == device_info) 
                { 
					continue; 
                } 
                memset(device_info, 0, sizeof(Device_Info)); 
                strcpy(device_info->szDevIp, ip); 
                device_info->nPort = atoi(port); 
                strcpy(device_info->szUserName, username);
                strcpy(device_info->szPassWord, password); 
                
                device_info->nBelongThread = i; 
                device_info->nIndex = nIndexCount;
				device_info->nTimeCount = 0;
				EnterCriticalSection(&m_csDeviceInfo);
                m_lsDeviceInfo.push_back(device_info); 
				LeaveCriticalSection(&m_csDeviceInfo);
                nIndexCount++;
            } 
        } 
    } 

	return TRUE;
}

void CRealPlayDlg::OnDisConnect(LONG lLoginID, char *pchDVRIP, LONG nDVRPort)
{
	EnterCriticalSection(&m_csDeviceInfo);
    
    std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
        Device_Info *pDeviceInfo = *it;
        
        if (pDeviceInfo != NULL)
        {
            if (pDeviceInfo->lLoginHandle == lLoginID)
            {
                pDeviceInfo->bOnline = FALSE;
				int nChannelCount = pDeviceInfo->nChannelCount < 16 ? pDeviceInfo->nChannelCount : 16;
                for(int i = 0; i < nChannelCount; i++)
                {
                    pDeviceInfo->channel[i].dwStatistic = 0;
                }
                break;
            }
        }
        
        it++;
    }

	LeaveCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::LogDevs(int nThreadId)
{
	NET_DEVICEINFO_Ex stDevInfo = {0};
	int nError = 0;
	int nChannelCount = 0;

	EnterCriticalSection(&m_csDeviceInfo);
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it++;
		if (pDevice_info == NULL)
		{
			continue;
		}
		
		if (pDevice_info->nBelongThread == nThreadId)
		{
			memset(&stDevInfo, 0, sizeof(stDevInfo));
			nError = 0;
			pDevice_info->lLoginHandle = CLIENT_LoginEx2(pDevice_info->szDevIp, pDevice_info->nPort, pDevice_info->szUserName, 
                                                         pDevice_info->szPassWord, EM_LOGIN_SPEC_CAP_TCP, NULL,
                                                         &stDevInfo, &nError);
			if (pDevice_info->lLoginHandle != 0)
			{
				// log success
				pDevice_info->bOnline = 1;
				pDevice_info->nChannelCount = stDevInfo.nChanNum;
				nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
				for (int i = 0; i < nChannelCount; i++)
				{
					pDevice_info->channel[i].lRealPlayHandle = CLIENT_RealPlayEx(pDevice_info->lLoginHandle, i, NULL, DH_RType_Realplay);
					pDevice_info->channel[i].dwStatistic = 0;
					if (pDevice_info->channel[i].lRealPlayHandle != 0)
					{
						CLIENT_SetRealDataCallBackEx(pDevice_info->channel[i].lRealPlayHandle, RealDataCallBackEx, (LDWORD)&(pDevice_info->channel[i]), 1);
					}
				}
			}
		}
	}//while

	LeaveCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::ShowDevsInfo()
{
	EnterCriticalSection(&m_csDeviceInfo);

	char szTemp[32] = {0};
	int nIndex = 0;
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it;
		if (pDevice_info != NULL)
		{
			nIndex = pDevice_info->nIndex;

			itoa(nIndex, szTemp, 10);
			m_ctlDevInfo.SetItemText(nIndex, 0, szTemp);
			
			m_ctlDevInfo.SetItemText(nIndex, 1, pDevice_info->szDevIp);
			
			itoa(pDevice_info->bOnline, szTemp, 10);
			m_ctlDevInfo.SetItemText(nIndex, 2, szTemp);
			
			itoa(pDevice_info->nChannelCount,szTemp, 10);
			m_ctlDevInfo.SetItemText(nIndex, 3, szTemp);

			int	nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
			for (int i = 0; i < nChannelCount; i++)
			{
				itoa(pDevice_info->channel[i].dwStatistic, szTemp, 10);
				m_ctlDevInfo.SetItemText(nIndex, 3+i+1, szTemp);
			}
		}

		it++;
	}

	LeaveCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::OnButtonLoadconfig() 
{
	// clean
	m_nThreadNum = 0;
	EnterCriticalSection(&m_csDeviceInfo);
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it;
		
		if (pDevice_info != NULL && pDevice_info->lLoginHandle!= 0)
		{
			CLIENT_Logout(pDevice_info->lLoginHandle);
			int nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
			for (int i = 0; i < nChannelCount; i++)
			{
				if (pDevice_info->channel[i].lRealPlayHandle != 0)
				{
					CLIENT_StopRealPlayEx(pDevice_info->channel[i].lRealPlayHandle);
				}
			}
			
			delete pDevice_info;
		}
		m_lsDeviceInfo.erase(it++);
		
	}
	LeaveCriticalSection(&m_csDeviceInfo);
	
	// read config file
	BOOL bRet=FALSE;
	bRet=ReadConfigFile();
	if (bRet)
	{
		// log device	
		int i = 0;
		Thread_Info* pThreadInfo = NULL;
		for (i = 0; i < m_nThreadNum; i++)
		{
			pThreadInfo = new Thread_Info;
			if (pThreadInfo)
			{
				pThreadInfo->dwUserInfo = (DWORD)this;
				pThreadInfo->nThreadIndex = i;
				int nThreadId = 0;
				HANDLE hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RoutineLoginThread, pThreadInfo, 0, (LPDWORD)&nThreadId);
			}
		}


		char szTemp[16] = {0};
		m_ctlDevInfo.DeleteAllItems();
		m_nSeletItem = 0;
		int nListSize = m_lsDeviceInfo.size();
		for (i = 0; i < nListSize; i++)
		{
			itoa(i, szTemp, 10);
			m_ctlDevInfo.InsertItem(LVIF_TEXT|LVIF_STATE,0, szTemp, 0,LVIS_SELECTED,0,0);
		}
	}	
}

void CRealPlayDlg::OnButtonPlay() 
{	
	int nChannelCount = 0;
	EnterCriticalSection(&m_csDeviceInfo);
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it++;
		if (pDevice_info != NULL && pDevice_info->nIndex == m_nSeletItem)
		{
			nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
			for (int i = 0; i < nChannelCount; i++)
			{
				if (pDevice_info->channel[i].lRealPlayHandle == 0)
				{
					pDevice_info->channel[i].lRealPlayHandle = CLIENT_RealPlayEx(pDevice_info->lLoginHandle, i, NULL, DH_RType_Realplay);
					pDevice_info->channel[i].dwStatistic = 0;
					if (pDevice_info->channel[i].lRealPlayHandle != 0)
					{
						CLIENT_SetRealDataCallBackEx(pDevice_info->channel[i].lRealPlayHandle, RealDataCallBackEx, (LDWORD)&(pDevice_info->channel[i]), 1);
					}
				}
			}
		}
	}//while
	
	LeaveCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::OnButtonStop() 
{	
	int nChannelCount = 0;
	EnterCriticalSection(&m_csDeviceInfo);
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it++;
		if (pDevice_info != NULL && pDevice_info->nIndex == m_nSeletItem)
		{
			nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
			for (int i = 0; i < nChannelCount; i++)
			{
				if (pDevice_info->channel[i].lRealPlayHandle != 0)
				{
					CLIENT_StopRealPlayEx(pDevice_info->channel[i].lRealPlayHandle);
					pDevice_info->channel[i].lRealPlayHandle = 0;
					pDevice_info->channel[i].dwStatistic = 0;
				}
			}
		}
	}//while
	
	LeaveCriticalSection(&m_csDeviceInfo);
}

void CRealPlayDlg::OnButtonStopall() 
{
	int nChannelCount = 0;
	EnterCriticalSection(&m_csDeviceInfo);
	std::list<Device_Info*>::iterator it = m_lsDeviceInfo.begin();
	while (it != m_lsDeviceInfo.end())
	{
		Device_Info* pDevice_info = *it++;
		if (pDevice_info == NULL)
		{
			continue;
		}

		nChannelCount = pDevice_info->nChannelCount < 16 ? pDevice_info->nChannelCount : 16;
		for (int i = 0; i < nChannelCount; i++)
		{
			if (pDevice_info->channel[i].lRealPlayHandle != 0)
			{
				CLIENT_StopRealPlayEx(pDevice_info->channel[i].lRealPlayHandle);
				pDevice_info->channel[i].lRealPlayHandle = 0;
				pDevice_info->channel[i].dwStatistic = 0;
			}
		}
	}//while
	
	LeaveCriticalSection(&m_csDeviceInfo);
}
//#ifdef WIN64
void CRealPlayDlg::OnTimer(UINT_PTR nIDEvent) 
//#else ifdef WIN32
//void CRealPlayDlg::OnTimer(UINT nIDEvent) 
//#endif
{
	// TODO: Add your message handler code here and/or call default
	ShowDevsInfo();

	CDialog::OnTimer(nIDEvent);
}

void CRealPlayDlg::OnClickListDevinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
	if (phdn->iItem == -1)
	{
		return;
	}
	
	m_nSeletItem = phdn->iItem;
	
	*pResult = 0;
}
