#!/usr/bin/perl 


BEGIN {
	push @INC, "/usr/share/arc/perl/";

	while (@ARGV > 0) {
		if($ARGV[0] eq "-h" or $ARGV[0] eq "--help" or $ARGV[0] eq "-help") {
			# For compatibility with most Unix utilities
			%ARGV = ();
			last;
		} elsif($ARGV[0] eq "-?") {
			# For compatibility with most Win utilities
			%ARGV = ();
			last;
		} elsif(($ARGV[0] eq "-c") || ($ARGV[0] eq "--config")) {
			shift;
			my $conffile = $ARGV[0];
			if($conffile) {
				$ENV{'ARC_CONFIG'} = $conffile;
			}
		} else {
			last;
		}
		shift;
	}
}

=head1 NAME

janitor - command line access to the Janitor service

=cut

use warnings;
use strict;
use Janitor::Janitor qw(process);
use Janitor::Util qw(sane_rte_name sane_job_id);



######################################################################

=head1 SYNOPSIS

Janitor.pl [ deploy | help | info | register | remove | setstate | search | sweep ]

=head1 DESCRIPTION

Mangages Dynamic Runtime Environment for Grid Jobs.

=head1 OPTIONS

=over 4

=cut

######################################################################
# Argument processing switch
######################################################################
&usage unless @ARGV > 0;

my $format = "   %-12s %s\n";



my $initstate = Janitor::Janitor::initstate();
exit $initstate if defined $initstate;

######################################################################

=item help

Shows a short summary of the options of the program.

=cut

######################################################################

	if ($ARGV[0] eq "help") {
		&usage(0);
	}

######################################################################

=item list

List all information of the current system

=cut

######################################################################

	elsif ($ARGV[0] eq "list") {
		my $response = &process(new Janitor::Request(Janitor::Request::LIST));
		my %result = $response->result();
		if($result{errorcode} == 0){
			my $show_jobs = 1;
			my $show_manual = 1;
			my $show_installed = 1;
			my $show_installable = 1;
			my $show_short = 0;
			if(@ARGV > 1) {
				$show_jobs = 0;
				$show_manual = 0;
				$show_installed = 0;
				$show_installable = 0;
				foreach my $show(@ARGV){
						if ($show eq "all") {
							$show_jobs = 1;
							$show_manual = 1;
							$show_installed = 1;
							$show_installable = 1;
						}
						elsif ($show eq "jobs") {
							$show_jobs = 1;
					 	}
						elsif ($show eq "rtes") {
							$show_manual = 1;
							$show_installed = 1;
							$show_installable = 1;
						}
						elsif ($show eq "local") {
							$show_manual = 1;
						}
						elsif ($show eq "dynamic") {
							$show_installed = 1;
							$show_installable = 1;
						}
						elsif ($show eq "installed") {
							$show_installed = 1;
						}
						elsif ($show eq "installable") {
							$show_installable = 1;
						}
						elsif ($show eq "shortlist") {
							$show_short = 1;
						}
				}
			}
			# JOBS
			if($show_jobs) {
			print "Jobs:\n\n" unless $show_short;
			my @joblist = $response->runningJob();
			if(defined $joblist[0]){
				foreach my $job(@joblist){
					my %hash = %{$job};
					if($show_short) {
						print "$hash{jobid}\n";
						next;
					}
					printf $format, "jobid:", $hash{jobid};
					printf $format, "created:", $hash{created};
					printf $format, "age:", $hash{age};
					printf $format, "state:", $hash{state};
					printf $format, "rte:", $hash{rte_list};
					printf $format, "rte key:", $hash{runtimeenvironmentkey} if defined $hash{runtimeenvironmentkey};
					if(defined $hash{uses}){
						my @uses = $hash{uses};
						foreach my $use(@uses){
							printf $format, "uses:", $use;
						}
					}
					print "\n";
				}
			}
			print "\n";
			}
			# MANUAL RTEs
			if($show_manual) {
			print "Locally installed runtime environments:\n\n" unless $show_short;
			my @rtelist = $response->runtimeLocal();
			if(defined $rtelist[0]){
				foreach my $rte(@rtelist){
					my %hash = %{$rte};
					if($show_short) {
						print "$hash{name}\n";
					} else {
						printf $format, "name:", $hash{name};
						print "\n";
					}
				}
			}
			print "\n";
			}
			if($show_installed) {
			print "Dynamically installed runtime environments:\n\n" unless $show_short;
			my @rtelist = $response->runtimeDynamic();
			if(defined $rtelist[0]){
				foreach my $rte(@rtelist){
					my %hash = %{$rte};
					if($show_short) {
						print "$hash{name}\n";
						next;
					}
					printf $format, "name:",        $hash{name};
					printf $format, "state:",       $hash{state};
					printf $format, "lastused:",    $hash{lastused};
					if(defined $hash{uses}){
						my @uses = $hash{uses};
						foreach my $use(@uses){
							printf $format, "uses:", $use;
						}
					}
					print "\n";
				}
			}
			print "\n";
			}
			if($show_installable) {
			print "Installable runtime environments:\n\n" unless $show_short;
			my @rtelist = $response->runtimeInstallable();
			if(defined $rtelist[0]){
				foreach my $rte(@rtelist){
					my %hash = %{$rte};
					if($show_short) {
						print "$hash{name}\n";
						next;
					}
					printf $format, "name:",        $hash{name};
					printf $format, "description:", $hash{description};
					if ($hash{supported}){
						printf $format, "supported:", "yes";
					}else{
						printf $format, "supported:", "no";
					}
					print "\n";
				}
			}
			print "\n";
			}
			print $result{errorcode}." ".$result{message}."\n" unless $show_short;
		}else{ # if result is valid
			print $result{errorcode}." ".$result{message}."\n";
		}
		exit $result{errorcode};
	}

