package Yaa::Log;

use strict;
use IO::File;
use POSIX qw(strftime);

use constant LOG_TIME_FORMAT => "[%a, %b %e %T %Y]: ";

BEGIN {
	eval { require Sys::Syslog; };
	use constant SYSLOG_ENABLED => (($@) ? 0 : 1);
}

####################################################
#            OBJECT CONSTRUCTOR                    #
####################################################

sub new {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	my $self = {};

	##################################################
	#               PUBLIC VARS                      #
	##################################################

	$self->{logging} = 1;		# log by default
	$self->{log_syslog} = 0;	# don't log to syslog
	$self->{log_file} = 0;
	$self->{log_stderr} = 0;

	# vars
	$self->{log_syslog_facility} = "local0";
	$self->{log_syslog_priority} = "info";

	$self->{log_time_format} = LOG_TIME_FORMAT;

	$self->{error} = undef;

	##################################################
	#               PRIVATE VARS                     #
	##################################################

	$self->{_file_fh} = undef;	# File file handle

	bless($self, $class);
	
	$self->clearParams();
	$self->setParams(@_);
	$self->init();

	return $self;
}
####################################################
#               PUBLIC METHODS                     #
####################################################

sub TIEHANDLE {
	my ($self) = @_;
	if (ref($self) eq 'Yaa::Log') {
		$self->{log_stderr} = 0;
		return $self;
	}
	return Yaa::Log->new(@_);
}

sub PRINT {
	my ($self) = shift;
	return $self->logger(@_);
}

sub error {
	my ($self) = @_;
	return $self->{error};
}

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

	$self->{logging} = 1;		# log by default
	$self->{log_syslog} = 0;	# don't log to syslog
	$self->{log_file} = 0;
	$self->{log_stderr} = 0;

	# vars
	$self->{log_syslog_facility} = "local0";
	$self->{log_syslog_priority} = "info";

	$self->{log_time_format} = "[%a, %b %e %T %Y]: ";

	$self->{error} = undef;

	return 1;
}

=head2 setParams (key => value, key2 => value2)

Sets object's parameters. Parameters are driver dependent.

=cut
sub setParams {
	my ($self) = shift;

	while (defined (my $name = shift) && defined (my $value = shift)) {
		$self->{$name} = $value if (substr($name, 0, 1) ne '_');
	}
	
	return 1;
}


# sets up logger
sub init {
	my ($self) = @_;
	my $err = 0;

	return 1 if (! $self->{logging});

	if (SYSLOG_ENABLED && $self->{log_syslog}) {
		my $ident = ($self->{log_syslog_ident}) ? $self->{log_syslog_ident} : $0;

		# open system logger
		Sys::Syslog::openlog($ident, 'cons, pid', $self->{log_syslog_facility});
	}

	if ($self->{log_file} && $self->{log_file_filename}) {
		# open that file
		$self->{_file_fh} = IO::File->new;

		if (! $self->{_file_fh}->open($self->{log_file_filename}, 'a')) {
			$self->{error} = "Unable to open file " . $self->{log_file_filename} . ": " . $!;
			$err = 1;
		}

		$self->{_file_fh}->autoflush(1);
		$self->{log_file} = 1;
	}

	if ($err) {
		# cleanup
		$self->{log_syslog} = 0;
		$self->{log_file} = 0;

		return 0;
	}

	return 1;
}

# The one and only method
sub logger {
	my $self = shift;
	return 1 if (! $self->{logging});
	
	# remove newlines
	my $str;
	$str .= $_ foreach (@_);
	$str =~ s/[\r\n]+$//;

	if ($self->{log_syslog} && SYSLOG_ENABLED) {
		Sys::Syslog::syslog($self->{log_syslog_priority}, "%s", $str);
	}

	if ($self->{log_file} && $self->{_file_fh}) {
		local *LOG = $self->{_file_fh};
		print LOG strftime($self->{log_time_format}, localtime(time())), $str, "\n";
	}

	if ($self->{log_stderr}) {
		print STDERR strftime($self->{log_time_format}, localtime(time())),  $str, "\n";
	}
	
	return 1;
}

sub DESTROY {
	my ($self) = @_;
	return 1 unless ($self->{logging});

	# close syslog
	Sys::Syslog::closelog() if ($self->{log_syslog} && SYSLOG_ENABLED);
	
	# close log file
	$self->{_file_fh} if ($self->{log_file} && $self->{_file_fh});

	return 1;
}

1;
