#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "Network.h"
#include "ServiceMode.h"

cNetwork* gpNetwork = NULL;
cServiceMode* gpService = NULL;


// ConsolCtrlHandler Prototype - Windows Command Processor 제어용 함수.
BOOL WINAPI ConsolCtrlHandler(DWORD opcode)
{
	switch ( opcode ) 
	{
	case CTRL_C_EVENT:
	case CTRL_BREAK_EVENT:
	case CTRL_CLOSE_EVENT:
	case CTRL_LOGOFF_EVENT:
	case CTRL_SHUTDOWN_EVENT:
		if( gpNetwork != NULL )
		{
			gpNetwork->Destroy();
			delete gpService;
			delete gpNetwork;
		}

		exit(1);

		return TRUE;

	default:
		// unknown type--better pass it on.
		return FALSE;
	}
}


// ServiceCtrlHandler Prototype - Windows Service 제어용 함수.
void WINAPI ServiceCtrlHandler(DWORD opcode)
{
	if( gpService == NULL )
		return;

	SERVICE_STATUS* pServiceStatus = gpService->GetServiceStatus();

	switch ( opcode )
	{
	case SERVICE_CONTROL_STOP:
		// Notifies a service that it should stop.
		pServiceStatus->dwWin32ExitCode = 0;
		pServiceStatus->dwCurrentState  = SERVICE_STOPPED;
		pServiceStatus->dwCheckPoint    = 0;
		pServiceStatus->dwWaitHint      = 0;
		// Updates the service control manager's status information for the calling service.
		SetServiceStatus( gpService->GetServiceStatusHandle(), pServiceStatus );
		// 종료할 코드는 Destroy 함수를 사용.
		return;
	case SERVICE_CONTROL_PAUSE:
		// Notifies a service that it should pause.
		pServiceStatus->dwCurrentState = SERVICE_PAUSED;
		break;
	case SERVICE_CONTROL_CONTINUE:
		// Notifies a paused service that it should resume.
		pServiceStatus->dwCurrentState = SERVICE_RUNNING;
		break;
	case SERVICE_CONTROL_INTERROGATE:
		// Notifies a service that it should report its current status information to the service control manager.
		break;
	case SERVICE_CONTROL_SHUTDOWN:
		// Notifies a service that the system is shutting down so the service can perform cleanup tasks.
		break;
	case SERVICE_CONTROL_PARAMCHANGE:
		// Notifies a service that its startup parameters have changed. The service should reread its startup parameters.
		break;
	case SERVICE_CONTROL_NETBINDADD:
		// Notifies a network service that there is a new component for binding. The service should bind to the new component.
		break;
	case SERVICE_CONTROL_NETBINDREMOVE:
		// Notifies a network service that a component for binding has been removed.
		// The service should reread its binding information and unbind from the removed component.
		break;
	case SERVICE_CONTROL_NETBINDENABLE:
		// Notifies a network service that a disabled binding has been enabled.
		// The service should reread its binding information and add the new binding.
		break;
	case SERVICE_CONTROL_NETBINDDISABLE:
		// Notifies a network service that one of its bindings has been disabled.
		// The service should reread its binding information and remove the binding.
		break;
	}
	// Updates the service control manager's status information for the calling service.
	SetServiceStatus( gpService->GetServiceStatusHandle(), pServiceStatus );
}


// ServiceMain Prototype (This method is the entry point for a service.)
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
	DWORD status;
	DWORD error = 0;;

	if( gpService == NULL )
		return;

	SERVICE_STATUS* pServiceStatus = gpService->GetServiceStatus();

	pServiceStatus->dwServiceType             = SERVICE_WIN32;
	pServiceStatus->dwCurrentState            = SERVICE_START_PENDING;
	pServiceStatus->dwControlsAccepted        = SERVICE_ACCEPT_STOP;
	pServiceStatus->dwWin32ExitCode           = 0;
	pServiceStatus->dwServiceSpecificExitCode = 0;
	pServiceStatus->dwCheckPoint              = 0;
	pServiceStatus->dwWaitHint                = 0;

	// 서비스 제어 처리자를 등록한다. - 실패시 0를 반환 한다.
	SERVICE_STATUS_HANDLE hService;
	hService = RegisterServiceCtrlHandler( gpService->GetServiceName(), ::ServiceCtrlHandler );
	if ( hService == (SERVICE_STATUS_HANDLE)0 )
		return;

	gpService->SetServiceStatusHandle( hService );

	// Initialization code goes here.
	// - 초기화 할 코드는 ServiceInitialization 함수를 사용
	// - 실패시 NO_ERROR(0)가 아닌 값를 반환.
	status = 0L; //Initialization( argc, argv, &error );	

	// Handle error condition - 초기화 실패 할 경우 종료코드(status)를 표시해 준다.
	if ( status != NO_ERROR )
	{
		pServiceStatus->dwCurrentState            = SERVICE_STOPPED;
		pServiceStatus->dwCheckPoint              = 0;
		pServiceStatus->dwWaitHint                = 0;
		pServiceStatus->dwWin32ExitCode           = status;
		pServiceStatus->dwServiceSpecificExitCode = error;

		// Updates the service control manager's status information for the calling service.
		if ( SetServiceStatus( hService, pServiceStatus ) == FALSE )
			return;
	}

	// Initialization complete - report running status.
	// - 초기화 완료 - 서비스 상태를 동작(RUNNING)으로 설정.
	pServiceStatus->dwCurrentState = SERVICE_RUNNING;
	pServiceStatus->dwCheckPoint   = 0;
	pServiceStatus->dwWaitHint     = 0;

	// Updates the service control manager's status information for the calling service.
	if ( SetServiceStatus( hService, pServiceStatus ) == FALSE )
		return;

	gpNetwork = new cNetwork;
	if( gpNetwork->Init( gpService ) == false )
	{
		assert(NULL);
		exit(1);
	}

	gpNetwork->Process();

	gpNetwork->Destroy();
	delete gpService;
	delete gpNetwork;

	return;
}


int main(int argc, char* argv[])
{
	gpService = new cServiceMode;
	if( gpService->ServiceRun( argc, argv, (LPSERVICE_MAIN_FUNCTION)ServiceMain ) == true )
	{
		delete gpService;
		return 0;
	}

	/// 콘솔 모드 수행
	SetConsoleCtrlHandler( ::ConsolCtrlHandler, TRUE );

	printf( "ConSole BootAgent On\n" );

	gpNetwork = new cNetwork;
	if( gpNetwork->Init( gpService ) == false )
	{
		assert(NULL);
		exit(1);
	}

	gpNetwork->Process();

	return 0;
}