######################################################################

=item info [<job-id>]

Lists informations about known jobs. If a <job-id> is given detailed informations
about this job are listed.

=cut

######################################################################

	elsif ($ARGV[0] eq "info") {
		if (scalar @ARGV != 2) {
			&usage;
		}else{
			my $jobid = $ARGV[1];

			if (sane_job_id($jobid) == 0) {
				printf STDERR "janitor: invalid jobid: \"" . $jobid . "\"\n";
				exit (1);
			}

			my $request = new Janitor::Request(Janitor::Request::INFO, $jobid);
;
			my $response = &process($request);

			my %result = $response->result();
			if($result{errorcode} == 0){
				my @joblist = $response->runningJob();
				foreach my $job(@joblist){
					my %hash = %{$job};
					printf $format, "jobid:", $hash{jobid};
					printf $format, "created:", $hash{created};
					printf $format, "age:", $hash{age};
					printf $format, "state:", $hash{state};
					printf $format, "rte:", $hash{rte_list};
					printf $format, "rte key:", $hash{runtimeenvironmentkey} if defined $hash{runtimeenvironmentkey};
					if(defined $hash{uses}){
						my $rUses = $hash{uses};
						foreach my $use(@$rUses){
							printf $format, "uses:", $use;
						}
					}
					print "\n";
				}
				print $result{errorcode}." ".$result{message}."\n";
			}else{ # if result is valid
				print $result{errorcode}." ".$result{message}."\n";
			}

			exit $result{errorcode};
		}
	}

######################################################################

=item search [RE1 [RE2 ...]]

Searches for informations about matching installable and 
manually installed runtime environments.

=cut

######################################################################

	elsif ($ARGV[0] eq "search") {

		&usage unless scalar @ARGV > 1; 
		
		my @rte = @ARGV;

		my $request = new Janitor::Request(Janitor::Request::SEARCH, undef, \@rte);
		my $response = &process($request);

		my %result = $response->result();
		if($result{errorcode} == 0){
						# MANUAL RTEs
			print "Locally installed runtime environments:\n\n";
			my @rtelist = $response->runtimeLocal();
			if(defined $rtelist[0]){
				foreach my $rte(@rtelist){
					my %hash = %{$rte};
					printf $format, "name:", $hash{name};
					print "\n";
				}
			}
			print "\n";
			print "Installable runtime environments:\n\n";
			@rtelist = $response->runtimeInstallable();
			if(defined $rtelist[0]){
				foreach my $rte(@rtelist){
					my %hash = %{$rte};
					printf $format, "name:",        $hash{name};
					printf $format, "description:", $hash{description};
					if ($hash{supported}){
						printf $format, "supported:", "yes";
					}else{
						printf $format, "supported:", "no";
					}
					print "\n";
				}
			}
			print "\n";

			print $result{errorcode}." ".$result{message}."\n";
		}else{ # if result is valid
			print $result{errorcode}." ".$result{message}."\n";
		}

		exit $result{errorcode};
		
	}

######################################################################

=item register <job-id> [RE1 [RE2 ...]]

Registers the job <job-id> within the Janitor. RE1 ... REn are the REs the
Job requested. If the requested REs are already installed the Janitor returns
the value 0. In this case it is not necessary to call the Janitor with the
option deploy. If the requested REs are not installed but installable 1 is
returned. To actually deploy the Janitor must be executed with the deploy
argument. If it is not possible to install the requested REs or an error
occured 2 is returned.

=cut

