#!/usr/bin/perl
# 
# This program will boot a target machine using either it's IPMI interface, if available, or one of the 
# (non-PDU) fence methods, if the target is in an Anvil! and we have a manifest for it.
# 
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
# 
# TODO: 
# 

use strict;
use warnings;
use Anvil::Tools;

my $THIS_FILE           =  ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory   =  ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
	$running_directory =~ s/^\./$ENV{PWD}/;
}

# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;

my $anvil = Anvil::Tools->new();

$anvil->Get->switches({list => [
	"ended-within",
	"host",
	"job-uuid"], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});

# Make sure we've got a 
if (($anvil->data->{switches}{'ended-within'} eq "") or ($anvil->data->{switches}{'ended-within'} !~ /^\d+$/))
{
	$anvil->data->{switches}{'ended-within'} = 300;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::ended-within" => $anvil->data->{switches}{'ended-within'}, 
	}});
}

$anvil->data->{switches}{host_uuid} = "";
if (($anvil->data->{switches}{host}) && ($anvil->data->{switches}{host} ne "all"))
{
	# Get the host_uuid 
	$anvil->data->{switches}{host_uuid} = $anvil->Database->get_host_uuid_from_string({debug => 2, string => $anvil->data->{switches}{host}});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::host_uuid" => $anvil->data->{switches}{host_uuid}, 
	}});
}

$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
	# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try 
	# again after we exit.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0075"});
	sleep 10;
	$anvil->nice_exit({exit_code => 1});
}

show_jobs($anvil);

$anvil->nice_exit({exit_code => 0});


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

