package Sub::Daemon::Log;

use Fcntl qw(:flock);
use Carp;

use constant LEVEL => {debug => 1, info => 2, warn => 3, error => 4, fatal => 5};

sub new {
	my $class = shift;
	my %opts = (
		path 	=> undef,
		level 	=> 'debug',
		@_,
	);
	
	my $self = bless \%opts, $class;
}

sub debug {
	$self = shift;
	$self->log('debug', @_);
}

sub info {
	$self = shift;
	$self->log('info', @_);
}

sub warn {
	$self = shift;
	$self->log('warn', @_);
}

sub error {
	$self = shift;
	$self->log('error', @_);
}

sub fatal {
	$self = shift;
	$self->log('fatal', @_);
}

sub _default {
	my $self = shift;
  my ($time, $level) = (shift, shift);
  my ($s, $m, $h, $day, $month, $year) = localtime $time;
  $time = sprintf '%04d-%02d-%02d %02d:%02d:%08.5f', $year + 1900, $month + 1,
    $day, $h, $m, "$s." . ((split /\./, $time)[1] // 0);
  return "[$time] [$$] [$level] " . join "\n", @_, '';
}

sub log {
	my ($self, $level) = (shift, shift);
	return if LEVEL()->{$self->{level}}  > LEVEL()->{$level};
	my $str = $self->_default(time(),$level,@_);
	my $handle = $self->handle;
	
	flock $handle, LOCK_EX;
	print $handle $str;
	flock $handle, LOCK_UN;
	#$self->append($str);
}

sub handle {
	my $self = shift;
	my $path = $self->{path} or return \*STDERR;
	open my $fi, '>>' . $path;
	return $fi;
}

sub append {
  my ($self, $msg) = @_;
  return unless my $handle = $self->handle;
  flock $handle, LOCK_EX;
  print($handle encode('UTF-8', $msg)) or croak "Can't write to log: $!";
  flock $handle, LOCK_UN;
}

1;