package MpmasPerennial;

use strict;
use warnings;
use Exporter;
use Storable qw(dclone);
use Data::Dumper;
use List::Util qw[min max];
use CtUtilities qw(queryhash extqueryhash);
use MpmasInputfile;
use MpmasInputBlock;
our @ISA = qw(MpmasInputfile);

sub filename {
	return "PCrops";
}

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

}
sub prepare_special{
	my $self = shift;

	#Build a sorted array of those constraints that are included in the perennials file
	my @pconstraints;
	my $continue = 1;
	my $cc = $self->milpinfo("MasPerLab");
	while ($continue) {
		my $con = $self->constraint_at_row($cc);
		if ($con->type eq "MASperlab"){
			push  @pconstraints, $con->id;
		}
		else {
			last;
		}
		$cc++;
	}

	##Build the individual perennial characteristics
	my $plist = MpmasInputBlock->new(2,20);
	for my $curP ($self->perennialobjects) { ##LOOP over perenials

		my $lifetime = $curP->lifetime;
		my $no = $self->networkobject($curP->obj);
		$curP->set_oid($no->oid);
		$plist->add_empty_rows(2);
		$plist->add_comment_row("", $curP->name, "(".$curP->id.")");
		$plist->add_row("","Object ID", $curP->oid);
		$plist->add_row("","Purchasing price", $curP->acqcost);
		$plist->add_row("", "Life span",$lifetime );
		$plist->add_empty_rows(1);
		my @header = ("", "Year");
		for my $i (0..$lifetime-1) {push @header, $i} ;
		$plist->add_comment_row(@header);
		for my $entry ("perennial_yield", "perennial_preharvest_cost", "perennial_harvest_cost", @pconstraints) {##LOOP over constraints
			my @row = ("",$entry);
			YEARLOOP: for my $i (0 .. $lifetime-1) { ## LOOP over years
				if (not defined $curP->dynfield($entry)) {
					push @row, "0";
				}
				elsif (not ref $curP->dynfield($entry)) {
					push @row, $curP->dynfield($entry);
				}
				elsif (ref $curP->dynfield($entry)) {
					my $hashref = $curP->dynfield($entry);
					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
						#die ("Error for perennial ".$curP->name. "(". $curP->id."): No entry for $entry for highest age ($lifetime) found.");
						push @row, 0;
					}##END INNER IFBLOCK
				}##END OUTER IFBLOCK
			} ## END LOOP over years
			$plist->add_row(@row);
		} ## END LOOP over constraints		
	}## END LOOP over perennials
	$self->add_block($plist);

	### Group perennials into management groups
	my @switchgroups;
	my $groupcount = -1;
	for my $curP ($self->perennialobjects) { ##LOOP over perenials
	     ##start a new switchgroup for each object that is not yet part of a switchgroup and has entries in managementswitch
	    if (not defined $curP->switchgroup and defined $curP->managementswitch) { 
		  
		  $groupcount++; #Set counter to next index of $switchgroup
		  my @perennialstack; #declare stack for iterating over all connected perennialstack
		  push @perennialstack, $curP; #put first perennial on stack
		  #start iteration
		  while (@perennialstack) {		
			my $p = shift @perennialstack; #take first perennial object from stack
			if (not defined $p->switchgroup) { #if the perennial is not part of a group yet...
				 #include it in the current group
				$p->set_switchgroup($groupcount);
				push @{$switchgroups[$groupcount]}, $p;
				#put all perennials this perennial can be switched to on the stack
				for my $i ($p->switchlist) {
				      my $q = $self->perennialobject($i);	
				      print "Note: No such perennial $i in perennial switch of ".$p->id."\n" and next unless (defined $q);
				      push @perennialstack, $q;
				}
			}
		  }#end while loop - iteration over stack
	    }#END if
	}#end loop over starting perennials

	##Build File Header
	my $ptop =  MpmasInputBlock->new(2,10);
	$ptop->add_comment_row("PERENNIAL CROPS FILE");
	$ptop->add_empty_rows(3);
	$ptop->add_comment_row("2","Perennial Crop Information");
	$ptop->add_row("", "Number of perennial crops:",$self->number_of_perennialobjects);
	$ptop->add_row("", "Number of labor constraints:", 1 );
	$ptop->add_row("", "Number of machinery constraints", scalar @pconstraints - 1 );
	$ptop->add_row("","Number of management groups",scalar @switchgroups);
	$ptop->add_empty_rows(3);
	$self->add_block($ptop);
	#Build Management Block Header and Groups
	my $swtop = MpmasInputBlock->new(2,30);
	$swtop->add_empty_rows(3);
	$swtop->add_comment_row("3","Switching Management Groups");
	$swtop->add_empty_rows(1);
	$swtop->add_comment_row("3.1","Define management groups");
	$swtop->add_comment_row("","Note:	Network.xls defines all perennial crop activities, some of these refer to different management methods (cultivation practices)");						
	$swtop->add_comment_row("","For example, harvesting a tree crop on-season or off-season, various levels of fertilization etc.")	;		
	$swtop->add_comment_row("","For agents it is then possible to switch management techniques over time, e.g., to switch from on-season to off-season harvesting");
	$swtop->add_comment_row("","This matrix defines for what activities (identified by the object ID) such switching is allowed.");				
	$swtop->add_comment_row("","Group ID","Number of objects per group","object IDs,....");
	for my $i (0..$#switchgroups) {
	    my @row = ("",$i, scalar @{$switchgroups[$i]});
	    my @sorted = sort{$a->oid <=> $b->oid} @{$switchgroups[$i]};
	    $switchgroups[$i] = \@sorted;
	    for my $j (@sorted) {
		push @row, $j->oid;
	    }
	    $swtop->add_row(@row);
	}
	$self->add_block($swtop);
	#Build switching matrix
	my $swmatrix = MpmasInputBlock->new(2,40);
	$swmatrix->add_empty_rows(3);
	$swmatrix->add_comment_row("3.2","Define switching combinations and activity indices");
	$swmatrix->add_comment_row("","Note:	For each Group ID enter here a matrix of management methods");
	$swmatrix->add_comment_row("","If 3 methods than create a 3x3 matrix for each group");
	$swmatrix->add_comment_row("","At the diagonal enter \"-1\" as there is no switching from method A to method A");
	$swmatrix->add_comment_row("","If switching from method A to method B is allowed then enter the activity index, if not enter \"-1\"");
	for my $i (0..$#switchgroups) {
		$swmatrix->add_empty_rows(1);
		$swmatrix->add_comment_row("GroupID = $i");
		my @sortedoid;
		for my $c (@{$switchgroups[$i]}) {
		    push @sortedoid, $c->oid;
		}
		$swmatrix->add_comment_row("","From/To",@sortedoid);
		for my $r (@{$switchgroups[$i]}) {
		    my @row = ("",$r->oid);
		    for my $c (@{$switchgroups[$i]}) {
			my $switchto = -1;
			if (defined $c->activity_of_switch_from($r->id)) {
			      my $ai = $c->activity_of_switch_from($r->id) ; 
			      my $ao = $self->activity($ai);
			      die "No such activity $ai for perennial switch  ".$c->id." to ". $r->id."\n" unless (defined $ao);
			      $switchto = $ao->lp_column;
			}
			push @row, $switchto;
		    }
		    $swmatrix->add_row(@row);
		}
		
	}
	$self->add_block($swmatrix);
}
1;
