// ConsoleTransfer.cpp : 응용 프로그램에 대한 클래스 동작을 정의합니다.
//

#include "stdafx.h"
#include "ConsoleTransfer.h"

#include <psapi.h.>
#include <math.h.>

#include "CustomControlSite.h"
#include "TransferDlg.h"
#include "Options.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


bool ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead);
bool ShutDownSystem(UINT uFlags);

//#define _TEST

// CConsoleTransferApp

BEGIN_MESSAGE_MAP(CConsoleTransferApp, CWinApp)
	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()


// CConsoleTransferApp 생성

CConsoleTransferApp::CConsoleTransferApp()
{
	// TODO: 여기에 생성 코드를 추가합니다.
	// InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

CConsoleTransferApp::~CConsoleTransferApp()
{
	if (m_pimpldisp)
		delete m_pimpldisp;
}


// 유일한 CConsoleTransferApp 개체입니다.

CConsoleTransferApp theApp;


// CConsoleTransferApp 초기화

BOOL CConsoleTransferApp::InitInstance()
{
	// 응용 프로그램 매니페스트가 ComCtl32.dll 버전 6 이상을 사용하여 비주얼 스타일을
	// 사용하도록 지정하는 경우, Windows XP 상에서 반드시 InitCommonControls()가 필요합니다. 
	// InitCommonControls()를 사용하지 않으면 창을 만들 수 없습니다.
	InitCommonControls();

	CWinApp::InitInstance();

	CCustomOccManager *poccmgr = new CCustomOccManager;
	m_pimpldisp = new CImpIDispatch;
	AfxEnableControlContainer(poccmgr);

#ifdef _TEST
	bool bRet = false;

	CTransferDlg dlg;
	m_pMainWnd = &dlg;

	dlg.m_pszFileList = NULL;

	dlg.m_tp.hwnd = NULL;
//	dlg.m_tp.nAction = TPA_UPLOAD;
	dlg.m_tp.nAction = TPA_DOWNLOAD;
	dlg.m_tp.nFileListSize = 11;
	dlg.m_tp.nFreeBytes = -1;
	strcpy(dlg.m_tp.szHost, "222.122.136.201/dav");
//	strcpy(dlg.m_tp.szHost, "192.168.0.203/dav");
	strcpy(dlg.m_tp.szDstPath, "");
	strcpy(dlg.m_tp.szDstPath, "G:\\");
	dlg.m_tp.szProxyHost[0] = NULL;
	dlg.m_tp.nProxyPort = 0;
	strcpy(dlg.m_tp.szUserId, "0udisk@unizit");
	strcpy(dlg.m_tp.szPassword, "0udisk");
//	strcpy(dlg.m_tp.szUserId, "192@dosoar");
//	strcpy(dlg.m_tp.szPassword, "dosoar");

	dlg.m_pszFileList = new char[100];
	if (!dlg.m_pszFileList)
		goto EXIT_PROGRAM;

	strcpy(dlg.m_pszFileList, "/HODOLi.avi");
//	strcpy(dlg.m_pszFileList, "E:\\Game\\F.E.A.R\\FEAR.mdf");
//	strcpy(dlg.m_pszFileList, "E:\\마이클조던_베스트40.avi");
#else
	if (!IsValidCommand())
		return FALSE;

	bool bRet = false;

	CTransferDlg dlg;
	m_pMainWnd = &dlg;
	CString	strTemp;

	dlg.m_pszFileList = NULL;

	// 파이프 핸들 열기...
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 
	if (hStdin == INVALID_HANDLE_VALUE)
		goto EXIT_PROGRAM;

	// 파라미터 구조체 내용 읽기...
	if (!ReadFile(hStdin, &dlg.m_tp, sizeof(dlg.m_tp)))
		goto EXIT_PROGRAM;

	dlg.m_pszFileList = new char[dlg.m_tp.nFileListSize];
	if (!dlg.m_pszFileList)
		goto EXIT_PROGRAM;

	if (!ReadFile(hStdin, dlg.m_pszFileList, dlg.m_tp.nFileListSize))
		goto EXIT_PROGRAM;
#endif

	dlg.DoModal();

	bRet = true;

EXIT_PROGRAM:
	if (dlg.m_pszFileList)
		delete []dlg.m_pszFileList;

	::PostMessage(dlg.m_tp.hwnd, WMU_TRANSFER_DLG_CLOSE, (WPARAM)dlg.m_tp.pParam, NULL);

	if (!IsExistsSameProcess()) {
		int nAfterExec = COptions::GetOptionVal(OPTION_AFTEREXEC);
		if (nAfterExec > 0) {
//			UINT uFlags = bForceKill ? EWX_FORCE : 0;
			UINT uFlags = 0;

			switch (nAfterExec) {
			case 1: uFlags |= EWX_LOGOFF;   break;
			case 2: uFlags |= EWX_REBOOT;   break;
			case 3: uFlags |= EWX_SHUTDOWN; break;
			}

			ShutDownSystem(uFlags);
		}
	}

	// 대화 상자가 닫혔으므로 응용 프로그램의 메시지 펌프를 시작하지 않고
	// 응용 프로그램을 끝낼 수 있도록 FALSE를 반환합니다.
	return FALSE;
}

bool CConsoleTransferApp::IsValidCommand()
{
	return strcmp(m_lpCmdLine, EXECUTE_PARAM) == 0;
}

#define MAX_PROCESS 1000

bool CConsoleTransferApp::IsExistsSameProcess()
{
	bool bRet = false;

	LPDWORD pdwProcessId = new DWORD[MAX_PROCESS];
	if (!pdwProcessId)
		return true;

	DWORD dwCount;
	if (!EnumProcesses(pdwProcessId, sizeof(DWORD) * MAX_PROCESS, &dwCount))
		goto EXIT_FUNCTION;

	dwCount /= sizeof(DWORD);

	char szModuleName[MAX_PATH];
	if (!GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH))
		goto EXIT_FUNCTION;

	int  nFound = 0;
	char szFileName[MAX_PATH];
	for (DWORD i = 0; i < dwCount; i++) {
		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pdwProcessId[i]);
		if (!hProcess)
			continue;

		if (!GetModuleFileNameEx(hProcess, NULL, szFileName, MAX_PATH))
			continue;

		if (strcmp(szFileName, szModuleName) == 0)
			nFound++;
	}

	if (nFound <= 1)
		bRet = true;

