package Net::SolarWinds::FileRotationBase;

use strict;
use warnings;
use IO::File;
use File::Copy qw(move);
use base qw(Net::SolarWinds::ConstructorHash);
use Carp qw(croak);

=pod

=head1 NAME

Net::SolarWinds::FileRotationBase - base file rotation framework

=head1 SYNOPSIS

  use base qw(Net::SolarWinds::FileRotationBase);

=head1 DESCRIPTION

This modle is intended to be used as a base module for modules that require an auto file rotation framework.  Auto file rotation is handled by file size.


=head1 OO Methods


=over 3

=cut

=item * Object constructor

The object constructor for this class has a collection of optional arguments.  Arguments are passed to the constructor in key value pairs.

Constructor useage example:

  my $fr=new Net::SolarWinds::FileRotationBase(folder=>'/var/logs/myapp',basefilename=>'someapp');

Argument list is as follows (default values shown):

  # Fully quallified system path to the log file
  filename=>'/path/to/some/file.log'

  # sets the folder files will be created and rotated under
  folder=>'.',  
  
  # sets the basefilename
  basefilename => 'DefaultFile',
  
  # used to concat the folder and filenames togeather
  pathconncat  => '/',
  
  # sets thefile extention to be used
  ext => 'log',
  
  # sets the number of files to keep in rotation
  maxfilecount => 3,
  
  # sets the max file size ( 8mb )
  maxsize      => 1024 * 1024 * 8,
  
  # sets the autoflush state ( handy for real time info in the file )
  autoflush    => 1,
  
  # sets the file auto rotation flag
  autorotate   => 1,

  # glob ref will be overwritten with the current fh
  mirror=>undef|\*STDERR

=cut

sub new {
	my ( $class, %args ) = @_;

    my $max_size=1024 * 1024 * 8;
	my $self = $class->SUPER::new(
		folder       => '.',
		basefilename => 'DefaultFile',
		pathconncat  => '/',
		ext          => 'log',
		maxfilecount => 3,
		maxsize      => $max_size,
		autoflush    => 1,
		autorotate   => 1,
		mirror       =>undef,
		%args
	);

	return $self;
}

=item * $fr->set_mirror(\*STDERR);

Sets a file handle to be mirroed to:

=cut

sub set_mirror {
  my ($self,$glob)=@_;

  $self->{mirror}=$glob;

  my $fh=$self->get_fh;
  return unless $fh;
  *$glob=$fh;
}

=item * my $filename=$fr->generate_filename;

Retuns the filename of the active file.

=cut

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


    return $self->{filename} if exists $self->{filename};

	my $filename =
	    $self->{folder}
	  . $self->{pathconncat}
	  . $self->{basefilename} . '.'
	  . $self->{ext};
}

=item * my $fh=$fr->get_fh;

Returns the active filehandle.

=cut

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

	# assumes this is defined correctly if it exists..
	# if some one mucks with the internals this can be painful!
	return $self->{fh} if exists $self->{fh};

	# if we got here then we have no file handle!

	my $filename = $self->generate_filename;

	my $fh = new IO::File(qq{>>$filename});

	# failed to open the file?
	# well this is pretty much the end of the world..
	# time to blame some one else!
	croak qq{Failed to create file "$filename" error was: $!\n}
	  unless defined($fh);

	$fh->autoflush( $self->{autoflush} );

	$self->{fh} = $fh;
	if(defined($self->{mirror})) {
	  my $mirror=$self->{mirror};
	  *$mirror=$fh;
	}

	return $fh;
}


=item * $fr->rotate_files

Forces log files to be rotated now!

=cut

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

	my $max_files = $self->{maxfilecount};
	my $basefile  = $self->generate_filename;
  ROTATE_LOOP: for ( my $count = $max_files ; $count > 0 ; --$count ) {

		my $targetfile = qq{$basefile.$count};

		# skip this file if it does not exist
		next ROTATE_LOOP unless ( -e $targetfile );

		my $next_count = 1 + $count;
		my $nextfile   = $basefile . '.' . ($next_count);

		# last file check
		if ( $next_count > $max_files ) {

			# this is the last file to manage in the list
			# we look for one after it and remove it as well
			# out of the goodness of our heart
			unlink $nextfile if -e $nextfile;

			# delete the elder file
			unlink $targetfile;
			next ROTATE_LOOP;

		}

		move( $targetfile, $nextfile );

	}
	my $nextfile = qq{$basefile.1};

	# move the current file to the .1 position
	$self->close_fh;
	return move( $basefile, $nextfile );

}


=item * $fr->close_fh;

Closes the current active file handle.

=cut

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

	return 1 unless exists $self->{fh};

	my $fh = $self->{fh};

	delete $self->{fh};

	return close($fh);
}

=item * $fr->write_to_file("Something to write to my file\n");

Writes the list of arguments to the target file.

=cut

sub write_to_file {
	my ( $self, @data ) = @_;
	my $fh = $self->get_fh;
	
	return 0 unless $fh;

	return 0 unless print $fh @data;

	return 1 unless $self->{autorotate};

	#auto rotate file checks
	my $pos = tell($fh);

	return 1 unless $pos >= $self->{maxsize};

	return $self->rotate_files;

}

=pod

=back

=head1 AUTHOR

Michael Shipper

=cut

1;
