package MpmasDistLatynskiy;

use strict;
use warnings;
use Exporter;
use Math::CDF qw(:all);
use List::Util qw( min max );

#use Math::Random::MT::Auto qw/rand srand/ ???

use MpmasDistSharedFunctions qw(prepare_icdf predraw_from_uniform draw_value_from_cdf do_assignment do_hhmember_assignment do_post_assignment evaluate_constraints divide_constraints set_verbosity);;
use MpmasQLFunctionLanguage;
our @ISA = qw(Exporter);
#our @EXPORT_OK qw();


sub fit_uniform_to_total {
#receive functions arguments
	my ($disinfo, $agentregistry, $observationregistry, $notassigned, $mapregistry, $subarearegistry, $locvarhash, $constraints, $verbose, $d, $clu) = @_;	
#make copy of locvarhash
	my %loc = %$locvarhash; 

#populate variables from the mpmasdist structures
	my $lbound = MpmasQLFunctionLanguage->convert($disinfo->{LBOUND}, \%loc, 0);
	my $ubound = MpmasQLFunctionLanguage->convert($disinfo->{UBOUND}, \%loc, 0);
	my $acceptance_margin = MpmasQLFunctionLanguage->convert($disinfo->{CONFIDENCE}, \%loc, 0);
	my $total = MpmasQLFunctionLanguage->convert($disinfo->{TOTAL}, \%loc, 0); 

	my @potential_owners;
	# compile list of agents not ruled out by constraints 
	AGENTLOOP: foreach my  $curAgent ($agentregistry->object_list) {
			my %loc2 = %loc;
			$loc2{agent_id} = $curAgent->get_attribute("id");
			$loc2{agent}	= $curAgent;
			push @potential_owners, $curAgent if (evaluate_constraints($constraints, ["fixed", "dynamic"], [0,1,2,3], \%loc2, $verbose) == 1 );
	}

	#set num_obs from list of agents
	my $num_obs = scalar @potential_owners;


##Evgenys code, taken as is (just adapting error messages, and restricting output to verbose

	if ($num_obs > 0) { #if there are no agents skip the loop
		#check if total is consistent with bounds and number of observations:
		if ( ($total > ($ubound * $num_obs)) || ($total < ($lbound * $num_obs)) )  {
			print STDERR "Error in fit_uniform_to_total, step $d: Total is not consistent with number of observations and bounds, check your input\n";
			exit(1);
		}

		#calculate range and transform acceptance margin to absolute terms:
		my $range = $ubound - $lbound + 1;
		$acceptance_margin = $total * $acceptance_margin;

		#variables for array with random numbers and sum of its elements:
		my @random_numbers;
		my $sum;
		#variables to record number of tries:
		my $n_tries = 0;

		do {
			#generate random numbers from the range and push into array:
			my $i = 0;
			@random_numbers=();
			
			if ($verbose == 1) {
				print "\nGenerating Population";
				$n_tries = $n_tries + 1; #increase tries counter
				print "\nTry\t$n_tries";
			}

			while ($i < $num_obs) {
			my $random_number = rand($range) + $lbound;
			push (@random_numbers, $random_number);
			$i = $i + 1;
			}
			
			
			#calculate the sum of array elements:
			$sum = 0; 	
			foreach my $num(@random_numbers){
			$sum = $sum + $num;
			}
			
		} until ( ($sum < ($total + $acceptance_margin)) && ($sum > ($total - $acceptance_margin)) );  #compare the sum with population total and confidence interval

		print "\nSAMPLE_TOTAL\t$total\nPOPULATION_TOTAL\t$sum\n" if $verbose;
	
	#Assign numbers to agents
		foreach my  $i (0..$#potential_owners) {
			my $curAgent = $potential_owners[$i];
			my %loc = %$locvarhash;
			$loc{agent_id} = $curAgent->get_attribute("id");
			$loc{agent}	= $curAgent;
			$loc{FIT_value_assigned} = $random_numbers[$i];
			do_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
			do_hhmember_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
			do_post_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
		}
	}
};
sub fit_cdf_to_total {
#receive functions arguments
	my ($disinfo, $agentregistry, $observationregistry, $notassigned, $mapregistry, $subarearegistry, $locvarhash, $constraints, $verbose, $d, $clu) = @_;	
#make copy of locvarhash
	my %loc = %$locvarhash; 

#populate variables from the mpmasdist structures
	my $acceptance_margin = MpmasQLFunctionLanguage->convert($disinfo->{CONFIDENCE}, \%loc, 0);
	my $total = MpmasQLFunctionLanguage->convert($disinfo->{TOTAL}, \%loc, 0); 

	my $transformation_function = MpmasQLFunctionLanguage->translate_to_perl($disinfo->{TFUNCTION}, \%loc); 
	my @potential_owners;
	# compile list of agents not ruled out by constraints 
	AGENTLOOP: foreach my  $curAgent ($agentregistry->object_list) {
			my %loc2 = %loc;
			$loc2{agent_id} = $curAgent->get_attribute("id");
			$loc2{agent}	= $curAgent;
			push @potential_owners, $curAgent if (evaluate_constraints($constraints, ["fixed", "dynamic"], [0,1,2,3], \%loc2, $verbose) == 1 );
	}

	#set num_obs from list of agents
	my $num_obs = scalar @potential_owners;


##Evgenys code, taken as is (just adapting error messages, and restricting output to verbose

	if ($num_obs > 0) { #if there are no agents skip the loop
		#check if total is consistent with bounds and number of observations:

		#calculate range and transform acceptance margin to absolute terms:
		$acceptance_margin = $total * $acceptance_margin;

		#variables for array with random numbers and sum of its elements:
		my @random_numbers;
		my $sum;
		#variables to record number of tries:
		my $n_tries = 0;

		do {
			#generate random numbers from the range and push into array:
			my $i = 0;
			@random_numbers=();
			
			if ($verbose == 1) {
				print "\nGenerating Population";
				$n_tries = $n_tries + 1; #increase tries counter
				print "\nTry\t$n_tries";
			}
			
			#draw numbers and calculate the sum of array elements:
			$sum = 0; 	
			foreach my $j (0..$num_obs -1){
				my $num = rand();
				my %loc2 = %loc;
				$loc2{FIT_value_drawn} = $num;
				my $res = MpmasQLFunctionLanguage->convert($transformation_function, \%loc2, 1, 0);
				$sum = $sum + $res;
				$random_numbers[$j] = $res;
			}
			
		} until ( ($sum < ($total + $acceptance_margin)) && ($sum > ($total - $acceptance_margin)) );  #compare the sum with population total and confidence interval

		if ($verbose == 1) {
			#calculate and print statistic for the sample and generated population:	
			my $pop_mean = $sum/$num_obs;
			my $sample_mean = $total/$num_obs;
			my $pop_min = min @random_numbers;
			my $pop_max = max @random_numbers;	
			print "\nSAMPLE_TOTAL\t$total\nPOPULATION_TOTAL\t$sum\nSAMPLE_MEAN\t$sample_mean\nPOPULATION_MEAN\t$pop_mean\nPOPULATION_MINIMUM\t$pop_min\nPOPULATION_MAXIMUM\t$pop_max\n";
		}	
	
	#Assign numbers to agents
		foreach my  $i (0..$#potential_owners) {
			my $curAgent = $potential_owners[$i];
			my %loc = %$locvarhash;
			$loc{agent_id} = $curAgent->get_attribute("id");
			$loc{agent}	= $curAgent;
			$loc{FIT_value_assigned} = $random_numbers[$i];
			do_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
			do_hhmember_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
			do_post_assignment($disinfo, $curAgent, undef,  \%loc, $verbose);
		}
	}

}



1;
