package TaskManager::System;

use strict;
use warnings;
use lib $ENV{'CF_SYSTEM_ROOT'}.'/lib/common/perl';

use POSIX qw(setsid);
use FindBin ();
use File::Basename ();
use File::Spec::Functions;
use Time::Local;
use Proc::Loadavg;

use Common::Log;

use TaskManager::Constants;

our @ISA = qw(Exporter);
our @EXPORT = qw(
	make_die
	drop_log
);

use constant TM_MAILER => '/usr/sbin/sendmail -t'; ## pipeing


sub drop_log {
	my $rec = shift;
	die "no log given"
		unless defined $rec;

	return undef
		if( defined $CFG->{'__DEBUG_LEVEL'}->{'NONE'} );

	write_log($CFG->{'LOGFILE'}, $$."\t".$rec, {'script_name'=>0})
		if( $CFG->{'LOGFILE'} && defined $CFG->{'__DEBUG_LEVEL'}->{'LOGFILE'} );

	print $rec."\n"
		if( defined $CFG->{'__DEBUG_LEVEL'}->{'STDOUT'} );
}


sub make_die {
	my $rec = shift;# or die ;

	$rec = 'unknown death reason'
		unless $rec;

#warn get_calls_stack();

	drop_log('FATAL:'.$rec);
	drop_log(get_calls_stack());
	die $rec;
}


sub get_calls_stack {
	my $report = '';
	my ($filename, $line, $sub);
	my $i = 0;
	(undef, $filename, $line, $sub, undef, undef) = caller($i++);
	while( $filename ) {
		$report .= "[$i] $filename:$line $sub()\n";
		(undef, $filename, $line, $sub, undef, undef) = caller($i++);
	}

	return $report;
}


sub get_timemark {
	my ($sec, $min, $hour) = (localtime(time()))[0..2];
	return sprintf('%02d:%02d:%02d', $hour, $min, $sec );
}


sub daemonize {

	chdir('/') or make_die("Can't chdir to /: $!");

#	umask 0;

#    ## close all files opened
#	{
#        # get the max numnber of possible file descriptors
#        my $openmax = POSIX::sysconf( &POSIX::_SC_OPEN_MAX );
#        $openmax = 64
#			if !defined($openmax) || $openmax < 0;
#
#        # close them all
#        POSIX::close($_)
#			foreach (0 .. $openmax);
#    }

	setsid() or make_die("Can't start a new session: $!");

	open(STDIN,  '</dev/null') or make_die("Can't read /dev/null: $!");
	open(STDOUT, '>/dev/null') or make_die("Can't write to /dev/null: $!");

	defined( my $pid = fork ) or make_die("Can't fork: $!");
	exit() if $pid;

	open(STDERR, '>&STDOUT') or make_die("Can't dup stdout: $!");

	return undef;
}


sub get_real_fnames {
	my $tm_script = catfile $FindBin::Bin, File::Basename::basename($0);
	my $tm_dir = File::Basename::dirname($tm_script);

	return ($tm_script, $tm_dir);
}


sub update_loadavg_value {

	my @LOADAVG = Proc::Loadavg::loadavg();
	my $MEM = get_mem_info();

	TaskManager::DB::do_query(
		"UPDATE server_list SET load_avg_1=?, mem_free=? WHERE id=?",
		$LOADAVG[0], $MEM->{'free'}->[0], $CFG->{'SERVER_ID'}
	)
		or make_die($TaskManager::DB::error);

	drop_log("Updated loadavg=$LOADAVG[0], mem_free=".join(' ',@{$MEM->{'free'}})." for server code=$CFG->{SERVER_CODE}");

	return undef;
}


sub ping {

	TaskManager::DB::do_query(
		"UPDATE server_list SET last_ping_dt=NOW() WHERE id=?",
		$CFG->{'SERVER_ID'}
	)
		or make_die($TaskManager::DB::error);

#	drop_log("Updated ping for server code=$CFG->{SERVER_CODE}");

	return undef;
}


sub ping_task {

	TaskManager::DB::do_query(
		"UPDATE server_list SET last_task_dt=NOW() WHERE id=?",
		$CFG->{'SERVER_ID'}
	)
		or make_die($TaskManager::DB::error);

#	drop_log("Updated ping for server code=$CFG->{SERVER_CODE}");

	return undef;
}


sub set_egid {
	my $sgid = shift;
	my $egid = $) + 0;

	$) = $sgid;

	drop_log("Cannot set egid to $sgid: $!")
		if ( $) == $egid && $egid != $sgid );

	return undef;
}


sub set_euid {
	my $suid = shift;
	my $euid = $>;

	$> = $suid;

	drop_log("Cannot set euid to $suid: $!")
		if ( $> == $euid && $euid != $suid );

	return undef;
}


sub get_mem_info {
	my $INF = {};

    if( open(INFIL,"/proc/meminfo") ) {
		foreach(<INFIL>) {
			m/^Mem(.+):\s+(\d+)\s+(.+)$/ && ($INF->{lc($1)} = [$2,uc($3)]);
		}
		close(INFIL);
	}

	return $INF;
}


sub mail {
	my %MAIL = (
		mailto		=> undef,
		task_id		=> undef,
		exec_str	=> undef,
		output		=> undef,
		system_name	=> undef,
		@_
	);
	
	open( MAIL, '|'.TM_MAILER ) or make_die("Can't piping mailer: $!");
	print MAIL "From: $MAIL{mailto}\r\nTo: $MAIL{mailto}\r\nSubject: TM[$MAIL{system_name}] task id $MAIL{task_id} [$MAIL{exec_str}]\r\n\r\n"
		.$MAIL{'output'};
	close MAIL;
	
	return undef;	
}


1;
