// ChildView.cpp : implementation of the CChildView class
//

#include "stdafx.h"
#include "mw4print.h"
#include "ChildView.h"
#include "cspcfd.h"

#include "MechLabHeaders.h"
#include "GameTypes.h"

#include "mw4dummy.h"
#include "recscore.h"
#include "dbexport.h"
typedef unsigned long UINT4;
typedef unsigned char* POINTER;
#include "logreport.h"

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

#include "mw4dummy.cpp"
#include "recscore.cpp"
#include "dbexport.cpp"
#include "logreport.cpp"

#define IDT_TIMER           1000

BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
	ON_COMMAND(ID_FILE_LOGREPORT, OnFileLogReport)
	ON_COMMAND(ID_FILE_LOG2DATES, OnFileLog2Dates)
	ON_COMMAND(ID_FILE_DBSETTINGS, OnFileDbSettings)
	ON_COMMAND(ID_FILE_BANNERSETTING, OnFileBannerSetting)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CDlgDBSettings, CDialog)
	ON_BN_CLICKED(IDC_DB_TEST, OnTestConnection)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CDlgGet2Dates, CDialog)
	//{{AFX_MSG_MAP(CDlgGet2Dates)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

bool _stdcall RunExec(const CStr& strExec)
{
    if (strExec.GetLength() > 0) {
        CStr strDir;
        int nStart = 0, nLen;
        const char* pcszExec = strExec.String();
        if (*pcszExec == '"') {
            nStart++;
            nLen = strExec.Find('"');
            if (nLen != -1) {
                nLen--;
            }
        } else {
            nLen = strExec.Find(' ');
        }
        strDir.Assign(&pcszExec[nStart], nLen);
        strDir.AsDirectory(TRUE);

        char szBuf[512];
        strcpy(szBuf, strExec.String());
        STARTUPINFO si;
        memset(&si, 0, sizeof(si));
        si.cb = sizeof(si);
        si.dwX = si.dwY = si.dwXSize = si.dwYSize = CW_USEDEFAULT;
        PROCESS_INFORMATION pi;
    
        return !!CreateProcess(NULL, szBuf, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP | HIGH_PRIORITY_CLASS, NULL, strDir.String(), &si, &pi);
    }

    return false;
}

CMyPrintInfo::CMyPrintInfo(const char* pcszFile, bool bIncludeBot)
    : m_strFile(pcszFile), m_bIncludeBot(bIncludeBot), m_bPrinted(false)
{
}

CLogInfo::CLogInfo()
{
    m_nState = 1; // 0: no error(ok!!!), 1: (@err=1), error, 2: launched(@Launched=1)...
    m_strTime = 0; // Time=%02d:%02d
    m_nPlayerCount = 0; // Player Count=%d
}

CLogResult::CLogResult()
{
	m_nTotalPlayers = 0;
	m_nGames = 0;
	m_nUnfinished = 0;
	m_nErrGames = 0;
	m_dwRet = 0;
}

void CLogResult::GetLogResult(const CString& str)
{
	m_nGames = 0, m_nTotalPlayers = 0, m_nUnfinished = 0, m_nErrGames = 0;
	m_dwRet = 0;

	SLogReport* pRPT = SLogReport::OpenLogReport(str, *(SYSTEMTIME*)NULL, FALSE);
	if (pRPT) {
		SLogItem* pStart = pRPT->GetFirst();
		SLogItem* pEnd = pRPT->GetLast();
		while(pStart < pEnd)
		{
			if ((0 < pStart->m_nPlayers) && (pStart->m_nPlayers <= 16)) {
				if (pStart->m_nLaunched) {
					m_nUnfinished++;
				} else if (pStart->m_nErr) {
					m_nErrGames++;
				} else {
					m_nGames++;
					m_nTotalPlayers += pStart->m_nPlayers;
				}
			}
			pStart = pStart->GetNext();
		}
	} else {
		CStr strFile(str);
		
		strFile.ChangeExt(".log", TRUE);

		int nBufferSize = (36 + 1) * 2000;
		char* psz = (char*)malloc(nBufferSize);
		DoLogReport(strFile, psz, nBufferSize);
		free(psz);
	}
	if (pRPT) {
		m_dwRet = pRPT->m_dwSigns;
		SLogReport::FreeLogReport(pRPT);
	}
}

