# -*- perl -*-

# Copyright (c) 2002 by Jeff Weisberg
# Author: Jeff Weisberg <argus @ tcp4me.com>
# Date: 2002-Apr-03 08:56 (EST)
# Function: the group class
#
# $Id: Group.pm,v 1.36 2005/11/25 17:11:38 jaw Exp $


package Group;
@ISA = qw(MonEl);

use strict;
use vars qw(@ISA $doc);

# And then, perchance because his breath was failing,
# He grouped himself together with a bush.
#   -- Dante, Divine Comedy

$doc = {
    package => __PACKAGE__,
    file    => __FILE__,
    isa     => [@ISA],
    conf => {
	quotp => 1,
	bodyp => 1,
	subtypes => qr/Group|Host|Service|Alias|Cron/i,
    },
    methods => {
    },
    fields => {
    },
};


sub new {
    my $class = shift || 'Group';
    my $x = {};
    bless $x, $class;
    $x;
}

sub config {
    my $me = shift;
    my $cf = shift;
    
    $me->init_from_config( $doc, 'group' );
    return undef unless $me->init( $cf );
}

sub readconfig {
    my $cf  = shift;
    my $mom = shift;
    my $me  = new;
    my( $line, $type, $name, $x, $nomoredata, @kinder );
    
    $me->{parents} = [ $mom ] if $mom;

    $line = $cf->nextline();
    ($type, $name) = $line =~ /(Group|Host)\s+\"(.*)\"/i;
    $me->{type} = "\u\L$type";
    $me->{name} = $name;
    $me->{definedinfile} = $cf->{file};
    $me->{definedonline} = $cf->{line};
    $me->{definedattime} = $^T;

    unless( $name ){
	eval{ $cf->error( "invalid entry in config file: '$_'" ); };
	$cf->eat_block() if $line =~ /\{\s*$/;
	return ;
    }
    
    while( defined($_ = $cf->nextline()) ){
	# print STDERR "readgroup: $_\n" if $::opt_d;
	if( /^\s*\}/ ){
	    $me->{children} = [ @kinder ];
	    $me->config($cf);
	    return $me;
	}

	elsif( /^(Group|Host)\s/i ){
	    $nomoredata = 1;
	    $cf->ungetline($_);
	    $x = Group::readconfig($cf, $me);
	    push @kinder, $x if $x;
	}

	elsif( /^Alias\s/i ){
	    $nomoredata = 1;
	    $cf->ungetline($_);
	    $x = Alias::readconfig($cf, $me);
	    push @kinder, $x if $x;
	}

	elsif( /^(Service)/i ){	# no, not Service\s, we permit a ':' for symmetry
	    $nomoredata = 1;
	    $cf->ungetline($_);
	    $x = Service::readconfig($cf, $me);
	    push @kinder, $x if $x;
	}
	elsif( /^cron\s/i ){
	    $cf->ungetline($_);
	    my $c = UserCron::readconfig($cf, $me);
	    push @{ $me->{cronjobs} }, $c if $c;
	}

	elsif( /:/ ){
	    my($k, $v) = split /:\s*/, $_, 2;
	    # data must be before Service|Group|Alias 
	    # disallow
	    # Group "foo" {
	    #    x1: value
	    #    Service TCP/FOO
	    #    x2: value          <- error
	    # }
	    if( $nomoredata ){
		$cf->warning( "additional data not permitted here (ignored)" );
		next;
	    }
	    $cf->warning( "redefinition of parameter '$k'" )
		if defined $me->{config}{$k};
	    $me->{config}{$k} = $v;
	}

	else{
	    eval{ $cf->error( "invalid entry in config file: '$_'" ); };
	    $cf->eat_block() if /\{\s*$/;
	    $me->{conferrs} ++;
	    # attempt to continue
	}
    }

    $me;
}

sub gen_conf {
    my $me = shift;
    my( $k, $c, $r, $rc, $t );

    if( $me->{i_am_top} ){
	$r .= "# various config errors were detected" .
	    ($me->{conferrs} ? ", but are not shown here" : '') . "\n"
	    if $Conf::has_errors;
	foreach $k (sort keys %Conf::Config){
	    next if ($k =~ /^_/) && $Conf::Config{_hide_expr};
	    my $v = $Conf::Config{$k};
	    $v =~ s/\#/\\\#/g;
	    $r .= "$k:\t$v\n";
	}
	$r .= Resolv::gen_confs();
        $r .= NotMe::gen_confs();
	$r .= DARP::gen_confs() if $::HAVE_DARP;
	foreach $c (@{$me->{cronjobs}}, @{$me->{children}}){
	    $r .= "\n";
	    $r .= $c->gen_conf();
	}
	return $r;
    }

    $r .= $me->SUPER::gen_conf();
    $r;
}

################################################################
# override MonEl virtual methods
################################################################
sub webpage {
    my $me = shift;
    my $fh = shift;
    my $topp = shift;
    my( $k, $v, $kk, $vv, $c, $x, %cs );

    print $fh "<!-- start of Group::webpage -->\n";
    
    # object data
    unless( $topp ){
	print $fh "<TABLE CELLSPACING=1 CLASS=GROUPDATA>\n";
	foreach $k (qw(name ovstatus flags info note comment annotation details)){
	    $v = $vv = $me->{$k};
	    $kk = $k;
	    $x = '';
	    if( $k eq 'ovstatus' ){
		$x = " BGCOLOR=\"" . MonEl::web_color($v, $me->{currseverity}) . "\"";
		$kk = 'status';
	    }
	    if( $k eq 'ovstatus' || $k eq 'flags' ){
		$vv = "<L10N $v>";
	    }
	    print $fh "<TR><TD><L10N $kk></TD><TD$x>$vv</TD></TR>\n" if defined($v);
	    if( $k eq 'ovstatus' && $me->{depend}{culprit} ){
		# QQQ - is this really how I want to do it?
		print $fh "<TR><TD>...<L10N because></TD><TD>$me->{depend}{culprit} ",
		"<L10N is down></TD></TR>\n";
	    }
	    
	}
	print $fh "</TABLE>\n";

	$me->web_override($fh);
	print $fh "<HR>\n";
    }
    
    # children status
    if( @{$me->{children}} ){
	print $fh "<TABLE CLASS=GROUPCHILD>\n";
	if( $topp ){
	    print $fh "<TR><TH><L10N Name></TH><TH><L10N Up></TH><TH><L10N Down></TH><TH>",
	    "<L10N Override></TH></TR>\n";
	    foreach $c (@{$me->{children}}){
		$c->web_page_row_top($fh);
	    }
	}else{
	    print $fh "<TR><TH><L10N Name></TH><TH COLSPAN=3><L10N Status></TH></TR>\n";
	    foreach $c (@{$me->{children}}){
		$c->web_page_row_base($fh);
	    }
	}
	print $fh "</TABLE>\n";
    }
    else{
	print $fh "<!-- no children -->\n";
    }
    
    print $fh "<!-- end of Group::webpage -->\n";
}


sub web_page_row_base {
    my $me = shift;
    my $fh = shift;
    my $label = shift;
    my( $kov, $color, $c, $s, %cs, $csv );

    return if $me->{web}{hidden};
    foreach $c (@{$me->{children}}){
	my $cc = $c;
	$cc = $c->aliaslookup() if $c->can('aliaslookup');
	$kov = 1 if $c->{override};

	my $st = $cc->{ovstatus};
	my $xx = '';
	if( $st !~ /^(up|down|override)$/ ){
	    $st = 'down';
	    $xx = ' <B>*</B>';
	}

	# what severity are down items?
	$csv = $cc->{currseverity} if $cc->{ovstatus} eq 'down' &&
	    $MonEl::severity_sort{$cc->{currseverity}} > $MonEl::severity_sort{$csv};
	
	push @{$cs{ $st }},
	    "<A HREF=\"". $c->url('func=page'). "\"><FONT COLOR=\"#000000\">".
		($c->{label_right}||$c->{name}).
		"$xx</FONT></A>"
    }

    if( $me->{override} ){
	$color = ' BGCOLOR=' . MonEl::web_color('override');
    }
    print $fh "<TR><TD$color><A HREF=\"", $me->url('func=page'), "\">",
        ($label||$me->{label_left}||$me->{name}), "</A></TD>";

    foreach $s ('up', 'down', 'override'){
	$cs{$s} ||= [];
	my $cx = join( " &nbsp; ", @{$cs{$s}});
	if( $cx ){
	    print $fh "<TD BGCOLOR=\"", MonEl::web_color($s, $csv), "\">$cx</TD>\n";
	}else{
	    print $fh "<TD></TD>";
	}
    }
    print $fh "</TR>\n";
}

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

Doc::register( $doc );
1;
