package MpmasMILPExtra;

use strict;
use warnings;
use Exporter;
use Storable qw(dclone);
use Carp qw(croak);
use Data::Dumper;

our @ISA = qw(MpmasMILPAbstract);

sub prepare_shared {
		my ($self, $fn,  $WHICHMILP, $fndefault, $locvarhash) = @_;
		$self->create_from_cll_file($fn, $WHICHMILP, $fndefault, $locvarhash);
		$self->SUPER::prepare_shared();
}		

sub create_from_cll_file {
		my ($self, $fn, $WHICHMILP, $fndefault, $locvarhash) = @_;
		my $poclasses = SimpleObjectRegistry->create();
		my $poconfigs;
		my $poInstances;
		($poclasses, $poconfigs) =  MpmasQLConfigReader::ReadCll($fndefault , $poclasses, $poconfigs, 0, 1) if (defined $fndefault);
		($poclasses, $poconfigs, $poInstances) =  MpmasQLConfigReader::ReadCll ($fn, $poclasses, $poconfigs, 0, 0 );
		$poInstances = MpmasQLVariableProcessing::transform_vars($poInstances,$locvarhash,0);
		$poconfigs = MpmasQLVariableProcessing::transform_vars($poconfigs,$locvarhash,0);
		# transform strings into one element array for 1-instance lists
		for my $l (keys %{$poInstances}) {
			my $s = $poInstances->{$l};
			$poInstances->{$l} =  [$s] unless (ref $poInstances->{$l})	 ; 
		}
		for my $l (keys %{$poconfigs}) {
			my $s = $poconfigs->{$l};
			$poconfigs->{$l} =  [$s] unless (ref $poconfigs->{$l})	 ; 
		}
		$self->set_constraint_type_order($poconfigs->{CONTYPEORDER});
		$self->set_activity_type_order($poconfigs->{ACTTYPEORDER});
		
		
		my $POConstraintRegistry = SimpleObjectRegistry->create();
	    my $POActivityRegistry = SimpleObjectRegistry->create();
	    my $POSOSRegistry = SimpleObjectRegistry->create();

		my $defaults = $poclasses->get_object_by_id("DEFAULT");
	    if (defined $defaults) {  
			  for my $i ( $defaults->elements) {
				  for my $j ($i->fields ) {
					  my $x = $j->content;
					  my $temp;
					  eval {	$temp = MpmasQLFunctionLanguage->interprete ($x, {}, $j->content_verbosity); };
					  print STDERR "Error when interpreting DEFAULT class for $WHICHMILP , Element $i, Field $j:\n$@\n" and exit(1) if $@;
					  $j->set_content($temp->[0]);

				  }
			  }
			  
			  MpmasQLClassDefinition->set_defaults($defaults);
	    }
	      my @list_of_classes_used = keys %{$poInstances};
			print Data::Dumper::Dump($poInstances);
						print Data::Dumper::Dump($poclasses);
	      #### Loop over all classes and create MIP elements for instances
	      print "\e[K \rPreparing instances\r";
	      CLASSLOOP: for my $curClassId (@list_of_classes_used){
		      my $curClass = $poclasses->get_object_by_id($curClassId);
		      unless ($curClass ) {
			      print STDERR "ERROR!!!: Class $curClassId was not defined in $fn file\n" and exit(1);
		      }
		      #Loop over all instances of one class
		      for my $curInstanceId ( @{$poInstances->{$curClassId}}){
			      next unless (defined $curInstanceId);
			      #Create the new model elements which are related to the current instance...
			      my ($NewConstraints, $NewActivities, $temp1, $temp2, $temp3, $temp4, $NewSOS) = $curClass->create_model_elements_for_instance($curInstanceId, $self->setup(), [$WHICHMILP], 0);

			      #...and then add them to the respective registries
			      $POConstraintRegistry->add_objects(@$NewConstraints);
			      $POActivityRegistry->add_objects(@$NewActivities);
				  $POSOSRegistry->add_objects(@$NewSOS);
				  
		      } #END INSTANCE LOOP
	      }#END CLASSLOOP
		  $self->set_activity_registry($POActivityRegistry);
		  $self->set_constraint_registry($POConstraintRegistry);
		  $self->set_SOS_registry($POSOSRegistry);
}
		  


