package MpmasLivestock;

use strict;
use warnings;
use Exporter;
use Storable qw(dclone);
use Data::Dumper;
use List::Util qw[min max];

use CtUtilities qw(queryhash extqueryhash numbers_robust_to_sorting);
use MpmasInputfile;
use MpmasInputBlock;
our @ISA = qw(MpmasInputfile);

sub filename {
	return "Livest";
}

sub required {
	my $self = shift;
	return ($self->config_entry("LIVESTOCK_MODEL") >= 1);
}
sub prepare_shared {

}
sub prepare_special{
	my $self = shift;
	
	#Sort livestockobjects by id
	my @sortedlvobjects = sort {numbers_robust_to_sorting($a->id) cmp numbers_robust_to_sorting($b->id)} $self->livestockobjects;

	my $livestockhead = MpmasInputBlock->new(2,10);
	$livestockhead->add_comment_row("THE LIVESTOCK FILE");
	$livestockhead->add_comment_row("","Note:The constraint and activity indices refer to the first current production activity.");
	$livestockhead->add_comment_row("","Currently the model only runs for a single cash span.");
	$livestockhead->add_empty_rows(2);
	$livestockhead->add_comment_row("1","MATRIX PARAMETERS");
		
	$livestockhead->add_comment_row("","Note: Always first enter the female and then the male. This order is needed by the \"random gender assignment\"."); 
	$livestockhead->add_comment_row("","If it assigns the offspring to be female, it enters at the first location, if male it enters at the second location.");

	my $lvmatrix = MpmasInputBlock->new(2,20);
	$lvmatrix->add_comment_row("1.4","Location of the animals of age 0 sold at the start of the period, plus the location of selling prices");
	$lvmatrix->add_comment_row("","Livestock","Object ID","Constraint indices","Activity indices","Activity indices for selling prices");

	#Build the info on selling at age 0 activities and at the same time gather arrays of internal and sales products
	my @internals;
	my %internals;
	my @salesp;
	my %salesp;
	my @maxdemands;
	my %maxdemands;
	for my $i (@sortedlvobjects) {
		for my $j ($i->subelement_fields("dyn_internal")) {
			my $o = $self->constraint($j);
			print STDERR  "Constraint $j is referred to in livestock element, but has not been declared anywhere.\n"  and exit(1) unless (defined $o);
			$internals{$j} = 1 ;
		}
		for my $j ($i->subelement_fields("dyn_max_demand")) {
			my $o = $self->constraint($j);
			print STDERR  "Constraint $j is referred to in livestock element, but has not been declared anywhere.\n"  and exit(1) unless (defined $o);
			print STDERR  "Error: You have defined a dyn_max_demand field for a livestock asset, but have  not set LIVESTOCK_MODEL > 1.\n"  and exit(1) unless ($self->config_entry("LIVESTOCK_MODEL") > 1);
			$maxdemands{$j} = 1 ;
		}
		for my $j ($i->subelement_fields("dyn_sales")) {
			my $o = $self->constraint($j);
			print STDERR  "Constraint $j is referred to in livestock element, but has not been declared anywhere.\n" and exit(1) unless (defined $o);
			$salesp{$j} = 1;
		}
		my $no = $self->networkobject($i->obj);
		print STDERR "Error: The asset ".$i->obj. ", which has been linked to the livestock type ".$i->name." has not been defined\n" and exit(1) unless (defined $no);
		$i->set_oid($no->oid);

		my $s0act = $self->activity($i->attr("s0act"));
		print STDERR "Error: Activity '". $i->attr("s0act") ."' unknown!\nLivestock Object: '". $i->attr("name")."', Field 's0act'.\n" and exit(1) unless (defined $s0act);
		my $s0con = $self->constraint($i->attr("s0con"));
		print STDERR "Error: Activity '". $i->attr("s0con") ."' unknown!\nLivestock Object: '". $i->attr("name")."', Field 's0con'.\n" and exit(1) unless (defined $s0con);
		my $priceact = $self->activity($i->attr("salesactivity_meat"));
		print STDERR "Error: Activity '". $i->attr("salesactivity_meat") ."' unknown!\nLivestock Object: '". $i->attr("name")."', Field: 'salesactivity_meat'.\n" and exit(1) unless (defined $priceact);
		$lvmatrix->add_row("",$i->id,$i->oid,$s0con->lp_row, $s0act->lp_column,$priceact->lp_column); 
	}
	@internals = keys %internals;
	@maxdemands = keys %maxdemands;
	@salesp = keys %salesp;
	$self->add_block($lvmatrix);

	$livestockhead->add_row("","Number of marketable products",scalar @salesp);
	$livestockhead->add_row("","Number of internal products", scalar @internals);
	if ($self->config_entry("LIVESTOCK_MODEL") > 1 ) {
		$livestockhead->add_row("","Number of maximum demand products", scalar @maxdemands);
	} 
	$livestockhead->add_row("","Number of livestock types", scalar @sortedlvobjects);
	$self->add_block($livestockhead);



	##Build the 
	my $plist = MpmasInputBlock->new(3,30);
	# find masforget constraint, for linking unused, but required items
	my $dlco= $self->constraint_at_row($self->milpinfo("MasForget"));
	print STDERR "Livestock Model: No constraint of type MASforget found!\n" and exit(1) unless (defined $dlco);
	my $deadlink = $dlco->id;
	
	for my $curP (@sortedlvobjects) { ##LOOP over sorted livestock objects
		my $act = $self->activity($curP->attr("act"));
		my $actlp = $act->lp_column;

		my $lifetime = $curP->lifetime;
		$plist->add_empty_rows(2);
		$plist->add_comment_row("", $curP->name, "(".$curP->id.")");
		$plist->add_row("","Object ID", "",$curP->oid);
		$plist->add_row("","Purchase price","", $curP->acqcost);
		$plist->add_row("","Purchase age", "",$curP->attr("purchase_age"));
		$plist->add_row("", "Life span","",$lifetime );
		$plist->add_empty_rows(1);
		my @header = ("","Group", "Item", "LP Constraint", "LP Activity");
		push @header, (0..$lifetime-1);
		$plist->add_comment_row(@header);

		

		for my $entry ("dyn_liveweight", "dyn_offspring", "dyn_sales", "dyn_internal", "dyn_liquidity", "dyn_land", "dyn_labor", "dyn_max_demand" ) {
  
			my @cs;
			if ( $entry eq "dyn_sales" ) {
			    @cs = @salesp;
			}
			elsif ( $entry eq "dyn_internal" ){
			    @cs = @internals;
			}
			elsif ( $entry eq "dyn_max_demand" ){
				next unless ($self->config_entry("LIVESTOCK_MODEL") > 1);
			    @cs = @maxdemands;
			}
			elsif ($entry eq "dyn_land") {
			    my $numsoils = $self->config_entry("NNRU");
			    @cs = sort {$a cmp $b} $curP->subelement_fields("dyn_land");
			    print STDERR  "Error in livestock object ". $curP->id. ":\nYou defined more dyn_land fields than you have soil types.\nYou can have only one dyn_land field per NRU.\n Use dyn_internal fields with negative values if your dyn_land fields do not correspond to NRUs.\n" and exit (1) if (scalar(@cs) > $numsoils); 
			    for my $i (0..$numsoils -1) {
					$cs[$i] = undef unless (defined $cs[$i]);    
				
			    }
			}
			elsif ($entry eq "dyn_labor") {
			    @cs =  $curP->subelement_fields("dyn_labor");
			    print STDERR  "Error in livestock object ". $curP->id. ":\nYou defined more  than one dyn_labor field.\nYou can have only one dyn_labor field.\n Use dyn_internal fields with negative values if your dyn_labor fields do not correspond to labgrps.\n" and exit (1) if (scalar(@cs) > 1); 
			    $cs[0] = undef unless (defined $cs[0]);    
			}
			else {
			    @cs = sort {$a cmp $b} $curP->subelement_fields($entry);
			    $cs[0] = undef if (scalar @cs == 0);    
			}
			
			for my $zf (@cs) {
				my $z = $zf;
				$z = $deadlink if (not defined $z);
				
				my $zo = $self->constraint($z);
				print STDERR "Error in livestock object ". $curP->id. ":\n Constraint $z not found\n" and exit(1) unless (defined $zo);
				my @row = ("",$entry, $z,$zo->lp_row, $actlp );


				YEARLOOP: for my $i (1 .. $lifetime) { ## LOOP over years
					if (not defined $curP->subelement_field($entry, $z)) {
						push @row, "0";
					}
					elsif (not ref $curP->subelement_field($entry, $z)) {
						push @row, $curP->subelement_field($entry, $z);
					}
					elsif (ref $curP->subelement_field($entry,$z)) {
						my $hashref = $curP->subelement_field($entry, $z);
						if (defined $hashref->{$i}) {
							push @row , $hashref->{$i};
						}
						else{
							for my $j ($i + 1 .. $lifetime) {##LOOP to find next year with existing entry
								if (defined $hashref->{$j}) {
									push @row, $hashref->{$j};
									next YEARLOOP;
								}		
							}##END LOOP to find next year
							## only reached if no further entry found on top
							push @row, 0;
						}##END INNER IFBLOCK
					}##END OUTER IFBLOCK
				} ## END LOOP over years
				$plist->add_row(@row);
			} ##END loop over constraints
		} ## END LOOP over entries		
	}## END LOOP over perennials
	$self->add_block($plist);


}
1;
