/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZazouMiniWebServer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

// ZazouMiniWebServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "ZMWS.h"

#ifdef WIN32
/*** Déclaration nécessaires au service ***/
static char ZMWS_SERVICE_NAME[] = "ZMWS Service";

SERVICE_STATUS_HANDLE zmwsServiceStatusHandle;

/*** Fonctions pour le service (déclarations) ***/
void ZMWSServiceCtrlHandler(DWORD controlCode);
void ZMWSServiceTerminate (DWORD error);
BOOL ZMWSServiceUpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
					 DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
					 DWORD dwWaitHint);
void ZMWSServiceMain(DWORD argc,LPTSTR *argv);
int ZMWSServiceRun();
int ZMWSServiceInstall();
int ZMWSServiceUninstall();
int ZMWSServiceStart();
int ZMWSServiceStop();

/*** Description du service ***/
SERVICE_TABLE_ENTRY ZMWSServiceTable[]=
{
	{ZMWS_SERVICE_NAME,(LPSERVICE_MAIN_FUNCTION)ZMWSServiceMain},
	{NULL,NULL}
};


/*** Fonctions pour le service (implémentations) ***/

void ZMWSServiceCtrlHandler(DWORD controlCode)
{
	switch(controlCode)
	{	
	case SERVICE_CONTROL_SHUTDOWN:
	case SERVICE_CONTROL_STOP:
		ZMWSServiceUpdateStatus(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);
		ZMWS::GetInstance().StopServer();
		ZMWSServiceTerminate (0);
		break;
	default:
		break;
	}
}

void ZMWSServiceTerminate (DWORD error) {
	if (zmwsServiceStatusHandle) {
		ZMWSServiceUpdateStatus(SERVICE_STOPPED,error,0,0,0);
	}
}

BOOL ZMWSServiceUpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
					 DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
					 DWORD dwWaitHint) {
	BOOL bSuccess;
	SERVICE_STATUS zmwsServiceStatus;

	zmwsServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
	zmwsServiceStatus.dwCurrentState = dwCurrentState;
	if (dwCurrentState == SERVICE_START_PENDING) {
		zmwsServiceStatus.dwControlsAccepted = 0;
	} else {
		zmwsServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
	}
	if (dwServiceSpecificExitCode == 0) {
		zmwsServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
	} else {
		zmwsServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
	}
	zmwsServiceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
	zmwsServiceStatus.dwCheckPoint = dwCheckPoint;
	zmwsServiceStatus.dwWaitHint = dwWaitHint;

	bSuccess = SetServiceStatus (zmwsServiceStatusHandle, &zmwsServiceStatus);
	if (!bSuccess) {
		ZMWSServiceTerminate(GetLastError());
	}
	return bSuccess;
}

void ZMWSServiceMain(DWORD argc,LPTSTR *argv)
{
    BOOL bSuccess;
    zmwsServiceStatusHandle = RegisterServiceCtrlHandler(ZMWS_SERVICE_NAME,(LPHANDLER_FUNCTION)ZMWSServiceCtrlHandler);
    if (!zmwsServiceStatusHandle) {
        ZMWSServiceTerminate(GetLastError());
        return;
    }
    bSuccess = ZMWSServiceUpdateStatus(SERVICE_START_PENDING,NO_ERROR,0,1,20000);
    if (!bSuccess) {
        ZMWSServiceTerminate(GetLastError());
        return;
    }
	ZMWS& theServer = ZMWS::GetInstance();
	bSuccess = theServer.StartServer(0, NULL);
    if (!bSuccess) {
        ZMWSServiceTerminate(bSuccess);
        return;
    }
    bSuccess= ZMWSServiceUpdateStatus(SERVICE_RUNNING,NO_ERROR,0,0,0);
    if (!bSuccess) {
        ZMWSServiceTerminate(GetLastError());
        return;
    }
	theServer.WaitForShutDown();
	print_dbg(NULL, OPER_DELETE);
    ZMWSServiceTerminate(0);
}

int ZMWSServiceRun() {
	BOOL bSuccess;
    bSuccess = StartServiceCtrlDispatcher(ZMWSServiceTable);
	if (!bSuccess) {
		return -1;
	}
	return 0;
}

