package MpmasQLTableDefinition4;
use strict;
use warnings;
use Exporter;
use Storable qw(dclone);
use Data::Dumper;
use SimpleObject;
use IndexedTable;
use Carp;

our @ISA = qw(SimpleObject);


my %dependingType = (swapped_keys =>1, merge => 1, recombine => 1);

sub shortError {
	my ($in) = @_;
	my $pos = index $in, "\n at ";
	return substr $in, 0, $pos;
}


##sub create{}: inherits create from SimpleObject

##sub new : alternative constructor with prototype
sub new {
      my ($class,  $type, $numkeys, $string, $id)  = @_;
      
      my $self ={};   
      $self->{id} = $id;
      $self->{type} = $type;     
      $self->{keys} = $numkeys;       
      $self->{content} = $string;       
      bless $self, $class;
      return $self;
}

sub id {
    return $_[0]->{id};
}
sub type {
    return $_[0]->{type};
}
sub keys {
    return $_[0]->{keys};
}
sub set_keys {
    $_[0]->{keys} = $_[1];
}
sub content {
    return $_[0]->{content};
}
sub set_content {
     $_[0]->{content} = $_[1];
}
sub concat_to_content {
    if (exists $_[0]->{content}) {
	  $_[0]->{content} .= $_[1];
    }
    else {
	  $_[0]->{content} = $_[1];
    }
}
sub depends_on_other_table {
	return exists $dependingType{ $_[0]->{type} };	
}
sub dependent_type {
	return exists $dependingType{ $_[1] };	
}

