#! /usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html

BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; }

use lib "$::XCATROOT/probe/lib/perl";
use probe_format;
use File::Basename;
use Data::Dumper;
use File::Path;
use POSIX qw(WNOHANG setsid :errno_h);
use Term::ANSIColor qw(:constants);
$Term::ANSIColor::AUTORESET = 1;

my $program_name = basename($0);

my $pro_dir    = "$::XCATROOT/probe/";
my $plugin_dir = "$pro_dir/subcmds";
my %cmds       = ();

my $verbose = 0;
my $color   = (-t *STDOUT);
my $fullmsg = 0;
my $help    = 0;
my $list    = 0;

$::USAGE = "Usage:
xcatprobe -h
xcatprobe -l
xcatprobe [-V] <subcommand>  <attrbute_to_subcommand>

Options:
    -h : get usage information of $program_name
    -l : list all valid sub commands
    -V : print verbose information of $program_name
    -w : show each line completely. By default long lines are truncated.
";

#-----------------------------------

=head3
    Description:
    Load sub commands from ~/subcmds directory
    Using -t option of command to judge if it is valid.
    If command in ~/subcmds has syntax error, or doesn't follow interface specification, this command will be skipped
=cut

#-----------------------------------
sub loadsubcmds {
    my @candidate = glob("$plugin_dir/*");
    my @subcmds   = ();
    my $output;

    print "Starting to load sub command form ~/subcmds.............\n" if ($verbose);

    foreach (@candidate) {
        my $cmdname = basename("$_");
        $output = `$_ -T 2>&1`;
        chomp($output);

        print "\n-->$_\n[OUTPUT]:\n$output\n" if ($verbose);
        if ($output !~ /\[(\w+)\]\s*:\s*(.+)/) {
            print "skip $_ for doing '$_ -T' failed, bad format\n" if ($verbose);
            next;
        } else {
            my $desc = $2;
            unless ($1 =~ /^ok$/) {
                print "skip $_ for doing '$_ -T' failed, invalid flag\n" if ($verbose);
                next;
            }
            $cmds{$cmdname} = $desc;
            print "load $_ \n" if ($verbose);
        }
    }
    print "\nLoad sub command.........[done]\n" if ($verbose);
}


#-----------------------------------

=head3
    Description:
    Ask the terminal how wide it is. 'tput cols' writes nothing when TERM
    names a terminal terminfo does not carry, so probe_format decides what an
    unusable answer means.
=cut

#-----------------------------------
sub terminal_width {
    return probe_format::screen_width($ENV{'TERM'} ? `tput cols 2>/dev/null` : undef);
}

#-----------------------------------

=head3
    Description:
    Format the output of sub command, make them colorfully.
=cut

#----------------------------------
sub format_cmd_output {
    my $line    = shift;
    my $color   = shift;
    my $fullmsg = shift;

    my ($lines, $mark) = probe_format::render($line, $fullmsg, terminal_width());

    my $last = pop @$lines;
    print "$_\n" foreach (@$lines);

    unless (defined($mark)) {
        print "$last\n";
        return 0;
    }

    print $last;
    return 0 unless (length($mark));

    if (!$color) {
        print $mark;
    } elsif ($mark =~ /FAIL/) {
        print BOLD RED $mark;
    } elsif ($mark =~ /WARN/) {
        print BOLD BLUE $mark;
    } elsif ($mark =~ /OK/) {
        print BOLD GREEN $mark;
    } else {
        print $mark;
    }
    return 0;
}

#-----------------------------------

=head3
    Description:
    List all valid sub command in ~/subcmds directory
=cut

#----------------------------------
sub listvalidsubcmd {
    my $maxlen = 0;
    foreach my $key (keys %cmds) {
        $maxlen = length($key) if (length($key) > $maxlen);
    }
    $maxlen += 4;

    my $desiredwidth = 120;
    my $screenwidth  = terminal_width();
    my $finallen = ($screenwidth > $desiredwidth ? $desiredwidth : $screenwidth);

    print "Supported sub commands are:\n";
    foreach my $key (keys %cmds) {
        my @desc       = split(" ", $cmds{$key});
        my $str        = "";
        my @formatdesc = ();
        foreach my $word (@desc) {
            if (length($str) + length($word) > $finallen - $maxlen) {
                $str =~ s/([^\s]+)\s$/$1/g;
                push @formatdesc, $str;
                $str = "";
            }
            $str .= $word . " ";
        }
        $str =~ s/([^\s]+)\s$/$1/g;
        push @formatdesc, $str;

        if ($color) {
            print BOLD GREEN "$key";
        } else {
            print "$key";
        }
        my $space = " " x ($maxlen - length($key));
        print "$space$formatdesc[0]\n";
        delete $formatdesc[0];
        $space = " " x $maxlen;
        foreach my $line (@formatdesc) {
            print "$space$line\n" if (length($line));
        }
    }
}

#######################################
# main
#######################################
my @tmpargv = @ARGV;
my @supportopt = ("-V", "-h", "-l", "-w");
my $pluginname;
my $optnum = 0;
foreach my $attr (@tmpargv) {
    if ($attr =~ /^-/) {
        unless (grep(/^$attr$/, @supportopt)) {
            print "Unsupported attribute: $attr\n";
            print $::USAGE;
            exit 1;
        }
        $optnum++;
        $help    = 1 if ($attr eq "-h");
        $verbose = 1 if ($attr eq "-V");
        $list    = 1 if ($attr eq "-l");
        $fullmsg = 1 if ($attr eq "-w");
    } else {
        $pluginname = $attr;
        last;
    }
}

# Create symlink /opt/xcat/probe/subcmds/bin/switchprobe -> /opt/xcat/bin/xcatclient if not already there
my $switchprobe_link = $plugin_dir."/bin/switchprobe";
unless (-l $switchprobe_link) {
    my $xcatclient = `which xcatclient`;
    chomp($xcatclient);
    if ($xcatclient) {
        symlink($xcatclient, $switchprobe_link);
    }
    else {
        print "Can not create symbolic link $switchprobe_link to xcatclient. xCAT-client package not installed.\n";
        exit 1;
    }
}

&loadsubcmds;
if (defined($pluginname)) {
    my $hit = 0;
    foreach my $key (keys %cmds) {
        $hit = 1 if ($pluginname eq $key);
    }
    unless ($hit) {
        print "Unsupported sub command: $pluginname\n";
        &listvalidsubcmd;
        exit 1;
    }
}

if ($help) {
    print $::USAGE;
    exit 0;
}

if ($ARGV[0] eq "-l") {
    &listvalidsubcmd;
    exit 0;
}

if (!defined($pluginname)) {
    print "There isn't sub command input from command line, use '-l' to list all valid subcommand\n";
    exit 0;
}

splice(@tmpargv, 0, $optnum + 1);
my $pluginattrs = join(" ", @tmpargv);
my $subcmd = "$plugin_dir/$pluginname $pluginattrs";
print "\nsubcmd = $subcmd\n" if ($verbose);

my $subcmdpid = 0;
$SIG{TERM} = $SIG{INT} = sub {
    $subcmdpid or exit 0;
    kill 'INT', $subcmdpid;
};

$subcmdpid = open(PIPE, "$subcmd |") or die("Something went wrong while fork()ing to handle subcommand $subcmd: $!");

while (<PIPE>) {
    chomp;
    format_cmd_output($_, $color, $fullmsg);
}
close(PIPE);    # This will set the $? properly

my $ret = $? >> 8;

exit $ret;