sub set_milpinfo {
	$_[0]->{MILPinfo} = $_[1];
}
sub set_milpinfo_entry {
	$_[0]->{MILPinfo}->{$_[1]} = $_[2];
}
sub set_sorted_constraints {
	$_[0]->{SortedConstraintRef} = $_[1];
}
sub set_sorted_activities {
	$_[0]->{SortedActivityRef} = $_[1];
}
sub set_sorted_quadratic_activities {
	$_[0]->{SortedQuadActRef} = $_[1];
}
sub set_constraint_registry {
	$_[0]->{ConstraintRegistry} = $_[1];
}
sub set_activity_registry {
	$_[0]->{ActivityRegistry} = $_[1];
}
sub set_SOS_registry {
	$_[0]->{SOSRegistry} = $_[1];
}
sub get_constraint_registry {
	return $_[0]->{ConstraintRegistry};
}
sub get_activity_registry {
	return $_[0]->{ActivityRegistry};
}
sub get_SOS_registry {
	return $_[0]->{SOSRegistry};
}

sub activity {
	return $_[0]->{ActivityRegistry}->get_object_by_id($_[1]);
}
sub lp_column_of_activity {
	my $i = $_[0]->{ActivityRegistry}->get_object_by_id($_[1]);
	croak "Activity $_[1] not defined!" unless (defined $i);
	return $i->lp_column;
}
sub add_activities {
	my $self = shift;
	$self->{ActivityRegistry}->add_objects(@_);
}
sub number_of_activities {
	return $_[0]->{ActivityRegistry}->counter;
}
sub activities {
	return $_[0]->{ActivityRegistry}->object_list;
}
sub sorted_activities {
	return $_[0]->{SortedActivityRef}->[$_[1]] if (defined $_[1]);
	return @{$_[0]->{SortedActivityRef}};
}
sub sorted_quadratic_activities {
	return $_[0]->{SortedQuadActRef}->[$_[1]] if (defined $_[1]);
	return @{$_[0]->{SortedQuadActRef}};
}

sub constraint {
	return $_[0]->{ConstraintRegistry}->get_object_by_id($_[1]);
}
sub lp_row_of_constraint {
	my $i = $_[0]->{ConstraintRegistry}->get_object_by_id($_[1]);
	croak "Constraint $_[1] not defined!" unless (defined $i);
	return $i->lp_row;
}
sub add_constraints {
	my $self = shift;
	$self->{ConstraintRegistry}->add_objects(@_);
}
sub number_of_constraints {
	return $_[0]->{ConstraintRegistry}->counter;
}
sub constraints {
	return $_[0]->{ConstraintRegistry}->object_list;
}
sub sorted_constraints {
	return $_[0]->{SortedConstraintRef}->[$_[1]] if (defined $_[1]);
	return @{$_[0]->{SortedConstraintRef}};
}
sub SOS {
	return $_[0]->{SOSRegistry}->get_object_by_id($_[1]);
}
sub SOSs {
	return $_[0]->{SOSRegistry}->object_list;
}
sub number_of_SOS {
	return $_[0]->{SOSRegistry}->counter;
}

sub milpinfo {
	return $_[0]->{MILPinfo}->{$_[1]};
}
sub set_activity_type_order {
	$_[0]->{ACTIVITYORDER} = $_[1];
}
sub set_constraint_type_order {
	$_[0]->{CONSTRAINTORDER} = $_[1];
}
sub get_activity_type_order {
	return $_[0]->{ACTIVITYORDER};
}
sub get_constraint_type_order {
	return $_[0]->{CONSTRAINTORDER};
}
sub set_milplist {
  $_[0]->{milplist} = $_[1];
}
sub milplist {
  return $_[0]->{milplist};
}
sub set_exchanges {
	$_[0]->{exchanges} = $_[1];
}
sub set_number_of_exchanges {
	$_[0]->{number_of_exchanges} = $_[1];
}
sub get_exchanges {
	return $_[0]->{exchanges};
}
sub get_number_of_exchanges {
	return $_[0]->{number_of_exchanges};
}
1;