EXIT_FUNCTION:
	if (pdwProcessId)
		delete []pdwProcessId;

	return !bRet;
}


CString GetErrorMessage(DWORD dwError)
{
	CString sError;
	LPVOID lpBuffer;

	if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpBuffer, 0, NULL))
		sError = "알 수 없는 오류입니다.";
	else
		sError = (LPCTSTR)lpBuffer;
 
	LocalFree(lpBuffer);

	return sError;
}

bool CreateDirectory(CString sDirectory)
{
	CString sPath = "";

	int     iToken = 0;
	CString sText  = sDirectory.Tokenize("\\", iToken);
	while (sText != "") {
		sPath += sText + "\\";

		if (sPath.GetLength() > 3 && !CreateDirectory(sPath, NULL)) {
			DWORD dwError = GetLastError();

			if (dwError != 183) {
				SetLastError(dwError);
				return false;
			}
		}

		sText  = sDirectory.Tokenize("\\", iToken);
	}

	return true;
}

bool DeleteDirectory(CString sDirectory)
{
	// no UI
	if (sDirectory.Right(1) != _T("\\"))
		sDirectory += _T("\\");

	sDirectory += _T("*");

	CFileFind finder;

	BOOL bFound = finder.FindFile(sDirectory);
	while (bFound) {
		bFound = finder.FindNextFile();

		if (finder.IsDots())
			continue;

		if (finder.IsDirectory()) {
			if (!DeleteDirectory(finder.GetFilePath()))
				return false;
		}
		else {
			if (!DeleteFile(finder.GetFilePath()))
				return false;
		}
	}
	finder.Close();

	sDirectory = sDirectory.Left(sDirectory.ReverseFind('\\'));
	RemoveDirectory(sDirectory);

	return true;
}