sub transform {
	my ($self,$dbh, $numkeys, $existing_tables) = @_;
	#print "here for ". $self->id."\n";
	$self->set_keys($numkeys) if (not defined $self->keys and defined $numkeys);
	croak "Error: number of keys not set for table ".$self->id."\n" unless (defined $self->keys );
	
	my $newtable;
	if ($self->type eq "sql") {
		  my $string = $self->{content};
	      croak "Error: To use sql tables you need to specify a database connection (Table: ".$self->id.")\n" unless (defined $dbh);
	      eval{	$newtable = IndexedTable->create_from_SQL($dbh, $string, $self->keys, $self->id) };
	      croak "Error: when running SQL query for table ".$self->id.":\n".shortError($@)."\n"  if $@;
	}
	elsif ($self->type eq "sparql") {
		my $string = $self->{content};
		  unless ( $string =~ s/^\s*ENDPOINT\s+<(.*?)>\s+// ) {
			croak "Error: when running SPARQL query for table ".$self->id.":\nEndpoint missing or not recognized in string\n";
		  }  
		  my $endpoint = $1;
		  
		  #print "SPARQL ENDPOINT ", $endpoint, "\n";
		  #print "SPARQL STRING ", $string, "\n";
		  
		  #(PREFIX|SELECT)(.*)$ 
	      eval{	$newtable = IndexedTable->create_from_SPARQL($endpoint, $string, $self->keys, $self->id) };
	      croak "Error: when running SPARQL query for table ".$self->id.":\n".shortError($@)."\n"  if $@;	
	}
	elsif ($self->type eq "ascii") {
		  my $string = $self->{content};
	      eval{	$newtable = IndexedTable->create_from_ascii( $string, $self->keys, $self->id) };
	      croak "Error: when opening file for table ".$self->id.":\n".shortError($@)."\n"  if $@;
	}
	elsif ($self->type eq "list") {
		  my $temp = $self->{content};
	      my %hash = map { $_ => 1 } @$temp;
	      if ($self->keys != 1) {
			croak "Error: when creating list table ".$self->id.": List tables can only have 1 key column\n";			  
		  }
	      
	      eval{	$newtable = IndexedTable->create_from_hash(\%hash, 1, $self->id) };
	      croak "Error: when creating list table ".$self->id.":\n".shortError($@)."\n"  if $@;
	}
	elsif ($self->type eq "set"  ) {
		  my $temp = $self->{content};
	      my %hash = map { $_ => 1 } @$temp;
	      if ($self->keys != 1) {
			croak "Error: when creating set table ".$self->id.": Set tables can only have 1 key column\n";			  
		  }
	      eval{	$newtable = IndexedTable->create_from_hash(\%hash, 1, $self->id) };
	      croak "Error: when creating set table ".$self->id.":\n".shortError($@)."\n"  if $@;
	}
	elsif ($self->type eq "here") {
	      my $sep = '\s*\|\s*';
	      my $end = '\s*§\s*';
		  my $string = $self->{content};

	      eval{	$newtable = IndexedTable->create_from_string($string,$sep, $end,  $self->keys, $self->id, 1) };
	      croak "Error: when creating here table ".$self->id.":\n".shortError($@)."\n"  if $@;
	      # print "here for ". $self->id."\n";
	      #$newtable->printme();
	}
	elsif ($self->type eq "spreadsheet") {
		  my $string = $self->{content};
		  $string =~ /^\s*(.*)\/([^\/]+)$/;
		  
		  my $filename = $1;
		  my $sheetname = $2;
		  croak "Error: when importing spreadsheet table ".$self->id.", sheetname not given.\n"  unless (defined $sheetname);
		  croak "Error: when importing spreadsheet table ".$self->id.", filename not given.\n"  unless (defined $filename);

		  eval{	$newtable = IndexedTable->create_from_spreadsheet($filename,$sheetname, $self->keys, $self->id, 1) };
	      croak "Error: when importing spreadsheet table ".$self->id.":\n".shortError($@)."\n"  if $@;

	}
	elsif ($self->type eq "swapped_keys") {
		  my $string = $self->{content};
		  $string =~ /^\s*(\w+)\s*:\s*(.+)$/;
		  
		  my $oldtablename = $1;
		  my $newkeystring = $2;
		  #print "Here " , $string, "\n (",$oldtablename,")(", $newkeystring,")\n";
  		  croak "Error when creating ".$self->id.", no new keys defined.\n"  unless (defined $newkeystring);

		  my @newkeys = split /\s*,\s*/, $newkeystring;
		  
		  
		  
		  my $oldtable = $existing_tables->get_object_by_id($oldtablename);
		  croak "Error when creating ".$self->id.", original table $oldtablename not (yet) defined.\n"  unless (defined $oldtable);

		  croak "Error when creating ".$self->id.", no new keys identifiable.\n"  unless (scalar @newkeys and defined $newkeys[0]);
		  
		   croak "Error when creating ".$self->id.", inconsistent number of keys:\nTable definition defines ",$self->keys," keys, but
		   key list contains " , scalar @newkeys, " keys.\n"  unless (scalar @newkeys == $self->keys);

		  
		  
		  eval{	$newtable = $oldtable->regrouped_copy_by_colnames(\@newkeys, $self->id )};
	      croak "Error when creating table by (swapped_keys) ".$self->id.":\n".shortError($@)."\n"  if $@;

	}
	elsif ($self->type eq "merge") {
		  my @list_of_tables = split /\s*,\s*/, $self->{content};
	  		  
		  my $oldtablename = $list_of_tables[0]; 
		  $newtable = dclone($existing_tables->get_object_by_id($oldtablename));
		  $newtable->set_id($self->id);
		  
		  croak "Error when creating ".$self->id.", original table $oldtablename not (yet) defined.\n"  unless (defined $newtable);

		  for my $i (1 .. $#list_of_tables ) {
			 my $secondtable = $existing_tables->get_object_by_id($list_of_tables[$i]);
		     croak "Error when creating ".$self->id.", original table ".$list_of_tables[$i]." not (yet) defined.\n"  unless (defined $secondtable);

			  eval{	$newtable = $newtable->merge_with($secondtable) ;
				  };

			  croak "Error when creating table (by merge) ".$self->id.":\n".shortError($@)."\n"  if $@;
			}
			#print "MERGE1: \n"; $newtable->printme_with_header_sorted();

	}
	elsif ($self->type eq "recombine") {
		  my @list_of_tables = split /\s*;\s*/, $self->{content};
		  my $totalColsNum;
	  	  for my $i (0 .. $#list_of_tables ) {	 
	  		 next if ($list_of_tables[$i] =~ /^\s*$/);
	  		$list_of_tables[$i] =~ /^\s*(\w+)\s*:\s*(.+)$/;
		  
			my $oldtablename = $1;
		    	my $newcolstring = $2;
			my @collist = split /\s*,\s*/, $newcolstring;
	      
			if($i == 0) {
				$totalColsNum = scalar @collist;
			}
	       		else {
				croak "Error when creating ".$self->id.", differing number of columns listed for tables to be recombined.\n"  unless ($totalColsNum == scalar @collist);
			}
	      
			croak "Error when creating ".$self->id.", no columns defined.\n"  unless (defined $newcolstring);

			my $oldtable = $existing_tables->get_object_by_id($oldtablename);
			croak "Error when creating ".$self->id.", original table $oldtablename not (yet) defined.\n"  unless (defined $oldtable);

			croak "Error when creating ".$self->id.", column list shorter than required number of keys\n"  if (scalar @collist < $self->keys);

		    my @newkeys = @collist[0 .. ($self->keys -1)];
		    my @newnonkeys = ();
		    if (scalar @collist > $self->keys) 
		   {		
					@newnonkeys = @collist[$self->keys() .. $#collist];
		    }
		    croak "Error when creating ".$self->id.", no new keys identifiable.\n"  unless (scalar @newkeys and defined $newkeys[0]);
		  
			my $temp;
			eval{	$temp = $oldtable->regrouped_copy_by_colnames(\@newkeys, $self->id, \@newnonkeys)};
			croak "Error when creating table (by recombine) ".$self->id.":\n".shortError($@)."\n"  if $@;
		      
		      
		    if (  $i == 0 ) {
				$temp->set_id($self->id);
				$newtable = $temp;
			 } 
			else {	
				eval{	$newtable = $newtable->merge_with($temp) ;
					  };
				croak "Error when creating table ".$self->id.":\n".shortError($@)."\n"  if $@;
			}
		  }
			#print "MERGE1: \n"; $newtable->printme_with_header_sorted();

	}
	
	else {
	      croak "Error: when creating table ".$self->id.":\n Invalid table type ". $self->type() . "\n";
	}
	
	
	return $newtable;
}