void CLogResult::DoLogReport(const CStr& str, char* psz, int nBufferSize)
{
    TARRAYREF(CLogInfo) aLogs;
    char szBuf[256];

    GetPrivateProfileString(NULL, NULL, "", psz, nBufferSize, str);
    while(*psz)
    {
        int nPlayerCount = GetPrivateProfileInt(psz, "Player Count", 0, str);
        if ((0 < nPlayerCount) && (nPlayerCount <= 16)) {
            int nState;
            if (GetPrivateProfileInt(psz, "@err", 0, str)) {
                nState = 1;
            } else if (GetPrivateProfileInt(psz, "@Launched", 0, str)) {
                nState = 2;
            } else {
                nState = 0;
            }
            GetPrivateProfileString(psz, "Time", "", szBuf, sizeof(szBuf), str);
            CLogInfo& log = aLogs.Add();
            log.m_nState = nState;
            log.m_strTime = szBuf;
            log.m_nPlayerCount = nPlayerCount;
        }
        psz = &psz[strlen(psz) + 1];
    }
    int i, nSize = aLogs.GetSize();

    for(i = 0; i < nSize; i++)
    {
        const CLogInfo& log = aLogs.GetAt(i);
		if (log.m_nState == 2) {
			m_nUnfinished++;
		} else if (log.m_nState == 1) {
			m_nErrGames++;
        } else {
			ASSERT(log.m_nState == 0);
            m_nGames++;
            m_nTotalPlayers += log.m_nPlayerCount;
        }
    }
}

CShortDate::CShortDate(const CTime& t)
{
	m_nYear = t.GetYear();
	m_nMonth = t.GetMonth();
	m_nDay = t.GetDay();
}

int CShortDate::Compare(const CShortDate& that)
{
	ASSERT(this && &that);

	int nDif;

	nDif = m_nYear - that.m_nYear;
	if (nDif == 0) {
		nDif = m_nMonth - that.m_nMonth;
		if (nDif == 0) {
			nDif = m_nDay - that.m_nDay;
		}
	}

	return nDif;
}

void CShortDate::IncADay()
{
	int nDayEnd = GetDayEnd(m_nYear, m_nMonth);
	if (++m_nDay >= nDayEnd) {
		m_nDay = 1;
		if (++m_nMonth >= 12) {
			m_nMonth = 1;
			m_nYear++;
		}
	}
}

CDlgGet2Dates::CDlgGet2Dates(SYSTEMTIME& SysTime, CWnd* pParent /*=NULL*/)
	: CDialog(CDlgGet2Dates::IDD, pParent), m_Start(SysTime), m_End(SysTime)
{
	//{{AFX_DATA_INIT(CDlgGet2Dates)
	//}}AFX_DATA_INIT
	//m_Start = 0;
	//m_End = 0;
}

void CDlgGet2Dates::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgGet2Dates)
	//}}AFX_DATA_MAP
	DDX_DateTimeCtrl(pDX, IDC_DNT_END, m_End);
	DDX_DateTimeCtrl(pDX, IDC_DNT_START, m_Start);
}

BOOL CDlgGet2Dates::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

CChildView::CChildView()
{
    m_uTimer = 0;
}

CChildView::~CChildView()
{
}

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
	
	// Do not call CWnd::OnPaint() for painting messages
}

bool CChildView::DoCopyData(HWND hwnd, const MW4PRINT_COPYDATASTRUCT& cd)
{
    hWindow = m_hWnd;
    if ((cd.dwData == MW4PRINT_COPYDATA_META) && (cd.cbData == sizeof(cd) - sizeof(COPYDATASTRUCT)) && cd.lpData) {
        const GUID& guid = *(const GUID*)cd.lpData; // do not use cd.m_GUID
        const char* pcsz = (const char*)&(&guid)[1]; // do not use cd.m_szFile

#ifdef _DEBUG
        g_bPRTest = true;
#else // _DEBUG
        g_bPRTest = false;
#endif // _DEBUG
        CMyPrintInfo* p = new CMyPrintInfo(pcsz, g_bPRTest);
        m_lstMPIs.AddTail(p);

        return true;
    }

    return false;
}

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd ::OnCreate(lpCreateStruct) == -1)
		return -1;

    DB_LoadConfig();

    m_uTimer = SetTimer(IDT_TIMER, 1 * 1000, NULL);
    if (!m_uTimer)
        return -1;
	
	return 0;
}

