package Statusmon::DisplayCFG;

use Statusmon::Statusmon;

@Statusmon::DisplayCFG::ISA = qw(Statusmon::Statusmon);

use Socket;
use cfgfile;


sub new
{
    my ($this, $cfg) = @_;
    my  $class = ref($this) || $this;
    my  $self = {};

    bless($self, $class);
    $self->sched_frequency( 1 );
    $self->{"dir"} = $BigSister::common::fs{'web'};
    return $self;
}


sub start {
    my( $self ) = @_;
    my( @new );
 
    my $file = $self->getarg( "file" );
    ($file = "bb-display.cfg" ) if( ! $file );
    $self->{"cfg_file"} = new cfgfile( $file );

    $self->{"previous_config"} = $self->{"config"};
    my $config = $self->{"config"} = {}; 
    $config->{"grouptitle"} = {};
    $config->{"groups"} = {};
    $config->{"pages"} = {};
    $config->{"frames"} = {};
    $config->{"ordered_pages"} = [];
    $config->{"rsync"} = [];
    $config->{"images"} = [];
    $config->{"autoconn"} = [];
    $config->{"itemgroups"} = {};
    $config->{"options"} = {
	"NewLog" => 1
	};
    my $display = $self->get_feature_provider( "display" );
    $config->{"defaultskin"} = $config->{"logskin"} 
      = $display ? ($display->read_skin( "default" )) : {};

    $self->read_file( $self->{"cfg_file"} );

    $self->add_feature_provider( "displayconfig" );
}





