#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <windows.h>

/* 
Code based on discussion: "How to send CTRL+C signal to detached command-line process?"
http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/dc9586ab-1ee8-41aa-a775-cf4828ac1239
*/

class Error
{
public:
	Error(const std::string& message) : _message(message) {};
	friend std::ostream& operator<<(std::ostream& stream, Error& err);
private:
	std::string _message;
};
std::ostream& operator<<(std::ostream& stream, Error& err) { stream << err._message; return stream; }

int main(int argc, char* argv[])
{
	try
	{
		std::string path = ".";
		if (argc > 1)
			path = argv[1];
		std::cout << "Using path '" << path << "'" << std::endl;

		BOOL ret = SetCurrentDirectory(path.c_str());
		if (ret == 0)
			throw Error("Could not change to directory '"+path+"'");

		std::string eventName = "PiAnoS_windows_server_apache_stop_event";
		std::cout << "Creating global IPC event '" << eventName << "'" << std::endl;
		HANDLE cancelEvent = CreateEvent(NULL, FALSE, FALSE, eventName.c_str());
		if (cancelEvent == INVALID_HANDLE_VALUE)
		{
			DWORD err = GetLastError();
			std::stringstream ss;
			ss << "CreateEvent() failed with error code " << err << std::endl;
			throw Error(ss.str());
		}

		std::string command = "httpd.exe";
		std::string commandLine = command;
		if (argc > 2)
			commandLine += std::string(" ") + std::string(argv[2]);

		std::cout << "Running command '" << commandLine << "'" << std::endl;

		std::vector<char> cmdbuf(MAX_PATH);
		strcpy_s(&cmdbuf[0], MAX_PATH, commandLine.c_str());
		cmdbuf[cmdbuf.size()-1] = '\0';

		STARTUPINFO si;
		ZeroMemory(&si, sizeof(STARTUPINFO));
		si.cb = sizeof(STARTUPINFO);
		PROCESS_INFORMATION pi;
		ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

		ret = CreateProcess(command.c_str(), &cmdbuf[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
		if (ret == 0)
		{
			DWORD err = GetLastError();
			std::stringstream ss;
			ss << "CreateProcess() failed with error code " << err << std::endl;
			throw Error(ss.str());
		}
		CloseHandle(pi.hThread);

		HANDLE events[2];
		events[0] = cancelEvent;
		events[1] = pi.hProcess;
		DWORD exitCode = ~0;

		switch ( WaitForMultipleObjects( 2, events, FALSE, INFINITE ) )
		{
		case WAIT_OBJECT_0 + 0:
			// We recieved a cancel event, KAMIKAZE!
			//
			// Either Ctrl+C or Ctrl+Break events would work here
			GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0 );
			WaitForSingleObject( pi.hProcess, INFINITE );
			break;

		case WAIT_OBJECT_0 + 1:
			GetExitCodeProcess( pi.hProcess, &exitCode );
			break;
		}
		return 0;
	}
	catch (Error& err)
	{
		std::cout << "ERROR: " << err << std::endl;
		return 1;
	}
}
