package TaskManager::Task::Queue;

use strict;
use warnings;

use TaskManager::Constants;
use TaskManager::DB;
use TaskManager::System;
use TaskManager::Task::Generic;

our @ISA = qw(TaskManager::Task::Generic);


sub new {
	my $class = shift || die "Bad method call!";
	my $self = $class->SUPER::new(@_);
	$self->{'table'} = 'task_queue';
	return $self;
}


sub allocate_task {
	my $self = shift || die "Bad method call!";
	my $WORKER_PID = shift or die "!";

	my $__gm = '';
#	$__gm .= ($__gm ? ',' : '').'?'
#		for( 1..scalar( @{$CFG->{'__MUTEX_GROUPS'}} ) );
#
#	my $sth = $dbh->prepare(<<SQL) or make_die($dbh->errstr);

	my $SQL = <<SQL;
		SELECT
			id, exec_str, UNIX_TIMESTAMP(dt_start) AS dt_start_uts, priority
		FROM
			task_queue
		WHERE
			(
				worker_status=? OR
				(
					worker_status=? AND
					repeat_on_error!=0 AND
					attempt_no*$CFG->{NEXT_ATTEMPT_TIMEOUT} + UNIX_TIMESTAMP(dt_start) < UNIX_TIMESTAMP(NOW())
				)
			)
--			AND
--			gmutex IN ($__gm)
		ORDER BY
			priority ASC,
			attempt_no ASC,
			dt_start ASC
		LIMIT
			0,1
SQL
#
#	$sth->execute(TM_STATUS_NEW, TM_STATUS_FAIL, @{$CFG->{'__MUTEX_GROUPS'}}) or make_die($sth->errstr);
#	return (undef,undef)
#		unless $sth->rows();

	my $REZ = TaskManager::DB::select_query(
		$SQL,
		TM_STATUS_NEW, TM_STATUS_FAIL
	);


	return undef
		unless scalar @$REZ;

	my $task_data = pop @$REZ;

	unless( $task_data->{'exec_str'} ) {
		$self->set_task_error($task_data->{'id'}, 0xFF, 'illegal params');
		return undef;
	}


	## looking for free slots (if reserve defined)
	if( $task_data->{'priority'}>1 ) {

		my $total_low_pr = scalar grep { $WORKER_PID->{$_}->[2] > 1 } (keys %$WORKER_PID);

		return (undef,undef,undef)
			if( $CFG->{'RESERVED_HIGH_PRIORITY_PROCESS'}
				&& $CFG->{'MAX_CHILD_PROCESS'} - $total_low_pr <= $CFG->{'RESERVED_HIGH_PRIORITY_PROCESS'}
			);
	}


	my $task_exec_str = $self->parse_exec_str($task_data->{'exec_str'});

	unless( $self->validate_exec_str($task_exec_str) ) {
		$self->set_task_error($task_data->{'id'}, 0xFF, 'illegal params');
		return undef;
	}

	TaskManager::DB::do_query(
		"UPDATE task_queue SET dt_start=NOW(), attempt_no=attempt_no+1 WHERE id=?",
		$task_data->{'id'}
	)
		or make_die($TaskManager::DB::error);

	return ( $task_data->{'id'}, [ split(/ +/, $task_exec_str) ], $task_data->{'priority'} );
}


sub check_server {

	my $REZ = TaskManager::DB::select_query(
		"SELECT * FROM server_list WHERE code=?",
		$CFG->{'SERVER_CODE'}
	);

	die "No server found by code '$CFG->{SERVER_CODE}'!"
		unless scalar @$REZ;

	die "Collision detected! More that one server found!"
		if ( scalar(@$REZ) > 1 );

	my $row = pop @$REZ;

	die "Server isn't active!"
		if $row->{'status'} ne TM_SERVER_STATUS_ACTIVE;

	die "Server has illegal limit type!"
		if( $row->{'limit_type'} ne TM_SERVER_LIMIT_TYPE_LOADAVG
			&& $row->{'limit_type'} ne TM_SERVER_LIMIT_TYPE_TASKNUM
		);

	die "No task max defined for queue server!"
		if( $row->{'limit_type'} eq TM_SERVER_LIMIT_TYPE_TASKNUM && !$row->{'max_tasknum'} );

	if( !$row->{'max_tasknum'} || $row->{'max_tasknum'}>TM_MAX_TOTAL_CHILD ) {
		drop_log("Max task num. set to ".TM_MAX_TOTAL_CHILD." from ".$row->{'max_tasknum'});
		$row->{'max_tasknum'} = TM_MAX_TOTAL_CHILD;
	}

	$CFG->{'SERVER_TYPE'} = $row->{'limit_type'};
	$CFG->{'SERVER_ID'} = $row->{'id'};
	$CFG->{'MAX_CHILD_PROCESS'} = $row->{'max_tasknum'};

	return undef;
}


## now it checks the task for current server (not for the whole project)
sub check_uncompleted_tasks {

#	my $__gm = '';
#	$__gm .= ($__gm ? ',' : '').'?'
#		for( 1..scalar( @{$CFG->{'__MUTEX_GROUPS'}} ) );

#	my $sth = $dbh->prepare() or make_die($dbh->errstr);
#	$sth->execute(TM_STATUS_WORK, @{$CFG->{'__MUTEX_GROUPS'}}) or make_die($sth->errstr);

	my $uncomp_tasks = TaskManager::DB::select_query(
		"SELECT COUNT(*) AS total_uncomp FROM task_queue WHERE worker_status=? AND id_worker_server=?",
		TM_STATUS_WORK, $CFG->{'SERVER_ID'}
	);

	drop_log("WARNING! ".$uncomp_tasks->[0]->{'total_uncomp'}." uncompleted tasks found for server $CFG->{SERVER_CODE}!")
		if ( scalar @$uncomp_tasks && $uncomp_tasks->[0]->{'total_uncomp'}>0 );

	return undef;
}


1;
