// 04WebServer.cpp : アプリケーションのクラス動作を定義します。
//

#include "stdafx.h"
#include "04WebServer.h"
#include "04WebServerDlg.h"
#include <initguid.h>
#include "04WebServer_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMy04WebServerApp


class CMy04WebServerModule :
	public CAtlMfcModule
{
public:
	DECLARE_LIBID(LIBID_My04WebServerLib);
	DECLARE_REGISTRY_APPID_RESOURCEID(IDR_04WEBSERVER_APP, "{53BED338-262D-477B-A927-53861BC1E214}");};

CMy04WebServerModule _AtlModule;

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


// CMy04WebServerApp コンストラクション

CMy04WebServerApp::CMy04WebServerApp()
{
	m_comRegisterd = 0;
	m_server = NULL;
	m_mutex = NULL;
	m_serviceMode = 0;
	m_serverStatus = "サーバは停止中です。";
	m_exitCode = 0;
}


// 唯一の CMy04WebServerApp オブジェクトです。

CMy04WebServerApp theApp;


// CMy04WebServerApp 初期化

BOOL CMy04WebServerApp::InitInstance()
{
	SetServerSecurityDescripter();

	//	COM初期化
	CoInitialize(NULL);
	CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);

	//	いろいろ初期化
	InitCommonControls();
	CWinApp::InitInstance();
	AfxEnableControlContainer();


	// コマンドライン解析
	CString				cmdString = GetCommandOption();
	CCommandLineInfo	cmdInfo;
	ParseCommandLine(cmdInfo);

	if(cmdString.IsEmpty())
	{
		//	指定なしなので、コントローラーをランチ
		CString path = GetAppPath() + "ServerController.exe";
		::ShellExecute(0, _T("open"), path.GetBuffer(0), 0, 0, SW_SHOWNORMAL);
	}
	else if(DoRegister(cmdString))
	{
		//	レジストリ登録処理なので、終了
		return FALSE;
	}
	
	//	多重起動チェック
	if(CheckOther())
	{
		AfxMessageBox("サーバはすでに起動中です、多重起動できません。",MB_ICONSTOP);
		return FALSE;
	}


	//	オプションによって判別
	if(cmdString.CompareNoCase("/Service") == 0)
	{
		//	サービス起動

		//	COM登録
		if(RegisteCOMClassObject())
			return FALSE;

		m_serviceMode = 1;
		m_serviceContext.RunService();
		return FALSE;
	}
	else if(cmdString.CompareNoCase("/Debug") == 0)
	{
		//	デバッグモード

		//	COM登録
		if(RegisteCOMClassObject())
			AfxMessageBox("COMの登録に失敗しました、COMオブジェクトがサービス登録のようです。");

		//	デバッグ実行？
		CMy04WebServerDlg dlg;
		m_pMainWnd = &dlg;
		dlg.DoModal();

		return FALSE;
	}
	else
	{
		//	アプリケーションモード

		//	COM登録
		if(RegisteCOMClassObject())
			return FALSE;

		return TRUE;
	}
}

//	各種レジストリ処理
int CMy04WebServerApp::DoRegister(CString command)
{
	if(command.CompareNoCase("/UnInstall") == 0)
	{
		//	コントローラ停止
		KillAllController();

		// 全て削除
		RegisterApp(FALSE);
		RegisterService(FALSE);
		return TRUE;
	}
	else if(command.CompareNoCase("/InstallApp") == 0)
	{
		// アプリケーションモードで登録
		RegisterApp(TRUE);
		return TRUE;
	}
	else if (command.CompareNoCase("/InstallService") == 0)
	{
		// アプリケーションモードで登録
		RegisterService(TRUE);
		return TRUE;
	}
	else if(command.CompareNoCase("/UnInstallApp") == 0)
	{
		//	コントローラ停止
		KillAllController();

		// アプリケーションモード削除
		RegisterApp(FALSE);
		return TRUE;
	}
	else if (command.CompareNoCase("/UnInstallService") == 0)
	{
		//	コントローラ停止
		KillAllController();

		// サービスモード削除
		RegisterService(FALSE);
		return TRUE;
	}
	else if (command.CompareNoCase("/IsRunning") == 0)
	{
		// 実行中か検出
		m_exitCode = CheckOther();
		return TRUE;
	}
	return FALSE;
}