void CChildView::OnDestroy() 
{
    if (m_uTimer) {
        KillTimer(m_uTimer);
        m_uTimer = 0;
    }
	CWnd ::OnDestroy();
}

void CChildView::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
    if (nIDEvent == IDT_TIMER) {
        CMyPrintInfo* p = m_lstMPIs.GetHead();
        while(p) {
            if (!p->m_bPrinted) {
                hWindow = m_hWnd;
                g_bPRTest = p->m_bIncludeBot;
                if (g_RSF.LoadPR(p->m_strFile)) {
                    int nErr = g_RSF.DoPrint();
                    if (nErr == 0) {
                        p->m_bPrinted = true;
                        m_lstMPIs.Cut(p);
                        delete p;
                    }
                }
                g_RSF.Reset();
                break;
            }
            p = p->m_pNext;
        }
    }
	
	CWnd ::OnTimer(nIDEvent);
}

void CChildView::OnFileBannerSetting()
{
    CDlgBannerSetting dlg(this);
    dlg.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CDlgBannerSetting

CDlgBannerSetting::CDlgBannerSetting(CWnd* pParent)
    : CDialog(CDlgBannerSetting::IDD, pParent)
{
}

BEGIN_MESSAGE_MAP(CDlgBannerSetting, CDialog)
END_MESSAGE_MAP()

void CDlgBannerSetting::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BOOL CDlgBannerSetting::OnInitDialog()
{
    CDialog::OnInitDialog();
    SetDlgItemText(IDC_BANNER_TEXT, g_szPrintBanner);
    return TRUE;
}

void CDlgBannerSetting::OnOK()
{
    GetDlgItemText(IDC_BANNER_TEXT, g_szPrintBanner, sizeof(g_szPrintBanner));

    // Persist to options.ini so it survives a restart.
    char szINI[MAX_PATH];
    sprintf(szINI, "%s\\options.ini", AssetsDirectory1);
    WritePrivateProfileString("battle tech print", "BannerText", g_szPrintBanner, szINI);

    CDialog::OnOK();
}

void CChildView::OnFileDbSettings()
{
    CDlgDBSettings dlg(this);
    dlg.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CDlgDBSettings

CDlgDBSettings::CDlgDBSettings(CWnd* pParent)
    : CDialog(CDlgDBSettings::IDD, pParent)
{
}

void CDlgDBSettings::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BOOL CDlgDBSettings::OnInitDialog()
{
    CDialog::OnInitDialog();

    CheckDlgButton(IDC_DB_ENABLED,      g_dbConfig.bEnabled      ? BST_CHECKED : BST_UNCHECKED);
    CheckDlgButton(IDC_DB_EXPORTEVENTS, g_dbConfig.bExportEvents  ? BST_CHECKED : BST_UNCHECKED);

    SetDlgItemText(IDC_DB_HOST,     g_dbConfig.szHost);
    SetDlgItemInt (IDC_DB_PORT,     g_dbConfig.nPort, FALSE);
    SetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase);
    SetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername);
    SetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword);

    SetDlgItemText(IDC_DB_STATUS, "");

    return TRUE;
}

void CDlgDBSettings::OnOK()
{
    g_dbConfig.bEnabled      = IsDlgButtonChecked(IDC_DB_ENABLED)      == BST_CHECKED;
    g_dbConfig.bExportEvents  = IsDlgButtonChecked(IDC_DB_EXPORTEVENTS) == BST_CHECKED;

    GetDlgItemText(IDC_DB_HOST,     g_dbConfig.szHost,     sizeof(g_dbConfig.szHost));
    g_dbConfig.nPort = (int)GetDlgItemInt(IDC_DB_PORT, NULL, FALSE);
    GetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase, sizeof(g_dbConfig.szDatabase));
    GetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername, sizeof(g_dbConfig.szUsername));
    GetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword, sizeof(g_dbConfig.szPassword));

    DB_SaveConfig();
    CDialog::OnOK();
}

