use strict;
use Win32::Daemon;
use Cwd 'abs_path';

my $service_interval = 1; # Time between execution of service code, in minutes
my $exe_path = $^X;
my $parameters = abs_path($0);
my $log_file = "C:/t/testlog.txt";
my %service_info = (
	machine =>  '',
	name    =>  'testsvc',
	display =>  'Perl Test Service',
	path    =>  $exe_path,
	user    =>  '',
	pwd     =>  '',
	description => 'Some text description of this service',
	parameters => $parameters
);

sub Log
{
	my $message = shift;

	open LOGFILE, ">>".$log_file or die("Unable to open log file");
	my $now = localtime;
	printf LOGFILE "%s -> %s\n", $now, $message;
	close LOGFILE;
}

if ($#ARGV >= 0)
{
	if ( $ARGV[0] eq "install" )
	{
		printf("Will try to install service\n");
		if( Win32::Daemon::CreateService( \%service_info ) )
		{
			print "Successfully added.\n";
		}
		else
		{
			print "Failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n";
		}			
	}
	elsif ( $ARGV[0] eq "uninstall" )
	{
		printf("Attempting to remove service...\n");
		if( Win32::Daemon::DeleteService( $service_info{'machine'}, $service_info{'name'} ) )
		{
			print "Successfully removed.\n";
		}
		else
		{
			print "Failed to remove service: " . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n";
		}			
	}
	else
	{
		Log($ARGV[0]);
		printf("Invalid argument.\n");
	}
	exit;
}

sub CallbackRoutine
{
	my( $Event, $Context ) = @_;
	my $State = Win32::Daemon::State();
	$Context->{last_event} = $State;

	if( Win32::Daemon::State() == SERVICE_START_PENDING )
	{
		# Initialization code
		# TODO: Add initialization code here ;)
		Log("Start Pending");

		$Context->{last_state} = SERVICE_RUNNING;
		Win32::Daemon::State( SERVICE_RUNNING );
	}

	# To allow execution of RUNNING state code immediately on startup.
	if( Win32::Daemon::State() == SERVICE_RUNNING )
	{
		Log("Running");
		# TODO: Add actual main code here :P
	}
	elsif( Win32::Daemon::State() == SERVICE_PAUSE_PENDING )
	{
		Log("Service control requested PAUSE...");
		$Context->{last_state} = SERVICE_PAUSED;
		Win32::Daemon::State( SERVICE_PAUSED );
	}
	# No need to repeatedly execute a block of code in the PAUSED state :P
	# elsif( SERVICE_PAUSED == $State ) 
	#{ } 
	#
	elsif( Win32::Daemon::State() == SERVICE_CONTINUE_PENDING )
	{
		Log("Starting execution again after a PAUSE");
		$Context->{last_state} = SERVICE_RUNNING;
		Win32::Daemon::State( SERVICE_RUNNING );
	}
	elsif( Win32::Daemon::State() == SERVICE_STOP_PENDING )
	{
		Log("Service control requested STOP, stopping...");
		# TODO: If any teardown code is needed, add it here...
		
		$Context->{last_state} = SERVICE_STOPPED;
		Win32::Daemon::State( SERVICE_STOPPED );
		Win32::Daemon::StopService();
	}
	elsif( Win32::Daemon::State() == SERVICE_STOPPED )
	{
		Log("Stopped. Hm, that's weird, the service callback should not be executed if the service is not running?");
	}
	else
	{
		# Take care of unhandled states by setting the State()
		# to whatever the last state was we set...
		Win32::Daemon::State( $Context->{last_state} );
	}
	return();
}

Log("Creating Context hash");
my %Context = (
	count   =>  0,
	start_time => time(),
);

Log("Registering Callback");
Win32::Daemon::RegisterCallbacks( \&CallbackRoutine );

Log("Telling Daemon to start...");
Win32::Daemon::StartService( \%Context, 1000*60*$service_interval );

Log("Service is stopped");