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

package xCAT::FSPbootseq;
use Socket;
use strict;
use Getopt::Long;
use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR);
use xCAT::NetworkUtils;
use xCAT::FSPUtils;
use xCAT::MsgUtils qw(verbose_message);

#use Data::Dumper;

##########################################################################
# Parse the command line for options and operands
##########################################################################
sub parse_args {

    my $request = shift;
    my %opt     = ();
    my $cmd     = $request->{command};
    my $args    = $request->{arg};
    my $node    = $request->{node};
    my @VERSION = qw( 2.6 );
    my @dev = qw(hfi net);

    #############################################
    # Responds with usage statement
    #############################################
    local *usage = sub {
        my $usage_string = xCAT::Usage->getUsage($cmd);
        return ([ $_[0], $usage_string ]);
    };
    #############################################
    # Process command-line arguments
    #############################################
    if (!defined($args)) {
        return (usage("Missing command with rbootseq in DFM, net or hfi ?"));
    }

    #############################################
    # Checks case in GetOptions, allows opts
    # to be grouped (e.g. -vx), and terminates
    # at the first unrecognized option.
    #############################################
    @ARGV                     = @$args;
    $Getopt::Long::ignorecase = 0;
    Getopt::Long::Configure("bundling");

    if (!GetOptions(\%opt, qw(h|help V|verbose v|version ))) {
        return (usage());
    }
    ####################################
    # Option -h for Help
    ####################################
    #if ( exists( $opt{h} )) {
    #    return( usage() );
    #}
    ####################################
    # Option -v for version
    ####################################
    if (exists($opt{v})) {
        return (\@VERSION);
    }
    ####################################
    # Check for "-" with no option
    ####################################
    #if ( grep(/^-$/, @ARGV )) {
    #    return(usage( "Missing option: -" ));
    #}

    ####################################
    # Check for an extra argument
    ####################################
    #if ( defined( $ARGV[0] )) {
    #    return(usage( "Invalid Argument: $ARGV[0]" ));
    #}

    my $command = grep(/^$ARGV[0]$/, @dev);
    if (!defined($command)) {
        return (usage("Invalid command: $ARGV[0]"));
    }

    if ($ARGV[0] =~ /^hfi$/) {
        $opt{hfi} = 1;
    } elsif ($ARGV[0] =~ /^net$/) {
        $opt{net} = 1;
    } else {
        return (usage("Invalid Argument: $ARGV[0]"));
    }

    shift @ARGV;
    if (defined($ARGV[0])) {
        return (usage("Invalid Argument: $ARGV[0]"));
    }


    #print "in parse_args:\n";
    #print $command;
    #print Dumper(\%opt);

    my $nodetype = xCAT::DBobjUtils->getnodetype($$node[0], "ppc");
    if ($nodetype =~ /^blade$/) {
        $request->{callback}->({ data => ["After running rebootseq on the nodes successfully, it's required to run <rpower noderange reset> to make the setting be permanent"] });
    }

    ####################################
    # Set method to invoke
    ####################################
    $request->{method} = $cmd;
    return (\%opt);
}


##########################################################################
# set hfi/eth boot string
##########################################################################
sub rbootseq {

    my $request = shift;
    my $d       = shift;
    my $opt     = $request->{opt};
    my @output;
    my $tooltype = 0;
    my $parameter;
    my $bootp_retries = 5;
    my $tftp_retries  = 5;
    my $blksize       = 512;
    my $hash;
    my $node_name = @$d[6];
    my $o         = @$d[7];

    #print "in setbootseq:\n";
    #print "request\n";
    #print Dumper($request);
    #print "d";
    #print Dumper($d);

    xCAT::MsgUtils->verbose_message($request, "rbootseq START for node:$node_name, type=$$d[4].");
    if (!($$d[4] =~ /^(lpar|blade)$/)) {
        push @output, [ $node_name, "\'boot\' command not supported for CEC or BPA", -1 ];
        return (\@output);
    }

    # add checking the power state of the cec
    xCAT::MsgUtils->verbose_message($request, "rbootseq check machine state for node:$node_name.");
    my $power_state = xCAT::FSPUtils::fsp_api_action($request, $node_name, $d, "cec_state", $tooltype);
    if (@$power_state[2] != 0) {
        push @output, [ $node_name, @$power_state[1], -1 ];
        return (\@output);
    }
    unless (@$power_state[1] and @$power_state[1] =~ /operating|standby/) {
        my $machine;
        my $state;
        if ($$d[4] eq 'blade') {
            $machine = "blade";
            $state   = "on";
        } else {
            $machine = "CEC";
            $state   = "power on";
        }

        push @output, [ $node_name, "\'boot\' command can only support while the $machine is in the \'$state\' state", -1 ];
        return (\@output);
    }
    if ($opt->{net}) {
        my $mactab = xCAT::Table->new('mac');
        unless ($mactab) {
            push @output, [ $node_name, "Cannot open mac table", -1 ];
            return (\@output);
        }

        my $mac_hash = $mactab->getNodeAttribs($node_name, [qw(mac)]);
        my $mac = $mac_hash->{mac};
        if (!defined($mac)) {
            push @output, [ $node_name, "No mac address in mac table", -1 ];
        }
        $mactab->close();

        if ($mac =~ /\| /) {

            #01:02:03:04:05:0E!node5|01:02:03:05:0F!node6-eth1
            my @mac_t = split(/\|/, $mac);
            my $m;
            my $m_t;
            foreach $m (@mac_t) {
                if (($m =~ /([\w:]{12})!$node_name/) || ($m =~ /([\w:]{17})!$node_name/)) {
                    $m_t = $1;
                    last;
                }

            }

            if (!defined($m_t)) {
                $mac = $mac_t[0];
            } else {
                $mac = $m_t;
            }
        }

        if ($mac =~ /\:/) {
            $mac =~ s/\://g;
        }

        if ($mac =~ /^(\w{12})$/) {

            $parameter = "mac=$mac:speed=auto,duplex=auto,$o->{server},,$o->{client},$o->{gateway},$bootp_retries,$tftp_retries,$o->{netmask},$blksize";
        } else {
            push @output, [ $node_name, "The mac address in mac table could NOT be used for rbootseq with -net. HFI mac , or other wrong format?", -1 ];
            return (\@output);
        }
        xCAT::MsgUtils->verbose_message($request, "rbootseq <$node_name> net=$parameter");
    }

    if ($opt->{hfi}) {

        $parameter = "/hfi-iohub/hfi-ethernet:$o->{server},,$o->{client},$o->{gateway},$bootp_retries,$tftp_retries,$o->{netmask},$blksize";

        xCAT::MsgUtils->verbose_message($request, "rbootseq <$node_name> hfi=$parameter");
    }

    xCAT::MsgUtils->verbose_message($request, "rbootseq set_lpar_bootstring for node:$node_name.");
    my $res = xCAT::FSPUtils::fsp_api_action($request, $node_name, $d, "set_lpar_bootstring", $tooltype, $parameter);

    #print "In boot, state\n";
    #print Dumper($res);
    my $Rc   = @$res[2];
    my $data = @$res[1];

    ##################################
    # Output error
    ##################################
    xCAT::MsgUtils->verbose_message($request, "rbootseq return:$Rc.");
    if ($Rc != SUCCESS) {
        push @output, [ $node_name, $data, $Rc ];
    } else {
        push @output, [ $node_name, "Success", 0 ];
    }

    return (\@output);


}

1;