sub show_jobs
{
	my ($anvil) = @_;
	
	$anvil->Database->get_hosts({debug => 3});
	$anvil->Database->get_jobs({
		debug         => 2, 
		job_host_uuid => $anvil->data->{switches}{host_uuid} ? $anvil->data->{switches}{host_uuid} : "all", 
		ended_within  => $anvil->data->{switches}{'ended-within'},
		job_uuid      => $anvil->data->{switches}{'job-uuid'}, 
	});
	
	# Sort them into hosts, and then sort them by picked-up time (if we sorted by modified date, the 
	# display would jump all over the place)
	# NOTE: Yes, I know, sorting on job_uuid doesn't make much sense but it means repeated runs are 
	#       at least consistent in the logss.
	my $jobs_found = 0;
	foreach my $job_uuid (sort {$a cmp $b} keys %{$anvil->data->{jobs}{running}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
		if (($anvil->data->{switches}{'job-uuid'}) && ($anvil->data->{switches}{'job-uuid'} ne $job_uuid))
		{
			next;
		}
		$jobs_found++;
		my $job_command        = $anvil->data->{jobs}{running}{$job_uuid}{job_command};
		my $job_data           = $anvil->data->{jobs}{running}{$job_uuid}{job_data};
		my $job_picked_up_by   = $anvil->data->{jobs}{running}{$job_uuid}{job_picked_up_by};
		my $job_picked_up_at   = $anvil->data->{jobs}{running}{$job_uuid}{job_picked_up_at};
		my $job_updated        = $anvil->data->{jobs}{running}{$job_uuid}{job_updated};
		my $job_name           = $anvil->data->{jobs}{running}{$job_uuid}{job_name};
		my $job_progress       = $anvil->data->{jobs}{running}{$job_uuid}{job_progress};
		my $job_title          = $anvil->data->{jobs}{running}{$job_uuid}{job_title};
		my $job_description    = $anvil->data->{jobs}{running}{$job_uuid}{job_description};
		my $job_status         = $anvil->data->{jobs}{running}{$job_uuid}{job_status};
		my $job_host_uuid      = $anvil->data->{jobs}{running}{$job_uuid}{job_host_uuid};
		my $short_host_name    = $anvil->data->{hosts}{host_uuid}{$job_host_uuid}{short_host_name} // "";
		my $modified_date      = $anvil->data->{jobs}{running}{$job_uuid}{modified_date};
		my $modified_date_unix = $anvil->data->{jobs}{running}{$job_uuid}{modified_date_unix};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			jobs_found         => $jobs_found, 
			job_command        => $job_command, 
			job_data           => $job_data, 
			job_picked_up_by   => $job_picked_up_by, 
			job_picked_up_at   => $job_picked_up_at, 
			job_updated        => $job_updated, 
			job_name           => $job_name, 
			job_progress       => $job_progress, 
			job_title          => $job_title, 
			job_description    => $job_description, 
			job_status         => $job_status, 
			job_host_uuid      => $job_host_uuid,
			short_host_name    => $short_host_name, 
			modified_date      => $modified_date, 
			modified_date_unix => $modified_date_unix, 
		}});
		
		# Turn the time stamps into strings and translate the job_title, job_description, and job_status
		my $say_job_picked_up_at = $anvil->Get->date_and_time({use_time => $job_picked_up_at});
		my $say_job_updated      = $anvil->Get->date_and_time({use_time => $job_updated});
		my $say_job_title        = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_title});
		my $say_job_description  = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_description});
		my $say_job_status       = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_status});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			say_job_picked_up_at => $say_job_picked_up_at, 
			say_job_updated      => $say_job_updated, 
			say_job_title        => $say_job_title, 
			say_job_description  => $say_job_description, 
			say_job_status       => $say_job_status, 
		}});
		
		my $sort_key = "queued";
		if ($job_progress == 100)
		{
			# Finished
			$sort_key = "completed";
		}
		elsif ($job_progress)
		{
			# Picked up
			$sort_key = "in_progress";
		}
		
		if (not exists $anvil->data->{count}{$short_host_name}{$sort_key})
		{
			$anvil->data->{count}{$short_host_name}{$sort_key} = 1;
		}
		else
		{
			$anvil->data->{count}{$short_host_name}{$sort_key}++;
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"count::${short_host_name}::${sort_key}" => $anvil->data->{count}{$short_host_name}{$sort_key}, 
		}});
		
		# Store
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid}         = $job_uuid;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command}      = $job_command;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data}         = $job_data;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by} = $job_picked_up_by;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated}      = $say_job_updated;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at} = $say_job_picked_up_at;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name}         = $job_name;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress}     = $job_progress;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title}        = $say_job_title;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description}  = $say_job_description;
		$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status}       = $say_job_status;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_uuid"         => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_command"      => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_data"         => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_picked_up_by" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_updated"      => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_picked_up_at" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_name"         => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_progress"     => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_title"        => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_description"  => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description}, 
			"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_status"       => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status}, 
		}});
	}
	
	if (($anvil->data->{switches}{'job-uuid'}) && (not $jobs_found))
	{
		print "The job: [".$anvil->data->{switches}{'job-uuid'}."] was not found.\n";
		$anvil->nice_exit({exit_code => 1});
	}
	
	foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{sorted_jobs}})
	{
		print "-=] Jobs on ".$short_host_name." [=------------------------------------------------\n";
		foreach my $sort_key ("queued", "in_progress", "completed")
		{
			my $count = exists $anvil->data->{count}{$short_host_name}{$sort_key} // 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				sort_key => $sort_key, 
				count    => $count, 
			}});
			next if not $count;
			
			my $say_header = "";
			if ($sort_key eq "queued")
			{
				$say_header = $anvil->Words->string({key => 'header_0112'});
			}
			elsif ($sort_key eq "in_progress")
			{
				$say_header = $anvil->Words->string({key => 'header_0113'});
			}
			elsif ($sort_key eq "completed")
			{
				$say_header = $anvil->Words->string({key => 'header_0114'});
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_header => $say_header }});
			print "- ".$say_header."\n";
			foreach my $job_picked_up_at (sort {$a cmp $b} keys %{$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_picked_up_at => $job_picked_up_at }});
				my $job_uuid             = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid};
				my $job_command          = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command};
				my $job_data             = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data};
				my $job_picked_up_by     = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by};
				my $say_job_updated      = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated};
				my $say_job_picked_up_at = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at};
				my $job_name             = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name};
				my $job_progress         = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress};
				my $say_job_title        = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title};
				my $say_job_description  = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description};
				my $say_job_status       = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					job_uuid             => $job_uuid,
					job_command          => $job_command,
					job_data             => $job_data,
					job_picked_up_by     => $job_picked_up_by,
					say_job_updated      => $say_job_updated, 
					say_job_picked_up_at => $say_job_picked_up_at, 
					job_name             => $job_name,
					job_progress         => $job_progress, 
					say_job_title        => $say_job_title, 
					say_job_description  => $say_job_description, 
					say_job_status       => $say_job_status, 
				}});
				print "Job Name: [".$job_name."], UUID: [".$job_uuid."]\n";
				if ($sort_key eq "queued")
				{
					print "- Command: [".$job_command."], <queued>\n";
				}
				elsif ($sort_key eq "completed")
				{
					print "- Command: [".$job_command."], Picked up at: [".$say_job_picked_up_at."], last updated: [".$say_job_updated."]\n";
				}
				else
				{
					print "- Command: [".$job_command."], Progress: [".$job_progress."\%] Picked up at: [".$say_job_picked_up_at."], last updated: [".$say_job_updated."], PID: [".$job_picked_up_by."]\n";
				}
				my $job_data_lines = (split/\n/, $job_data);
				if ($job_data_lines > 1)
				{
					print "---] Job Data:\n";
					print $job_data."\n";
					print "----------------\n";
				}
				else
				{
					print "- Job Data: [".$job_data."]\n";
				}
				print "---] Job Status:\n";
				print $say_job_status."\n";
				print "--------------------------------------------------------------------------------\n";
			}
		}
	}
	
	return(0);
}
