## Created on November 2007 by Joseph.Emeras@imag.fr

## this package handles a OAR node description

package OAR::Monika::OARNode;

use strict;
use warnings;
use utf8::all;
use OAR::Monika::monikaCGI qw(-utf8);
use OAR::Monika::Conf;
use Data::Dumper;
use Time::Local;
use POSIX qw(strftime);

## class constructor
sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self  = {};
    $self->{Nodename}   = shift or die "missing a node name !";
    $self->{Ressources} = shift or die "missing node ressources !";
    bless($self, $class);
    return $self;
}

## return node full name
sub name {
    my $self = shift;
    return $self->{Nodename};
}

## return node's ressource state
# parameters: node, resource id
# return value: state of the given ressource
sub ressourceState($$) {
    my $self      = shift;
    my $ressource = shift;
    return $self->{Ressources}->{$ressource}->{infos}->{state};
}

## return node's state
# parameters: node
# return value: hash table containing (ressource, state) couples
sub state($) {
    my $self = shift;
    my %hashResult;
    foreach my $key (keys %{ $self->{Ressources} }) {

        #$hashResult{$key}= $self->{Ressources}->{$key}->{infos}->{state};
        $hashResult{$key} = $self->ressourceState($key);
    }
    return %hashResult;
}

## return this node's ressource cores count
# parameters: node, resource id
# return value: number of cores of the given ressource
#sub ressourceCores($$) {
#  my $self = shift;
#  my $ressource= shift;
#  return $self->{Ressources}->{$ressource}->{infos}->{cpucore};
#}

## return this node cpu/cores resource count: if a cpu is composed of two cores, the return value will be 2...
sub nodeResources {
    my $node = shift;
    my $cpt  = 0;

    #my %alreadyCounted;
    foreach (keys %{ $node->{Ressources} }) {

        #unless (defined($alreadyCounted{$node->{Ressources}->{$_}->{infos}->{cpu}})){
        #$cpt+=$node->{Ressources}->{$_}->{infos}->{cpucore};
        #$alreadyCounted{$node->{Ressources}->{$_}->{infos}->{cpu}}= 1;
        #}
        $cpt++;
    }
    return $cpt;
}

## alias cpus --> core
sub cpus {
    my $node   = shift;
    my $result = $node->nodeResources;
    return $result;
}

## extract the name to display using a regex from the node real name
sub displayname {
    my $self = shift;
    $self->name() =~ OAR::Monika::Conf::myself()->nodenameRegex();
    my $shortname = $1 or die "Fail to extract node' shortname";
    return $shortname;
}

## extract the name to display on the page
sub displayHTMLname {
    my $self = shift;
    $self->name() =~ OAR::Monika::Conf::myself()->nodenameRegexDisplay();
    my $shortname = $1 or die "Fail to extract node' shortname";
    return $shortname;
}

## return a hash containing (ressource,\@jobs) couple.
sub jobs {
    my $self = shift;
    my %hashResult;
    foreach my $key (keys %{ $self->{Ressources} }) {
        $hashResult{$key} = $self->{Ressources}->{$key}->{jobs};
    }
    return %hashResult;
}

## return an array containing ressource's jobs.
sub ressourceJobs {
    my $self      = shift;
    my $ressource = shift;
    my $ptResult  = $self->{Ressources}->{$ressource}->{jobs};
    return @$ptResult;
}

sub isRessourceWorking {
    my $self      = shift;
    my $ressource = shift;
    if (@{ $self->{Ressources}->{$ressource}->{jobs} }) {
        return 1;
    } else {
        return 0;
    }

}

## return the hash table of properties of this node's ressource
sub ressourceProperties($$) {
    my $self      = shift;
    my $ressource = shift;
    return %{ $self->{Ressources}->{$ressource}->{infos} };
}

## return the (ressource, \%properties) couple for this node
sub properties {
    my $self = shift;
    my %hashResult;
    foreach my $key (keys %{ $self->{Ressources} }) {

        #$hashResult{$key}= $self->{Ressources}->{$key}->{infos};
        my %hashtemp = $self->ressourceProperties($key);
        $hashResult{$key} = \%hashtemp;
    }
    return %hashResult;
}