CString NumericFormat(__int64 nNumeric)
{
    CString sNumeric;
    sNumeric.Format("%I64d", nNumeric);

	int nStartPos = sNumeric.GetLength();
	for (int i = nStartPos, j = 0; i > 0; i--, j++) {
		if (i != nStartPos && (j % 3) == 0)
		sNumeric.Insert(i, ',');
	}

	return sNumeric;
}

CString NumericFormatWithPoint(long double nNumeric)
{
    CString sNumeric;
    sNumeric.Format("%.2f", nNumeric);

	int nStartPos = sNumeric.Find('.');
	for (int i = nStartPos, j = 0; i > 0; i--, j++) {
		if (i != nStartPos && (j % 3) == 0)
		sNumeric.Insert(i, ',');
	}

	return sNumeric;
}

CString BYTE2KMBYTE(__int64 nBytes, int nFlag, BOOL bShowDecimalPoint)
{
	CString sValue;

	char* szUnit[] = {"Bytes", "KB", "MB", "GB", "TB", "PB"};

	if (nFlag == 0) {
		for (nFlag = 5; nFlag > 0; nFlag--)
			if (((UINT64)nBytes >> (nFlag * 10)) >= 1)
				break;
	}

	double nPow = pow(1024.0, (double)nFlag);
	if (bShowDecimalPoint && nFlag > 0)
		sValue = NumericFormatWithPoint((long double)nBytes / nPow) + szUnit[nFlag];
	else
		sValue = NumericFormat((__int64)ceil((long double)nBytes / nPow)) + szUnit[nFlag];

	return sValue;
}

CString BYTE2KMBIT(__int64 nBytes, int nFlag, BOOL bShowDecimalPoint)
{
	CString sValue;

	char* szUnit[] = {"", "K", "M", "G", "T", "P"};

	if (nFlag == 0) {
		for (nFlag = 5; nFlag > 0; nFlag--)
			if (((UINT64)nBytes >> (nFlag * 10)) >= 1)
				break;
	}

	double nPow = pow(1024.0, (double)nFlag);
	if (bShowDecimalPoint && nFlag > 0)
		sValue = NumericFormatWithPoint((long double)nBytes / nPow) + szUnit[nFlag];
	else
		sValue = NumericFormat((__int64)ceil((long double)nBytes / nPow)) + szUnit[nFlag];

	return sValue;
}

bool ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead)
{
	DWORD dwRead;
	while (nNumberOfBytesToRead > 0) {
		if (!ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, &dwRead, NULL))
			return false;

		nNumberOfBytesToRead -= dwRead;
	}

	return true;
}

bool ShutDownSystem(UINT uFlags)
{
	bool bRet = false;

	if (uFlags == EWX_LOGOFF) {
		bRet = ExitWindowsEx(uFlags, 0) ? true : false;
	}
	else {
		UINT uVersion = GetVersion();

		if (uVersion < 0x80000000) { // If OS is like WinNT
			HANDLE           hToken;
			TOKEN_PRIVILEGES tp;

			if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
				return false;
	 
			if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid))
				return false;

			tp.PrivilegeCount           = 1; 
			tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

			if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
				return false;

			if (!InitiateSystemShutdown(NULL, NULL, 0, TRUE, (uFlags & EWX_REBOOT)))
				return false;

			bRet = true;
		}
		else {
			bRet = ExitWindowsEx(uFlags, 0) ? true : false;
		}
	}

	return bRet;
}