sub read_file {
    my( $self, $file ) = @_;
    my( $cmd, $args, @args, $title, $group, $ref, $page, %args );
    my( $table, $pageattr );
    my $anonid = 0; 

    print STDERR "DisplayCFG::read_file( )\n" if( $BigSister::common::dl>1 );
    my $config = $self->{"config"};
    $file->rewind();
    my $prefetched = undef;
outer: while( 1 ) {
	if( $prefetched ) {
	    $_ = $prefetched;
	    undef $prefetched;
	}
	else {
	    $_ = $file->nextline();
	    last unless( defined $_ );
	    chomp $_;
	}
	if( /^#/ || /^$/ ) {
	    ; # do nowt
	}
	elsif( /^%(Groups|Logskin|Page|Section|skin|title|refto|table|ref|itemref|Rsync|Pager|Autojoin|image|Autoconn|Port|Frameset|include|Option|sort|select|select_items|select_names|Itemgroup)(|\s+.*)$/ ) {
	    ($cmd, $args) = ($1,$2);
	    $args =~ s/^\s+//;
	    @args = split( /\s+/, $args );
	    print "executing $cmd( ".join(",",@args)." )\n" if( $BigSister::common::dl>5 );
	    if( $cmd eq "Groups" ) {
		while( $_ = $file->nextline() ) {
		    next if( /^#/ || /^$/ );
		    if( /^%/ ) {
		        $prefetched = $_;
			next outer;
		    }
		    $title = "";
		    if( /\((.*)\)/ ) {
			$title = $1;
			$_ = $`.$';
		    }
		    my @args = split( /\s+/ );
		    $args = shift @args;
		    $title = $args unless( $title );
		    $args =~ s/\./$BigSister::common::domain_encode/g;
		    $config->{"grouptitle"}->{$args} = $title;
		    unless( defined $config->{"groups"}->{$args} ) {
		        $config->{"groups"}->{$args} = [];
		    }
		    my $groups = $config->{"groups"}->{$args};
		    foreach $group (@args) {
			if( ! grep( $_ eq $group, @$groups ) ) {
			    push( @$groups, $group );
			}
		    }
		}
	    }
	    elsif( $cmd eq "Itemgroup" ) {
	        my( $group, @columns ) = @args;
		$config->{"itemgroups"}->{$group} = \@columns;
	    }
	    elsif( $cmd eq "Port" ) {
	       $config->{"port"} = $args[0];
	    }
	    elsif( $cmd eq "Autoconn" ) {
		my( $ref, $host, $addr );

		$ref = $config->{"autoconn"};
		foreach $host (@args) {
		    my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($host);
		    foreach $addr (@addrs) {
			push( @$ref, [ $addr, $host ] );
		    }
		}
	    }
	    elsif( $cmd eq "Autojoin" ) {
		my( $what, $group ) = @args;

		if( $what eq "new" ) {
		    $config->{"autojoin_new"} = $group;
		} elsif( $what eq "all" ) {
		    $config->{"autojoin_all"} = $group;
		} elsif( $what eq "all_hosts" ) {
		    $config->{"autojoin_allhosts"} = $group;
		}
		elsif( $what eq "pattern" ) {
		    my( $what, $pattern, $group ) = @args;
		    $config->{"autojoin_pattern"} = {} unless( $config->{"autojoin_pattern"} );
		    $config->{"autojoin_pattern"}->{$pattern} = $group;
		}
	    }
	    elsif( $cmd eq "Rsync" ) {
		my( $host, $prefix, @groups ) = @args;
		my( $rsync, $port );

		$port = 1984;
		if( $host =~ /:/ ) {
		     $port = $host;
		     $host =~ s/:.*//;
		     $port =~ s/.*://;
		     unless( $port =~ /^\d+$/ ) { $port = getservbyname( $port, "tcp" ); }
		}
		$rsync = $config->{"rsync"};
		unless( inet_aton($host) ) {
		    print STDERR "$BigSister::common::prog: WARNING: host $host appearing in line $. of config is not a valid host name\n"; 
		}
		push( @$rsync, {
		    "host" => $host,
		    "groups" => \@groups,
		    "port" => $port,
		    "prefix" => ($prefix eq "none")?"":$prefix
		    } );
	    }
	    elsif( $cmd eq "Frameset" ) {
		my( $name, $top, $title ) = @args;
		unless( $top =~ /\.htm/ ) { $top .= ".html"; }
		my $ref = [ @{$config->{"ordered_pages"}} ];
		$config->{"frames"}->{$name} = {
		    "name" => $name,
		    "top" => $top,
		    "title" => $title,
		    "pages" => $ref
		    };
	    }
	    elsif( $cmd eq "Option" ) {
		my $option;
		foreach $option (@args) {
		    my $val = 1;
		    if( $option =~ /^(\-|\+)(.*)$/ ) {
			$option = $2;
			$val = ($1 eq "+");
		    }
		    $config->{"options"}->{$option} = $val;
		}
	    }
	    elsif( $cmd eq "Section" ) {
	        my( $title ) = @args;

		$title =~ s/_/ /g;
		$page = [];
		$config->{"pages"}->{$anonid} = $page;
		$ref = $config->{"ordered_pages"};
		push( @$ref, $anonid );
		$anonid++;
		push( @$page, {
		    "type" => "section",
		    "title" => $title
		} );
	    }
	    elsif( $cmd eq "Page" ) {
		my( $name, $title, $template ) = @args;
		my( $file, $ref );

		unless( $name =~ /\.htm/ ) { $name .= ".html"; }
		%args = ( "title", "auto" );
		$page = [];
		$title =~ s/_/ /g;
		$config->{"pages"}->{$name} = $page;
		$ref = $config->{"ordered_pages"};
		push( @$ref, $name );
		$file = $self->{"dir"};
		$file .="/" if( $file );
		$file .= $name;
		push( @$page, $pageattr = {
		    "type" => "page",
		    "title" => $title,
		    "template" => $template,
		    "file" => $file,
		    "name" => $name,
		    "skin" => $config->{"defaultskin"},
		    "color" => 3
		    } );
	    }
	    elsif( $cmd eq "ref" ) {
		unless( $page ) { 
		    print STDERR "$BigSister::common::prog: %$cmd statement not allowed without former %Page statement in line $.\n";
		    next;
		}
		push( @$page, {
		    "type" => "ref",
		    "name" => $args[0]
		    } );
	    }
	    elsif( $cmd eq "refto" ) {
		if( ($args[0] eq "none") || (! $args[0]) ) {
		    delete $args{"refto"};
		}
		elsif( $args[0] eq "clear" ) {
		    delete $args{"row-refto"};
		}
		elsif( $args[1] ) {
		    $args{"row-refto"} = {} unless( defined $args{"row-refto"} );
		    $ref = $args{"row-refto"};
		    $$ref{$args[0]} = $args[1];
		}
		elsif( $args[0] eq "self" ) {
		    $args{"refto"} = "#";
		}
		else {
		    $args{"refto"} = $args[0];
		    unless( $args{"refto"} =~ /\.htm/ ) { $args{"refto"} .= ".html"; };
		    $args{"refto"} .= "#";
		}
	    }
	    elsif( ($cmd eq "skin") || ($cmd eq "Logskin") ) {
		my $skin;
		my $read;

		my $display = $self->get_feature_provider( "display" );
		($cmd = "defaultskin") if( $cmd eq "skin" );
		if( $display ) {
		    foreach $read ("default", @args) {
			$skin = $display->read_skin( $read, $skin );
		    }
		    $config->{"\L$cmd"} = $skin;
		}
	    }
	    elsif( $cmd eq "title" ) {
		if( ($args[0] eq "none") || (! $args[0]) ) {
		    delete $args{"title"};
		}
		else {
		    $args{"title"} = $args[0];
		}
	    }
	    elsif( $cmd eq "select" ) {
		$args{"select"} = $args[0];
	    }
	    elsif( $cmd eq "select_items" ) {
	        my %items = ();
	        foreach my $arg (@args) {
		    if( $arg eq "ALL" ) {
		        %items = ();
			next;
		    }
		    my $selected = 1;
		    if( $arg =~ /^-/ ) {
		        $arg = $';
			$selected = 0;
		    }
		    if( defined $config->{"itemgroups"}->{$arg} ) {
		        foreach my $item (@{$config->{"itemgroups"}->{$arg}}) {
			    $items{$item} = $selected;
			}
		    }
		    else {
		        $items{$arg} = $selected;
		    }
		}
		if( %items ) {
		    $args{"items"} = \%items;
		}
		else {
		    delete $args{"items"};
		}
	    }
	    elsif( $cmd eq "select_names" ) {
	        if( @args && ! ($args[0] eq "ALL")) {
		    my @names = @args;
		    $args{"select_names"} = \@names;
		}
		else {
		    delete $args{"select_names"};
		}
	    }
	    elsif( $cmd eq "sort" ) {
		$args{"sort"} = $args[0];
	    }
	    elsif( $cmd eq "itemref" ) {
		if( ($args[0] eq "none") || (! $args[0]) ) {
		    delete $args{"itemref"};
		}
		else {
		    $args{"itemref"} = $args[0];
		}
	    }
	    elsif( $cmd eq "include" ) {
		my $inc;

		foreach $inc( @args ) {
		    $inc = BigSister::common::find_file( $inc );
		    unless( -f $inc ) {
			print STDERR "$BigSister::common::prog: WARNING: file $inc not found (line $.)"; 
		    }
		    push( @$page, {
			"type" => "include",
			"file" => $inc
			} );
		}
	    }
	    elsif( $cmd eq "table" ) {
		foreach $table (@args) {
		    my( %tab, %clone );
		    $tab{"title"} = $args{"title"} if( $args{"title"} );
		    if( $table =~ /^(\++)(.*)$/ ) {
			$table = $2;
			$tab{"depth"} = length( $1 );
		    }
		    push( @$page, {
			"type" => "ref",
			"name" => $table
			} );
		    $tab{"group"} = $table;
		    foreach my $arg qw( refto itemref sort select select_names items ) {
		        $tab{$arg} = $args{$arg} if( $args{$arg} );
		    }
		    $tab{"type"} = "table";
		    if( $ref = $args{"row-refto"} ) {
			%clone = %$ref;
			$tab{"row-refto"} = \%clone;
		    }
		    push( @$page, \%tab );
		}
	    }
	    elsif( $cmd eq "image" ) {
		my( $file, $img ) = @args;
		my( %image, $images, %clone );
		
		$file = BigSister::common::find_file( $file );
		if( ! -f $file ) {
		    print STDERR "$BigSister::common::prog: no file called $file at line $.\n";
		    next;
		}
		require "display_map.pm" unless( defined &display_map::new );
		$image{"type"} = "image";
		$image{"image"} = display_map->new( $self, $file );
		$image{"imgfile"} = $img;
		$image{"refto"} = $args{"refto"} if( $args{"refto"} );
		if( $ref = $args{"row-refto"} ) {
		    %clone = %$ref;
		    $image{"row-refto"} = \%clone;
		}
		push( @$page, \%image );
		$images = $self->{"images"};
		push( @$images, $image{"image"} );
	    }
	    elsif( $cmd eq "Pager" ) {
		$config->{"pager"} = $args[0];
	    }
	    else {
		print STDERR "$BigSister::common::prog: unrecognized statement $cmd at line $.\n";
	    }
	}
	else {
	    print STDERR "$BigSister::common::prog: unrecognized statement at line $.\n";
	}
    }
    close IN;

    $self->post_event( {
        "cmd_group" => "config",
	"cmd" => "displayconfig",
	"config" => $config,
	"previous_config" => $self->{"previous_config"}
	} );
}




sub run {
    my( $self ) = @_;
    my $file;

    if( $self->{"cfg_file"} && ($file = $self->{"cfg_file"}->has_changed()) ) {
	BigSister::common::log( "notice", "config file $file has changed - reloading" );
        $self->start();
    }
}


sub get_current_config {
    my( $self ) = @_;

    return( $self->{"config"} );
}



1;