void CDlgDBSettings::OnTestConnection()
{
    // Read fields into a temporary config so we test what's in the UI,
    // not necessarily what was last saved.
    SDBConfig saved = g_dbConfig;

    GetDlgItemText(IDC_DB_HOST,     g_dbConfig.szHost,     sizeof(g_dbConfig.szHost));
    g_dbConfig.nPort = (int)GetDlgItemInt(IDC_DB_PORT, NULL, FALSE);
    GetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase, sizeof(g_dbConfig.szDatabase));
    GetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername, sizeof(g_dbConfig.szUsername));
    GetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword, sizeof(g_dbConfig.szPassword));

    SetDlgItemText(IDC_DB_STATUS, "Testing...");
    UpdateWindow();

    char szError[512] = "";
    bool bOK = DB_TestConnection(szError, sizeof(szError));
    SetDlgItemText(IDC_DB_STATUS, bOK ? "OK - Connected successfully." : szError);

    g_dbConfig = saved;   // restore; OnOK() will save the final values
}

void CChildView::OnFileOpen() 
{
	// TODO: Add your command handler code here
    const char* pcszFilters = "Battle Tech Print File(*.pr)|*.pr|All Files(*.*)|*.*|";
    CSpcFileDialog FD(TRUE, ".pr", NULL, OFN_HIDEREADONLY, pcszFilters, this);
    FD.SetTitle("Open : *.Pr");
    FD.SetFilterIndex(1);
    FD.EnableHook("Include &Bot");
    //FD.SetCustomFilter();
    if (FD.DoModal() == IDOK) {
#ifdef _DEBUG
        g_bPRTest = true;
#else // !_DEBUG
        g_bPRTest = (FD.m_ofn.Flags & OFN_READONLY) ? true: false;
#endif // _DEBUG
        CString str(FD.GetPathName());
        CMyPrintInfo* p = new CMyPrintInfo(str, g_bPRTest);
        m_lstMPIs.AddTail(p);
    }
}

void CChildView::OnFileLogReport() 
{
	// TODO: Add your command handler code here
    SYSTEMTIME SysTime;
    GetLocalTime(&SysTime); // GetSystemTime

    char szPath[MAX_PATH];

	AdjustSysTimeForLog(SysTime);
    sprintf(szPath, "c:\\mw4files\\%02d_%02d_%d.rpt", SysTime.wMonth, SysTime.wDay, SysTime.wYear);

    const char* pcszFilters = "Battle Tech Report File(*.rpt)|*.rpt|All Files(*.*)|*.*|";
    CSpcFileDialog FD(TRUE, ".rpt", szPath, OFN_HIDEREADONLY, pcszFilters, this);
    FD.SetTitle("Open : *.Rpt");
    FD.SetFilterIndex(1);
    if (FD.DoModal() == IDOK) {
        CString str(FD.GetPathName());

		CLogResult lr;
		
		lr.GetLogResult(str);

		int nPos = str.ReverseFind('\\');
		if (nPos == -1) {
			nPos = str.ReverseFind('/');
		}
		CStr strFile(&((const char*)str)[nPos + 1]);
		strFile.ChangeExt("", TRUE);

		char szBuf[256 * 3];
		sprintf(szBuf, "%s\n\n%d total players, %d Games", strFile.String(), lr.m_nTotalPlayers, lr.m_nGames);
		if (lr.m_nUnfinished) {
			sprintf(&szBuf[strlen(szBuf)], "\n\nUnfinished Games: %d", lr.m_nUnfinished);
		}
		if (lr.m_nErrGames) {
			sprintf(&szBuf[strlen(szBuf)], "\n\nError Games: %d", lr.m_nErrGames);
		}
		if (lr.m_dwRet == LRPT_FILE_ERR)
			strcat(szBuf, "\n\nPrevious LogData lost!!!");
		else if (lr.m_dwRet == LRPT_FILE_ERR2)
			strcat(szBuf, "\n\nLogData broken!!!");

		MessageBox(szBuf, "Log Report");
    }
}

