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

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;

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

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:
    Format the output of sub command, make them colorfully.
=cut

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

    my $msg;
    my $flag;

    if ($line =~ /\[(\w+)\]\s*:(.+)/) {
        $flag = $1;
        $msg  = $2;
    } else {
        $msg = $line;
    }

    $msg =~ s/\t/        /g;
    my $flaglen      = 6;
    my $desiredwidth = 120;
    my $screenwidth = 80;
    if ($ENV{'TERM'}) {
        $screenwidth  = (`tput cols` + 0);
    }
    my $maxlen = ($screenwidth > $desiredwidth ? $desiredwidth : $screenwidth);

    my @finalmsg = ();
    my $msglen   = length($msg);
    if ($msglen <= $maxlen) {
        if (!$fullmsg && $flag) {
            my $leftspace = $maxlen - length($msg);
            if ($leftspace < $flaglen) {
                $msg = substr($msg, 0, $maxlen - $flaglen);
                $msg =~ s/(.*).../$1\.\.\./g;
            }
        }
        push @finalmsg, $msg;
    } else {
        my @tmpmsg = split("", $msg);
        my $head   = 0;
        my $tail   = $maxlen;
        while ($head < $msglen) {
            push @finalmsg, substr($msg, $head, ($tail - $head));
            if (!$fullmsg) {
                if ($flag) {
                    $finalmsg[0] =~ s/(.*).........$/$1\.\.\./g;
                } else {
                    $finalmsg[0] =~ s/(.*)...$/$1\.\.\./g;
                }
                last;
            }
            $head = $tail;
            $tail = $head + ($maxlen <= ($msglen - $tail) ? $maxlen : ($msglen - $tail));
        }
    }

    for (my $i = 0 ; $i < $#finalmsg + 1 ; ++$i) {
        if ($i ne $#finalmsg) {
            print "$finalmsg[$i]\n";
            next;
        }

        if ($flag) {
            my $leftspace = $maxlen - length($finalmsg[$i]);
            my $spacenum = 0;
            if($flag !~ /debug/i) {
                $spacenum = (($leftspace >= $flaglen) ? ($leftspace - $flaglen) : ($screenwidth - length($finalmsg[$i]) + $maxlen - $flaglen));
            }
            my $spacestr = " " x $spacenum;
            print "$finalmsg[$i]$spacestr";

            if ($flag =~ /failed/i) {
                if ($color) {
                    print BOLD RED "[FAIL]\n";
                } else {
                    print "[FAIL]\n";
                }
            } elsif ($flag =~ /warning/i) {
                if ($color) {
                    print BOLD BLUE "[WARN]\n";
                } else {
                    print "[WARN]\n";
                }
            } elsif ($flag =~ /ok/i) {
                if ($color) {
                    print BOLD GREEN "[ OK ]\n";
                } else {
                    print "[ OK ]\n";
                }
            } elsif ($flag =~ /debug/i) {
                print "\n";
            } elsif ($flag =~ /info/i) {
                print "[INFO]\n";
            }
        } else {
            print "$finalmsg[$i]\n";
        }
    }
    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 = 80;
    if ($ENV{'TERM'}) {
        $screenwidth  = (`tput cols` + 0);
    }
    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;

