package IPCFile;

use strict;
use FileHandle;

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

    bless($self, $class);
    $self->{"file"} = $file;
    ($maxlog=1024*1024) unless( $maxlog );
    ($logno=7) unless( $logno );
    $self->{"maxlog"} = $maxlog;
    $self->{"logno"} = $logno;
    $self->{"mintime"} = 30 * 60;
    $self->{"nexttime"} = time + ($self->{"mintime"});
    return $self;
}


sub set_rotate_hook {
    my( $self, $callback ) = @_;

    $self->{"rotatehook"} = $callback;
}


sub log {
    my( $self, $text ) = @_;

    return unless( $text );
    unless( $self->{"outfh"} ) {
        $self->_nextoutfile();
    }
    return unless( $self->{"outfh"} );
    $text = (time)." ".$text."\n";
    my $fh = $self->{"outfh"};
    print $fh $text;
    $self->{"size"} += length( $text );
    if( ($self->{"size"} > $self->{"maxlog"})
        && (time -$self->{"createtime"} > $self->{"mintime"} )) {
        $self->_nextoutfile();
    }
}


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

    if( $self->{"outfh"} ) {
        close $self->{"outfh"};
	$self->{"outfh"} = undef;
    }
    my $nextname = ($self->{"file"}).(time).".";
    for( my $index=0; ($index<100) && (-f $nextname.$index); $index++ ) {;}
    my $fh = new FileHandle();
    unless( open( $fh, ">$nextname" ) ) {
        BigSister::common::log( "err", "could not create interprocess communication file $nextname" );
	Platform::poll_sleep(10);
    }
    $self->{"size"} = 0;
    $self->{"createtime"} = time;
    $self->{"outfh"} = $fh;
    my $oldfh = select $fh; select $fh; $| = 1; select $oldfh;
    my $i=0;
    while( 1 ) {
        last if( open( _STAMP, ">".($self->{"file"}) )
	    && (print _STAMP ":$nextname:\n")
	    && close( _STAMP ) );
	select( undef,undef,undef, 0.5 );
	if( $i++ == 10 ) {
	    BigSister::common::log( "warning", "cannot create file $self->{'file'} - trying again but this is probably an error" );
	}
    }

    my $dir = $self->{"file"};
    my $file = $self->{"file"};
    $file =~ s#.*/##;
    $dir =~ s#\Q$file\E$##;
    opendir( _DIR, $dir );
    foreach my $name (readdir( _DIR )) {
        if( $name =~ /^\Q$file\E[\d\.]+$/ ) {
	    my $candidate = $dir.$name;
	    next if( $candidate eq $nextname );
	    my $mtime = ((stat($candidate))[9]);
	    next if( time-$mtime < 1800 );
	    unlink( $candidate );
	}
    }
}
        


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

    unless( $self->{"readfh"} ) {
        $self->_nextinputfile();
    }
    my $fh = $self->{"readfh"};
    return( undef ) unless( $fh );
    seek( $fh, $self->{"readpos"}, 0 ) || return undef;
    my $text = <$fh>
    if( $text ) {
        $text = $self->{"readbuffer"}.$text;
	$self->{"readbuffer"} = "";
	$self->{"readpos"} = tell( $fh );
	unless( $text =~ /[\r\n]$/ ) {
	    $self->{"readbuffer"} = $text;
	    return undef;
	}
	chomp $text;
	$text =~ /^(\d+) (.*)$/;
	return( $1, $2 );
    }
    $self->_checkreadnext();
}



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

    return unless( $self->{"readfh"} );
    seek( $self->{"readfh"}, 0, 2 );
    $self->{"readpos"} = tell( $self->{"readfh"} );
}



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

    if( $self->{"readfh"} ) {
        close( $self->{"readfh"} );
	$self->{"readfh"} = undef;
    }
    my $newfile;
    my $mtime = ((stat($self->{"file"}))[9]);
    unless( open( _FILEN, "<$self->{'file'}" )
    	&& ($newfile=<_FILEN>)
	&& ($newfile =~ /^:(.*):[\r\n]*$/) ) {
	close _FILEN;
	return;
    }
    close _FILEN;
    $newfile = $1;

    my $fh = new FileHandle();
    unless( open( $fh, "<$newfile" ) ) {
	$self->{"readwarned"} || BigSister::common::log( "err", "cannot open interprocess communication file $newfile" );
	$self->{"readwarned"} = 1;
        return;
    }
    $self->{"readwarned"} = 0;
    $self->{"readfh"} = $fh;
    $self->{"readstamp"} = $mtime;
    $self->{"readpos"} = 0;
}


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

    if( $self->{"readfh"} ) {
	my $mtime = ((stat($self->{"file"}))[9]);
	return if( $mtime == $self->{"readstamp"} );
    }
    $self->_nextinputfile();
}

1;