#include "ServiceWrapper.h"


LPSTR ServiceName;
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandle;	

bool doAction (int action, int desiredAccess, LPSTR path = NULL);

enum actions {
	DO_INSTALL, DO_DELETE, DO_CHECK 
};


ServiceWrapper::ServiceWrapper(LPSTR serviceName)
{
	ServiceName = serviceName;
	ServiceStatusHandle = 0;	
}

ServiceWrapper::~ServiceWrapper(void)
{
}

bool ServiceWrapper::Install(LPSTR commandLine) {
	return doAction(DO_INSTALL, SC_MANAGER_ALL_ACCESS, commandLine);		
}

bool ServiceWrapper::UnInstall() {
	return doAction(DO_DELETE, SC_MANAGER_ALL_ACCESS);
}

bool ServiceWrapper::IsInstalled() {
	return doAction(DO_CHECK, SC_MANAGER_CONNECT);	
}

bool doAction(int action, int desiredAccess, LPSTR path) {
	SC_HANDLE scm = OpenSCManager(NULL, NULL, desiredAccess);
	SC_HANDLE service = NULL;
	if (!scm) return FALSE;

	switch(action) {
	case DO_INSTALL:
		service = CreateServiceA(
			scm, 
			ServiceName, 
			ServiceName, 
			SERVICE_ALL_ACCESS, 
			SERVICE_WIN32_OWN_PROCESS, 
			SERVICE_DEMAND_START, 
			SERVICE_ERROR_NORMAL, 
			path,
			NULL,
			NULL,
			NULL,
			NULL,
			NULL
			);
		return (service != NULL);
		break;
	case DO_DELETE:
		service = OpenServiceA(scm, ServiceName, DELETE);
		if (service == NULL)
			return FALSE;
		if (DeleteService(service))
			return TRUE;
		break;
	case DO_CHECK:
		service = OpenServiceA(scm, ServiceName, SERVICE_QUERY_STATUS);
		return (service != NULL);
	default:
		return FALSE;
	}
	CloseServiceHandle(service);		
	CloseServiceHandle(scm);
	return FALSE;
}

void WINAPI ServiceControlHandler(DWORD controlCode) {
	switch (controlCode) {
	case SERVICE_CONTROL_INTERROGATE:
		break;
	case SERVICE_CONTROL_STOP:
		ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;		
		break;
	default:
		break;
	}
	SetServiceStatus(ServiceStatusHandle, &ServiceStatus);	
	spectrum_control_handler(CTRL_CLOSE_EVENT);
}

void WINAPI ServiceMain(DWORD argc, LPSTR *argv) {
	ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;

	ServiceStatusHandle = RegisterServiceCtrlHandlerA(ServiceName, ServiceControlHandler);
	if (ServiceStatusHandle) {
		ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
		SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
		ServiceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
		ServiceStatus.dwCurrentState = SERVICE_RUNNING;
		SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
		mainloop();
		ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
		SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
		ServiceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
		ServiceStatus.dwCurrentState = SERVICE_STOPPED;
		SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
	}	
}

void ServiceWrapper::RunService() {
	SERVICE_TABLE_ENTRYA serviceTable[] = {
		{ ServiceName, ServiceMain },
		{ NULL, NULL}
	};

	StartServiceCtrlDispatcherA(serviceTable);
}
