package MpmasQLClassDefinition;
use strict;
use warnings;
use Exporter;
use Storable qw(dclone);
use Data::Dumper;
use SimpleObject;
use MpmasQLFunctionLanguage;
use MpmasQLElementDefinition;
use CtUtilities qw(is_in_list is_in_string_list);
our @ISA = qw(SimpleObject);

#class variables
my $defaults;
sub get_default_value {
	shift; #ignore invoker
	my $element = shift;
	my $field = shift;
	my $e = $defaults->element($element);
	return $e->field_content($field);	
};
sub set_defaults {
      shift;
      $defaults = shift;
}

sub create {
	my $class =shift;
	my $id = shift;
	my $NewClassObject = {};
	$NewClassObject->{id} = $id;
	$NewClassObject->{elements} = SimpleObjectRegistry->create;
	$NewClassObject->{attributes} = SimpleObjectRegistry->create;
	bless $NewClassObject, $class;
	return $NewClassObject;
}

sub elements {
	my $self = shift;
	return $self->{elements}->object_list;
}
sub element {
	my $self = shift;
	my $which = shift;
	return $self->{elements}->get_object_by_id($which);
}
sub add_elements {
	my $self = shift;
	my @object = @_;
	$self->{elements}->add_objects(@object);
}
sub delete_elements {
	my $self = shift;
	my @object_ids = @_;
	$self->{elements}->delete_objects(@object_ids);
}
sub instance_attributes {
	my $self = shift;
	return $self->{attributes}->object_list;
}
sub instance_attribute {
	my $self = shift;
	my $which = shift;
	return $self->{attributes}->get_object_by_id($which);
}
sub add_instance_attributes {
	my $self = shift;
	my @object = @_;
	$self->{attributes}->add_objects(@object);
}
sub name {
	my $self = shift;
	return $self->{id};
}
sub id {
	my $self = shift;
	return $self->{id};
}


sub create_model_elements_for_instance {
	my ($self, $curInstanceId, $setup, $milplist, $mperiodN, $verbose) = @_;
	$milplist =  [( MpmasInputfile::DEFBASEMILP() )] unless (defined $milplist);
	$verbose = 0 unless (defined $verbose);

	#Declare lists of new elements
	my (@NewActivities, @NewConstraints, @NewNetworkObjects, @NewPerennialFileEntries, @NewLivestockFileEntries, @NewTPPenaltyEntries, @NewSOS);

	#Convert instance attributes
    my $instance_attributes = {};
    my @sortedAttr = sort {$a->conv_rank() <=> $b->conv_rank() } $self->instance_attributes();

	if ($verbose) {
		
		print "Class: ".$self->name() .", Instance: $curInstanceId, instance attributes:\n";
		print join(", ", ,map{$_->fieldname()} @sortedAttr )."\n";
		
	}

    for my $ia (@sortedAttr) {
		my $locvarhash = {(
		  instance => $curInstanceId
		), %$instance_attributes};
		
		my ($result) ;
		eval {  $result = MpmasQLFunctionLanguage->interprete ($ia->content(), $locvarhash, $ia->content_verbosity()) };
		print STDERR "Error $@\n Instance: $curInstanceId, Instance attribute: ".$ia->fieldname()."\n" and exit(1) if $@;

		$instance_attributes->{$ia->fieldname()} = $result->[0]; 		
	}

	#First loop over all elements of the current class	
	my @elementstack = $self->elements;
	
	ELEMENTSTACK: while (@elementstack) {
		my $curElement = shift @elementstack;
		my ($new, $type, $new_untransformed_elements) = $curElement->transform($curInstanceId, $setup, $milplist, $verbose, $instance_attributes, $mperiodN);
		push @elementstack, @$new_untransformed_elements;
		next unless (defined $new);  ##skip next part if no new transformed elements were created

		###Point to the right hash depending on type of element
		my $rightlist; #pointer to direct newly created object to the right registry
		if ($type eq "constraint"){
			$rightlist = \@NewConstraints;
		}
		elsif ($type eq "activity"){
			$rightlist = \@NewActivities;
		}
		elsif ($type eq "asset"){
			$rightlist = \@NewNetworkObjects;
		}
		elsif ($type eq "perennialfileentry"){
			$rightlist = \@NewPerennialFileEntries;
		}
		elsif ($type eq "livestockfileentry"){
			$rightlist = \@NewLivestockFileEntries;
		}
		elsif ($type eq "timepreference_penalty_entry"){
			$rightlist = \@NewTPPenaltyEntries;
		}
		elsif ($type eq "sos"){
			$rightlist = \@NewSOS;
		}

		push @$rightlist, $new;
		
	}
	return (\@NewConstraints, \@NewActivities, \@NewNetworkObjects, \@NewPerennialFileEntries, \@NewLivestockFileEntries,\@NewTPPenaltyEntries, \@NewSOS);
}
1;