void CChildView::OnFileLog2Dates() 
{
    SYSTEMTIME SysTime;
    GetLocalTime(&SysTime); // GetSystemTime

	CDlgGet2Dates dlg(SysTime, this);

	BOOL bSuccess = FALSE;
	while(dlg.DoModal() == IDOK)
	{
		CString str;

		CShortDate Start(dlg.m_Start);
		CShortDate End(dlg.m_End);

		if (Start.Compare(End) > 0) {
			MessageBox("Start date should be <= End Date");
			continue;
		}
		if (Start.m_nYear < 2002) {
			MessageBox("Start year should be >= 2002");
			continue;
		}

		CStrArray aStrs;
		BOOL bDone = false;

		int nTotalPlayers = 0;
		int nGames = 0;
		int nUnfinished = 0;
		int nErrGames = 0;
		int nErr1 = 0;
		int nErr2 = 0;
		int nDays = 0;

		do
		{
			if (Start.Compare(End) == 0)
				bDone = TRUE;

			CString strDate;
			strDate.Format("c:\\mw4files\\%02d_%02d_%d.rpt", Start.m_nMonth, Start.m_nDay, Start.m_nYear);

			CLogResult lr;
			lr.GetLogResult(strDate);

			nTotalPlayers += lr.m_nTotalPlayers;
			nGames += lr.m_nGames;
			nUnfinished += lr.m_nUnfinished;
			nErrGames += lr.m_nErrGames;
			int n1 = 0, n2 = 0;
			if (lr.m_dwRet == LRPT_FILE_ERR) {
				nErr1++;
				n1++;
			} else if (lr.m_dwRet == LRPT_FILE_ERR2) {
				nErr2++;
				n2++;
			}

            // comment out below if-block for off day!!!
			CStr& str = aStrs.Add();
            //if (lr.m_nTotalPlayers || lr.m_nGames || lr.m_nUnfinished || lr.m_nErrGames || n1 || n2) {
			str.Format("%02d/%02d/%04d, %6d, %5d, %5d, %5d, %4d, %4d\r\n",
				Start.m_nMonth, Start.m_nDay, Start.m_nYear,
				lr.m_nTotalPlayers, lr.m_nGames, lr.m_nUnfinished, lr.m_nErrGames,
				n1, n2);
            //} else {
			//    str.Format("%02d/%02d/%04d no records\r\n", Start.m_nMonth, Start.m_nDay, Start.m_nYear);
            //}
			Start.IncADay();
			nDays++;
		} while(!bDone);
		CStr& strD = aStrs.Add();
		strD.Format("===================================================\r\n"
			        "mm/dd/year, #Plyrs, Games, Unfin, #Errs, Lost, Brkn\r\n");

		CStr& strT = aStrs.Add();
		strT.Format("%5d days, %6d, %5d, %5d, %5d, %4d, %4d\r\n",
			nDays, nTotalPlayers, nGames, nUnfinished, nErrGames,
			nErr1, nErr2);

		int nTotal = aStrs.GetTotalLength();
		HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE, nTotal);
		if (hMem) {
			LPVOID p = GlobalLock(hMem);
			if (p) {
				char* psz = (char*)p;
				CStr* pStart = &aStrs.GetAt(0);
				CStr* pEnd = &pStart[aStrs.GetSize()];
				while(pStart < pEnd)
				{
					strcpy(psz, pStart->String());
					psz += pStart->GetLength();
					pStart++;
				}
				*psz = '\0';

                HANDLE handle = CreateFile("c:\\mw4files\\report.txt",
                    GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (handle) {
                    DWORD dwWritten;
                    WriteFile(handle, p,  psz - (char*)p, &dwWritten, NULL);
                    CloseHandle(handle);
                   
                    CStr strExec;
#if 0
                    //char szBuf[256];
                    //GetWindowsDirectory(szBuf, sizeof(szBuf));
                    //strExec.Format("\"%s\\system32\\notepad.exe\" /p c:\\mw4files\\report.txt", szBuf);
#else
                    strExec.Format("c:\\mw4files\\notepad.exe /p c:\\mw4files\\report.txt", AssetsDirectory1);
                    //strExec.Format("\"%s\\notepad.exe\" /p c:\\mw4files\\report.txt", AssetsDirectory1);
#endif
                    RunExec(strExec);
                }

				if (OpenClipboard()) {
					EmptyClipboard();
					if (SetClipboardData(CF_TEXT, hMem)) {
						bSuccess = TRUE;
						hMem = NULL;
					}
					CloseClipboard();
				}
			}
			if (hMem) {
				GlobalFree(hMem);
				hMem = NULL;
			}
		}
		if (bSuccess) {
			MessageBox("LOG data is printed & placed in (CLIPBOARD & c:\\mw4files\\report.txt)");
		} else {
			//MessageBox("");
		}
		break;
	}
}
