#ifdef _WIN32

#include <stdio.h>
#include "ntservice.h"
//#include <strsafe.h>
#include <wtsapi32.h>

/* Handle to SCM for updating service status */
static SERVICE_STATUS_HANDLE hServiceStatus = 0;
static BOOL foreground = FALSE;
static char ConsoleTitle[128];
static int glb_argc;
static char **glb_argv;
HANDLE hServDoneEvent = NULL;
HANDLE WaitHandles[3];
extern volatile int debug;
char *progname;

int real_main(int argc, char *argv[]);
/*
 * Forward declarations
 */
void ServiceControl(DWORD dwCtrlCode);
void ntservice_init(void);
void ntservice_exit(void);

void main_shutdown();
void log_text(char * text);

/*
void svcReportError(LPTSTR szText) {
  HANDLE hEventSource;
  LPCTSTR lpszStrings[2];
  TCHAR Buffer[80];
  
  hEventSource = RegisterEventSource(NULL, TEXT(NTSERVICE_DISPLAY_NAME));
  
  if (NULL != hEventSource) {
	  StringCchPrintf(Buffer, 80, TEXT("%s"), szText);
	  lpszStrings[0] = TEXT(NTSERVICE_DISPLAY_NAME);
	  lpszStrings[1] = Buffer;
	  
	  ReportEvent(hEventSource,
								EVENTLOG_ERROR_TYPE,
								0,
								SVC_ERROR,
								NULL,
								2,
								0,
								lpszStrings,
								NULL);
								
	  DeregisterEventSource(hEventSource);
	}

}
*/


