package cfgfile;

use strict;
require BigSister::common;

use FileHandle;

my %vars = ();

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

    bless($self, $class);
    $self->{"files"} = [];
    $self->{"watchfiles"} = [];
    $self->{"mtimes"} = [];
    $self->{"fh"} = new FileHandle();
    $self->{"read_files"} = 0;
    my $file;
    foreach $file (@files) {
	$self->add_file( $file );
    }

    unless( %vars ) {
	$vars{"HOST"} = $BigSister::common::hostname;
	$vars{"\$"} = "\$";
    }
    return $self;
}


sub find_file {
    my( $self, $file ) = @_;
    return BigSister::common::find_file( $file );
}


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

    return if( grep( $_ eq $file, @{$self->{"watchfiles"}} ) );
    push( @{$self->{"watchfiles"}}, $file );
    push( @{$self->{"mtimes"}}, ((stat($file))[9]) );
}


sub add_file {
    my( $self, $file, $position ) = @_;

    if( ! defined $position ) {
	$position = $#{$self->{"files"}} + 1;
    }
    foreach my $file ($self->find_file( $file )) {
	if( $file ) {
	    return(1) if( grep( $_ eq $file, @{$self->{"files"}} ) );
	    splice( @{$self->{"files"}}, $position, 0, $file );
	    $self->add_watch( $file );
	    return 1;
	}
    }
    return undef;
}


sub has_changed {
    my( $self ) = @_;
    my $i;

    for( $i=0; $i<=$#{$self->{"watchfiles"}}; $i++ ) {
	my $mtime = ((stat( $self->{"watchfiles"}->[$i] ))[9]);
	if( $mtime != $self->{"mtimes"}->[$i] ) {
	    return( $self->{"watchfiles"}->[$i] );
	}
    }
    return undef;
}


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

    $self->{"fileno"} = 0;
    $self->{"includes"} = [];
    $self->{"watchfiles"} = [];
    $self->{"mtimes"} = [];
    $self->_open_next();
}


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

    if( $#{$self->{"includes"}} >= 0 ) {
	$self->{"fileopen"} = 1;
	$self->{"fh"} = shift @{$self->{"includes"}};
	return 1;
    }
    while( $self->{"fileno"} <= $#{$self->{"files"}} ) {
	$self->add_watch( $self->{"files"}->[$self->{"fileno"}] );
	$self->{"current_file"} = $self->{"files"}->[$self->{"fileno"}];
	$self->{"fileopen"} = 
	  open( $self->{"fh"}, "<".$self->{"current_file"} );
	$self->{"fileno"}++;
	return(1) if( $self->{"fileopen"} );
    }
    return undef;
}


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

    return(undef) if( ! $self->{"fileopen"} );
    my $fh = $self->{"fh"};
    my $line = <$fh>;
    unless( $line ) {
	close( $self->{"fh"} );
	$self->{"fileopen"} = 0;
	$self->_open_next();
	return( $self->nextline() );
    }
    while( $line =~ /\\[\r\n]*$/ ) {
	$line = $`;
	$line .= <$fh>;
    }
    if( $line =~ /^[\s\t]*#/ ) {
	return( $self->nextline() );
    }
    if( $line =~ /^include[\s\t]+([^\s\t]+)[\r\n]*$/ ) {
	foreach my $file ($self->expand($1)) {
	    $self->_include( $file );
	}
	return( $self->nextline() );
    }
    return $line;
}


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

    return(undef) unless( $self->{"fileopen"} );
    return( $self->{"current_file"} );
}


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

    my @heads = ("");
    while( $file =~ /\$(\$|[A-Z_0-9]+)/ ) {
	my $pref = $`;
	$file = $';
	foreach my $head (@heads) {
	    $head .= $pref;
	}
	my @expanded = split( /[\s\t]+/, $vars{$1} );
	my @newheads = ();
	foreach my $expand (@expanded) {
	    foreach my $head (@heads) {
		push( @newheads, "$head$expand" );
	    }
	}
	@heads = @newheads;
    }
    foreach my $head (@heads) {
	$head .= $file;
    }
    return( @heads );
}


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

    foreach my $file ($self->find_file( $file )) {
	return( undef ) unless( $file );
	$self->add_watch( $file );
	my $fh = new FileHandle();
	open( $fh, "<$file" ) || return(undef);
	push( @{$self->{"includes"}}, $self->{"fh"} );
	$self->{"fh"} = $fh;
    }
}


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

    close( $self->{"fh"} ) if( $self->{"fh"} && $self->{"fileopen"} );
    foreach my $fh (@{$self->{"includes"}}) {
	close $fh;
    }
}


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

    $self->close();
}

1;