//	モジュールパスを取得
CString CMy04WebServerApp::GetAppPath(int directoryPath)
{
	char	s[MAX_PATH+1];
	DWORD len = GetModuleFileName(NULL, s, MAX_PATH);

	if(directoryPath)
	{
		while ( s[len--]!='\\' && len!=0 )
			;
		s[len+2] = '\0';        // ￥マークで終わらせる
	}

	return(s);
}

//	終了
int CMy04WebServerApp::ExitInstance()
{
	//	念のため、停止する
	StopServer();

	//	COM削除
	RemoveCOMClassObject();

	//	多重起動フラグ解除
	if(m_mutex)
		::CloseHandle(m_mutex);

	CoUninitialize();

	CWinApp::ExitInstance();
	return m_exitCode;
}

//	サーバを起動します
int CMy04WebServerApp::StartServer()
{
	SCOPE_LOCK();

	//	とりあえず、停止
	StopServer();

	try
	{
		if(m_server == NULL)
			m_server = new CServer();

		m_serverStatus = "サーバは正常に作動中です。";
	}
	catch(CServerException e)
	{
		StopServer();
		m_serverStatus = e.m_info;
		return(-1);
	}

	return(0);
}

//	停止
int CMy04WebServerApp::StopServer()
{
	SCOPE_LOCK();

	if(m_server != NULL)
		delete m_server;
	m_server = NULL;

	m_serverStatus = "サーバは停止中です。";

	return(0);
}

//	エラー情報を取得
CString CMy04WebServerApp::GetServerErrorInfo()
{
	SCOPE_LOCK();

	return(m_serverStatus);
}

//	サーバが実行中か取得する
int CMy04WebServerApp::ServerRunning()
{
	SCOPE_LOCK();

	if(m_server)
		return(TRUE);
	else
		return(FALSE);
}

//	サーバー情報取得
CString CMy04WebServerApp::GetServerInfoXML()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_infoRoot);
		return(copy.ToXMLString());
	}
	else
		return("");
}

//	サーバー設定取得
CString CMy04WebServerApp::GetServerSettingXML()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_settingRoot);
		return(copy.ToXMLString());
	}
	else
		return("");
}

//	サーバー設定取得
CString CMy04WebServerApp::GetServerContextXML()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_context);
		return(copy.ToXMLString());
	}
	else
		return("");
}

//	サーバー情報取得
CString CMy04WebServerApp::GetServerInfoString()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_infoRoot);
		return(copy.ToString());
	}
	else
		return("");
}

//	サーバー設定取得
CString CMy04WebServerApp::GetServerSettingString()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_settingRoot);
		return(copy.ToString());
	}
	else
		return("");
}

//	サーバー設定取得
CString CMy04WebServerApp::GetServerContextString()
{
	SCOPE_LOCK();

	if(m_server)
	{
		CConfig	copy(m_server->m_context);
		return(copy.ToString());
	}
	else
		return("");
}

//	サーバーステータス設定
void CMy04WebServerApp::SetServerStatus(CString stat)
{
	SCOPE_LOCK();

	m_serverStatus = stat;
}

//	接続数の取得
int CMy04WebServerApp::GetConnectCount()
{
	SCOPE_LOCK();

	if(m_server)
	{
		return(m_server->GetConnectCount());
	}
	else
		return(0);
}

//	サービスモード
int CMy04WebServerApp::IsService()
{
	return(m_serviceMode);
}

//	多重起動のチェック
int CMy04WebServerApp::CheckOther()
{
	m_mutex = ::CreateMutex( /*&sa*/NULL, FALSE, "04WebServer" );
	if( ::GetLastError() == ERROR_ALREADY_EXISTS )
	{
		::CloseHandle(m_mutex);
		m_mutex = NULL;
		return TRUE;
	}
	return FALSE;
}