int ZMWSServiceInstall()
{
    SC_HANDLE zmwsService, hscm;
	std::string strPath;
    char szFilename[MAX_PATH];
    
    GetModuleFileName(NULL,szFilename,sizeof(szFilename));
    strPath  = szFilename;
	strPath += " -service";
    
    hscm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
	if (!hscm) {
		printf ("ZMWSService installation failed (err: %d) ...\n", GetLastError());
		return -1;
	}

    zmwsService = CreateService(hscm,ZMWS_SERVICE_NAME,
        ZMWS_SERVICE_NAME,
        SERVICE_ALL_ACCESS,
        SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS ,
        SERVICE_AUTO_START,
        SERVICE_ERROR_NORMAL,
		strPath.c_str(),
        0,0,0,0,0);
	if (!zmwsService) {
		printf ("ZMWSService installation failed (err: %d) ...\n", GetLastError());
	} else {
		printf ("Successfully installed ZMWSService.\n", GetLastError());
		CloseServiceHandle(zmwsService);
	}
	CloseServiceHandle(hscm);
	return 0;
}

int ZMWSServiceUninstall()
{
    SC_HANDLE zmwsService, hscm;
    
    hscm = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
	if (!hscm) {
		printf ("ZMWSService uninstallation failed (err: %d) ...\n", GetLastError());
		return -1;
	}
    
    zmwsService=OpenService(hscm,ZMWS_SERVICE_NAME,SERVICE_ALL_ACCESS | DELETE);
	if (!zmwsService) {
		printf ("ZMWSService uninstallation failed (err: %d) ...\n", GetLastError());
	} else {
		DeleteService(zmwsService);
		CloseServiceHandle(zmwsService);
		printf ("Succefully uninstalled ZMWSService.\n");
	}
	CloseServiceHandle(hscm);
	return 0;
}

int ZMWSServiceStart() {
	SC_HANDLE zmwsService, scm;
	scm=OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
	if(!scm) {
		printf ("ZMWSService start failed (err: %d) ...\n", GetLastError());
		return -1;
	}
	zmwsService=OpenService(scm, ZMWS_SERVICE_NAME, SERVICE_ALL_ACCESS);
	if(!zmwsService) {
		CloseServiceHandle(scm);
		printf ("ZMWSService start failed (err: %d) ...\n", GetLastError());
		return -1;
	}
	StartService(zmwsService, 0, NULL);
	
	CloseServiceHandle(zmwsService);
	CloseServiceHandle(scm);

	printf ("ZMWSService started.\n");
	return 0;
}

int ZMWSServiceStop() {
	SERVICE_STATUS zmwsService_status;
	SC_HANDLE zmwsService,scm;
	scm=OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
	if(!scm) {
		printf ("ZMWSService stop failed (err: %d) ...\n", GetLastError());
		return -1;
	}
	zmwsService=OpenService(scm, ZMWS_SERVICE_NAME, SERVICE_ALL_ACCESS);
	if(!zmwsService) {
		CloseServiceHandle(scm);
		printf ("ZMWSService stop failed (err: %d) ...\n", GetLastError());
		return -1;
	}
	ControlService(zmwsService, SERVICE_CONTROL_STOP, &zmwsService_status);
	
	CloseServiceHandle(zmwsService);
	CloseServiceHandle(scm);
	printf ("ZMWSService stopped.\n");
	return 0;
}
#endif

int main(int argc, char** argv)
{
	unsigned short port = 0;
	int i;

	for (i=1; i<argc; ++i) {
		if (!strcmp(argv[i], "-shutdown")) {
			port=80;
			if (++i<argc) {
				port = (unsigned short)strtoul (argv[i], NULL, 10);
			}
		} else {
#ifdef WIN32
			// If called by SCM
			if (!strcmp(argv[i], "-service")) {
				return ZMWSServiceRun();
			}
			if (!strcmp(argv[i], "-serviceinstall")) {
				return ZMWSServiceInstall();
			}
			if (!strcmp(argv[i], "-servicestart")) {
				return ZMWSServiceStart();
			}
			if (!strcmp(argv[i], "-servicestop")) {
				return ZMWSServiceStop();
			}
			if (!strcmp(argv[i], "-serviceuninstall")) {
				return ZMWSServiceUninstall();
			}
#endif
		}
	}

	ZMWS& theServer = ZMWS::GetInstance();

	if (port) {
		// C'est une demande d'arrêt
		theServer.ShutdownServer(port);
	} else if (theServer.StartServer(argc, argv)) {
		std::string strHello = "Server started\n";
		print_dbg(strHello.c_str());
		theServer.WaitForShutDown();
	}
	print_dbg(NULL, OPER_DELETE);
	return 0;
}