## print this node status HTML table
sub htmlTable {
    my $self   = shift;
    my $cgi    = shift;
    my $output = "";

    $output .= $cgi->start_table(
        {   -border      => "1",
            -cellspacing => "0",
            -cellpadding => "0",
            -width       => "100%" });
    $output .= $cgi->start_Tr({ -align => "center" });

    my $cgiName            = File::Basename::basename($cgi->self_url(-query => 0));
    my $max_cores_per_line = OAR::Monika::Conf::myself()->max_cores_per_line();
    my $nb_cells           = 0;
    foreach my $currentRessource (sort keys %{ $self->{Ressources} }) {
        if (($nb_cells++ % $max_cores_per_line) == 0) {
            $output .= $cgi->end_Tr();
            $output .= $cgi->start_Tr({ -align => "center" });
        }

        #my $ressourceState= $self->{Ressources}->{$currentRessource}->{infos}->{state};
        my $ressourceState = $self->ressourceState($currentRessource);

        if ($ressourceState eq "Alive" && $self->isRessourceWorking($currentRessource) eq '1') {
            my @jobs = @{ $self->{Ressources}->{$currentRessource}->{jobs} };

            $output .= $cgi->start_td();
            $output .= $cgi->start_table(
                { -border => "1", -cellspacing => "0", -cellpadding => "0", -width => "100%" });
            foreach my $curr_job (@jobs) {
                $output .= $cgi->start_Tr({ -align => "center" });
                $output .=
                  $cgi->colorTd($curr_job, 100 / $self->cpus . "%", $cgiName . "?job=$curr_job");
                $output .= $cgi->end_Tr();
            }
            $output .= $cgi->end_table();
            $output .= $cgi->end_td();
        } elsif ($ressourceState eq "Alive" && $self->isRessourceWorking($currentRessource) eq '0')
        {
            my $drain = $self->{Ressources}->{$currentRessource}->{infos}->{drain};
            if (!defined($drain) or ($drain ne "YES")) {
                $output .= $cgi->colorTd("Free", 100 / $self->cpus . "%");
            } else {
                $output .= $cgi->colorTd("Drain", 100 / $self->cpus . "%");
            }

        } elsif ($ressourceState eq "Down") {
            $output .= $cgi->colorTd("Down", 100 / $self->cpus . "%");
        } elsif ($ressourceState eq "Absent") {

            my $available_upto =
              $self->{Ressources}->{$currentRessource}->{infos}->{available_upto};
            if (defined($available_upto) && $available_upto ne '0') {

                #my $now= `date +%s`;
                my $now = time();
                if ($now < $available_upto && $available_upto ne '2147483647') {
                    $output .= $cgi->colorTd("StandBy", 100 / $self->cpus . "%");
                } else {
                    $output .= $cgi->colorTd("Absent", 100 / $self->cpus . "%");
                }
            } else {
                $output .= $cgi->colorTd("Absent", 100 / $self->cpus . "%");
            }
        } elsif ($ressourceState eq "Suspected") {

            # if the resource is suspected and running a job, we must display it
            # differently
            if ($self->isRessourceWorking($currentRessource) eq '1') {
                my @jobs = @{ $self->{Ressources}->{$currentRessource}->{jobs} };
                $output .= $cgi->colorTd($jobs[0] . '*', 100 / $self->cpus . "%");

                #$output .= $cgi->colorTd($cgi->i("Suspected"),100/$self->cpus."%");
            } else {
                $output .= $cgi->colorTd("Suspected", 100 / $self->cpus . "%");
            }
        } else {
            $output .= $cgi->colorTd("Down", 100 / $self->cpus . "%");
        }
    }
    $output .= $cgi->end_Tr();
    $output .= $cgi->end_table();
    return $output;
}

sub getRessourceInfos {
    my $self      = shift;
    my $ressource = shift;
    defined $ressource                                or die "which ressource ?";
    exists $self->{Ressources}->{$ressource}->{infos} or die "Unknown ressource: " . $ressource;
    my %return = %{ $self->{Ressources}->{$ressource}->{infos} };
    return %return;
}

sub htmlStatusTable {
    my $self          = shift;
    my $cgi           = shift;
    my $output        = "";
    my $nodes_synonym = OAR::Monika::Conf::myself->nodes_synonym;
    $output .= $cgi->start_table({ -border => "1", -align => "center" });
    $output .= $cgi->start_Tr();
    $output .= $cgi->th({ -align => "left", bgcolor => "^c0c0c0" }, $cgi->i("Nodename"));
    $output .= $cgi->th({ -align => "left" }, $self->name());
    $output .= $cgi->end_Tr();
    $output .= $cgi->end_table();
    $output .= $cgi->br();
    $output .= $cgi->start_table({ -border => "1", -align => "center" });
    my @keylist    = keys %{ $self->{Ressources} };
    my @properties = keys %{ $self->{Ressources}->{ $keylist[0] }->{infos} };
    $output .= $cgi->start_Tr();
    $output .= $cgi->th({ -align => "left", bgcolor => "^c0c0c0" }, $cgi->i("Ressource no."));

    foreach my $key (sort @keylist) {
        $output .= $cgi->th({ -align => "left", bgcolor => "^c0c0c0" }, $cgi->i($key));
    }
    $output .= $cgi->end_Tr();

    foreach my $prop (@properties) {
        $output .= $cgi->start_Tr();
        $output .= $cgi->th({ -align => "left", bgcolor => "^c0c0c0" }, $cgi->i($prop));
        foreach my $key (sort @keylist) {
            my $value = $self->{Ressources}->{$key}->{infos}->{$prop};
            if ($prop eq $nodes_synonym) {
                $value = $self->displayHTMLname();
            }
            if ($prop eq 'available_upto') {
                $value = strftime("%F %T", localtime($value));
            }
            $output .= $cgi->td({ -valign => "top", bgcolor => "^c0c0c0" }, $cgi->i($value));
        }
        $output .= $cgi->end_Tr();
    }
    $output .= $cgi->end_table();
    return $output;
}

## that's all.
return 1;