//	サーバが使用するセキュリティ記述子を取得
void CMy04WebServerApp::SetServerSecurityDescripter()
{

	//	既定のDACLを削除
	TOKEN_DEFAULT_DACL	dacl;
	dacl.DefaultDacl = NULL;

	HANDLE	token=NULL;
	::OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_DEFAULT,&token);
	::SetTokenInformation(token,TokenDefaultDacl,&dacl,sizeof(TOKEN_DEFAULT_DACL ));
	::CloseHandle(token);
}

//	CoClass登録
int CMy04WebServerApp::RegisteCOMClassObject()
{
	//	COMオブジェクト登録
	if (FAILED(_AtlModule.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE)))
		return -1;
	m_comRegisterd = 1;

	return 0;
}

//	CoClass削除
void CMy04WebServerApp::RemoveCOMClassObject()
{
	if(m_comRegisterd)
		_AtlModule.RevokeClassObjects();
	m_comRegisterd = 0;
}

//	アプリケーションとして登録
void CMy04WebServerApp::RegisterApp(int reg)
{
	_ATL_REGMAP_ENTRY aMapEntries [] = \
	{ \
		{ OLESTR("APPID"), _AtlModule.GetAppId() }, \
		{ NULL, NULL } \
	}; \

	if(reg)
	{
		ATL::_pAtlModule->UpdateRegistryFromResource(IDR_04WEBSERVER_APP, TRUE, aMapEntries);
		_AtlModule.RegisterServer(TRUE);
	}
	else
	{
		ATL::_pAtlModule->UpdateRegistryFromResource(IDR_04WEBSERVER_APP, TRUE, aMapEntries);
		_AtlModule.UnregisterServer(TRUE);
	}
}

//	サービスとして登録
void CMy04WebServerApp::RegisterService(int reg)
{
	_ATL_REGMAP_ENTRY aMapEntries [] = \
	{ \
		{ OLESTR("APPID"), _AtlModule.GetAppId() }, \
		{ NULL, NULL } \
	}; \

	if(reg)
	{
		ATL::_pAtlModule->UpdateRegistryFromResource(IDR_04WEBSERVER_SERVICE, TRUE, aMapEntries);
		_AtlModule.RegisterServer(TRUE);
		if(CSystemService::AddToService())
		{
			AfxMessageBox("サービスの追加に失敗しました。",MB_ICONSTOP);
			m_exitCode = 0x100;
		}
	}
	else
	{
		ATL::_pAtlModule->UpdateRegistryFromResource(IDR_04WEBSERVER_SERVICE, TRUE, aMapEntries);
		_AtlModule.UnregisterServer(TRUE);
		if(CSystemService::DelFromService())
		{
			AfxMessageBox("サービスの削除に失敗しました。",MB_ICONSTOP);
			m_exitCode = 0x100;
		}
	}
}

//	デバッグログ
void CMy04WebServerApp::WriteDebugLog(LPCTSTR lpszFormat, ...)
{
	//	書式展開
	va_list argList;
	CString	str;
	va_start(argList, lpszFormat);
	str.FormatV(lpszFormat,argList);
	va_end(argList);

	FILE *text = fopen(GetAppPath() + "Debuglog.txt","at");

	fprintf(text,"%s\n",str);
	fclose(text);
}

//	コマンドオプションを取得
CString CMy04WebServerApp::GetCommandOption()
{
	CString	line = GetCommandLine();
	if(line.IsEmpty())
		line = m_lpCmdLine;

	int index = line.Find("/");
	if(index == -1)
	{
		index = line.Find("-");
		if(index == -1)
			return("");
	}

	return(line.Mid(index));
}

//	全てのコントローラを終了
void CMy04WebServerApp::KillAllController()
{
	::PostMessage(HWND_BROADCAST,::RegisterWindowMessage(_T("04WebServer All Quit")),0,0);
}