######################################################################


	elsif ($ARGV[0] eq "register") {
		&usage(2) unless scalar @ARGV > 1; 
		
		my @rte = @ARGV;
		shift @rte;
		my $jobid = shift @rte;
		map { s/'(.*)'/$1/; } @rte ; # this changes @ARGV

		if (sane_job_id($jobid) == 0) {
			printf STDERR "janitor: invalid jobid: \"" . $jobid . "\"\n";
			exit (2);
		}
 
		if (sane_rte_name(@rte) == 0) {
			printf STDERR "janitor: I don't like this kind of RE name!\n";
			exit(2);
		}

		my $request  = new Janitor::Request(Janitor::Request::REGISTER, $jobid, \@rte);

		my $response = &process($request);
		my %result   = $response->result();
 
		print $result{errorcode}." ".$result{message}."\n";
		exit  $result{errorcode};
	}

######################################################################

=item deploy <job-id>

Deploys all the REs needed by the previously registered Job <job-id>. If
successfull it returns 0, otherwise 1.

=cut

######################################################################

	elsif ($ARGV[0] eq "deploy") {
		&usage unless scalar @ARGV == 2; 

		my $jobid = $ARGV[1];

		if (sane_job_id($jobid) == 0) {
			printf STDERR "janitor: invalid jobid: \"" . $jobid . "\"\n";
			exit (1);
		}

		my $request  = new Janitor::Request(Janitor::Request::DEPLOY, $jobid);
		my $response = &process($request);
		my %result   = $response->result();

		print $result{errorcode}." ".$result{message}."\n";
		exit  $result{errorcode};
	}
######################################################################

=item remove <job-id>

Removes the job <job-id> from the Janitors database.

=cut

######################################################################

	elsif ($ARGV[0] eq "remove") {
		&usage unless scalar @ARGV == 2;

		my $request = new Janitor::Request(Janitor::Request::REMOVE, $ARGV[1]);
		
		if (sane_job_id($request->jobid()) == 0) {
			printf STDERR "janitor: invalid jobid: \"" . $request->jobid() . "\"\n";
			exit (2);
		}

		my $response =  &process($request);
		my %result   = $response->result();

		print $result{errorcode}." ".$result{message}."\n";
		exit $result{errorcode};
	}

######################################################################

=item setstate <newstate> RE1 [RE2 ...]

Sets the state of a RE.

=cut

######################################################################

	elsif ($ARGV[0] eq "setstate") {
		&usage unless scalar @ARGV > 1; 

		my @rte = @ARGV;
		shift @rte;
		my $state = shift @rte;
		map { s/'(.*)'/$1/; } @rte ; # this changes @ARGV

		if (sane_rte_name(@rte) == 0) {
			printf STDERR "janitor: I don't like this kind of RE name!\n";
			exit(2);
		}


		my $request = new Janitor::Request(Janitor::Request::SETSTATE, undef, \@rte, undef, $state);

		my $response =  &process($request);
		my %result   = $response->result();

		print $result{errorcode}." ".$result{message}."\n";
		exit $result{errorcode};
		
	}

######################################################################

=item sweep [--force]

Removes dynamically installed REs which were not used for a long time. If
--force is given it will also remove old Jobs. These timespans can be
configured in the arc.conf configuration file.

=cut

######################################################################

	elsif ($ARGV[0] eq "sweep") {
		&usage unless scalar @ARGV <= 2;

		my $request = new Janitor::Request(Janitor::Request::SWEEP);

		if (scalar @ARGV == 2) {
			&usage unless $ARGV[1] eq "--force";
			$request->force(1);
		}

		my $response =  &process($request);
		my %result   = $response->result();
	
		print $result{errorcode}." ".$result{message}."\n";
		exit $result{errorcode};
	}


	else {	
		&usage;
	}

######################################################################

=back

=cut

######################################################################

sub usage {
	my ($ret) = @_;
	$ret = 1 unless defined $ret;

	# get the name of this programm
	my $name = $0;
	$name =~ s#^.*/([^/]*)$#$1#; 	#

	printf STDERR <<EOUSAGE, $name;
Usage: %s [-h | -? | -c config_file | --config config_file ] 
 [ deploy | help | list | info | register | remove | setstate | search | sweep ]
  deploy <job-id>:             deploys all REs needed by job <job-id>
  help:                        displays this message
  list:                        lists details about all registered jobs
  info <job-id>:               lists information about this job's REs
  register <job-id> [ REs ]:   registers a new job
  remove <job-id>:             unregister job <job-id>
  setstate <newstate> [ REs ]: sets the state of REs
  search [ REs ]:              searches for informations about REs
  sweep [--force]:             clean up runtime environments

See janitor(8) for detailed instructions.

EOUSAGE

	exit $ret;
}