void launchUserProgram(char * cmd) {
  DWORD csid = WTSGetActiveConsoleSessionId();
  HANDLE handle, handle2;
	if (WTSQueryUserToken(csid, &handle)) {
	  if (!DuplicateTokenEx(handle, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &handle2)) {
	    CloseHandle(handle);
	    log_text("#1");
	    return;
		}
		CloseHandle(handle);
		
		log_text("#2");
		STARTUPINFO si;
		memset(&si, 0, sizeof(si));
		si.cb = sizeof(si);
		si.lpDesktop = TEXT("winsta0\\default");
		
		PROCESS_INFORMATION pi;
		memset(&pi, 0, sizeof(pi));
		
		if (!CreateProcessAsUser(handle2, NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
		  log_text("#3");
		}
		
		
		CloseHandle(handle2);
		
	}
}


void WINAPI service_main( DWORD argc, LPTSTR *argv )
{
  ntservice_init();
  /* pass the global command line options on to the service */
  real_main( glb_argc, glb_argv );
  ntservice_exit();
}


/*
 * This is the entry point for the executable
 * We can call ntpdmain() explicitly or via StartServiceCtrlDispatcher()
 * as we need to.
 */
int main( int argc, char *argv[] )
{
	int rc;
	int i = 1;

	/* Save the command line parameters */
	glb_argc = argc;
	glb_argv = argv;

	/* Command line users should put -f in the options */
	while (argv[i]) {
		if (!_strnicmp(argv[i], "-c", 2) ||
			!strcmp(argv[i], "-q") ||
			!strcmp(argv[i], "--help") ||
			!strcmp(argv[i], "-n")) {
			foreground = TRUE;
			break;
		}
		i++;
	}

	if (foreground) {
		/* run in console window */
		exit(real_main(argc, argv));
	} else {
	  /* Start up as service */

		SERVICE_TABLE_ENTRY dispatchTable[] = {
			{ TEXT(NTSERVICE_DISPLAY_NAME), (LPSERVICE_MAIN_FUNCTION) service_main },
			{ NULL, NULL }
		};

		rc = StartServiceCtrlDispatcher(dispatchTable);
		if (!rc) {
      char buffer[200];
			progname = argv[0];
			rc = GetLastError();
			sprintf(buffer, "%s: unable to start as service, rc: %i", progname, rc);
  	  MessageBox( NULL,
        (LPCTSTR)buffer,
        (LPCTSTR)"ERROR",
        MB_ICONINFORMATION | MB_OK
    );
//#ifdef DEBUG
			fprintf(stderr, "%s: unable to start as service, rc: %i\n\n", progname, rc);
//#endif
			fprintf(stderr, "\nUse -d, -q, --help or -n to run from the command line.\n");
			exit(rc);
		}
	}
	exit(0);
}

/*
 * Initialize the Service by registering it.
 */
void
ntservice_init() {
	if (!foreground) {
		/* Register handler with the SCM */
		hServiceStatus = RegisterServiceCtrlHandler(NTSERVICE_DISPLAY_NAME,
					(LPHANDLER_FUNCTION)ServiceControl);
		if (!hServiceStatus) {
//			NTReportError(NTSERVICE_NAME,
//				"could not register service control handler");
			UpdateSCM(SERVICE_STOPPED);
			exit(1);
		}
		UpdateSCM(SERVICE_RUNNING);
	} else {
		strcpy(ConsoleTitle, "NTP Version ");
		strcat(ConsoleTitle, "1.0");
		SetConsoleTitle(ConsoleTitle);
	}

	//atexit( ntservice_exit );
}
/*
 * Routine to check if this is a service or a foreground program
 */
BOOL
ntservice_isservice() {
	return(!foreground);
}
/* service_ctrl - control handler for NTP service
 * signals the service_main routine of start/stop requests
 * from the control panel or other applications making
 * win32API calls
 */
void
ntservice_exit( void )
{

	if (!foreground) { /* did not become a service, simply exit */
		/* service mode, need to have the service_main routine
		 * register with the service control manager that the
		 * service has stopped running, before exiting
		 */
		UpdateSCM(SERVICE_STOPPED);
	}
//	uninit_io_completion_port();
	Sleep( 2 );  	//##++

# ifdef DEBUG
	_CrtDumpMemoryLeaks();
# endif
}

/*
 * ServiceControl(): Handles requests from the SCM and passes them on
 * to the service.
 */
void
ServiceControl(DWORD dwCtrlCode) {
  /* Handle the requested control code */
  switch(dwCtrlCode) {
    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
      UpdateSCM(SERVICE_STOP_PENDING);
      main_shutdown();
      return;

    case SERVICE_CONTROL_PAUSE:
    case SERVICE_CONTROL_CONTINUE:
    case SERVICE_CONTROL_INTERROGATE:
    default:
      break;
  }
  UpdateSCM(SERVICE_RUNNING);
}

/*
 * Tell the Service Control Manager the state of the service.
 */
void UpdateSCM(DWORD state) {
	SERVICE_STATUS ss;
	static DWORD dwState = SERVICE_STOPPED;

	if (hServiceStatus) {
		if (state)
			dwState = state;

		memset(&ss, 0, sizeof(SERVICE_STATUS));
		ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS;
		ss.dwCurrentState = dwState;
		ss.dwControlsAccepted = SERVICE_ACCEPT_STOP |
					SERVICE_ACCEPT_SHUTDOWN;
		ss.dwCheckPoint = 0;
		ss.dwServiceSpecificExitCode = 0;
		ss.dwWin32ExitCode = NO_ERROR;
		ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 5000 : 1000;

		if (!SetServiceStatus(hServiceStatus, &ss)) {
			ss.dwCurrentState = SERVICE_STOPPED;
			SetServiceStatus(hServiceStatus, &ss);
		}
	}
}

BOOL WINAPI
OnConsoleEvent(
	DWORD dwCtrlType
	)
{
	switch (dwCtrlType) {
#ifdef DEBUG
		case CTRL_BREAK_EVENT :
			if (debug > 0) {
				debug <<= 1;
			}
			else {
				debug = 1;
			}
			if (debug > 8) {
				debug = 0;
			}
			printf("debug level %d\n", debug);
		break ;
#endif

		case CTRL_C_EVENT  :
		case CTRL_CLOSE_EVENT :
		case CTRL_SHUTDOWN_EVENT :
			if (WaitHandles[0] != NULL) {
				SetEvent(WaitHandles[0]);
				Sleep( 100 );  //##++
			}
		break;

		default :
			return FALSE;


	}
	return TRUE;;
}




#endif /* _WIN32 */
