package Camila::Type;

use 5.006;
use strict;
use warnings;
use Data::Dumper;
use Camila;

require Exporter;

our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw();

sub new_from_list {
  my $class = shift;
  my @list = @_;
  my $type;

  my $def_type = shift @list;
  my $defType = $def_type->{atomo};
  if ($def_type->{tipo} eq "ATOMO") {
    $type = { type => 'alias', alias => uc($defType) };
  }

  elsif ($defType eq "FF") {
    $type = create_from_ff_list(@list);
  }

  elsif ($defType eq "EQ") {
    $type = create_from_eq_list(@list);
  }

  elsif ($defType eq "TUP") {
    $type = create_from_tup_list(@list);
  }

  elsif ($defType eq "SET") {
    $type = create_from_set_list(@list);
  }

  elsif ($defType eq "LIST") {
    $type = create_from_seq_list(@list);
  }

  elsif ($defType =~ /^INT(\d+)$/) {
    $type = create_from_int_initsegment($1,@list);
  }

  else {
    $type = { type => 'unknown' }
  }

  return bless $type, $class;
}

sub create_from_ff_list {
  return {
	  type => 'ff',
	  from => Camila::Type->new_from_list(@{$_[0]{lista}}),
	  to   => Camila::Type->new_from_list(@{$_[1]{lista}}),
	 };
}

sub create_from_set_list {
  return {
	  type => 'set',
	  of   => Camila::Type->new_from_list(@{$_[0]{lista}})
	 };
}

sub create_from_seq_list {
  return {
	  type => 'seq',
	  of   => Camila::Type->new_from_list(@{$_[0]{lista}}) 
	 };
}

sub create_from_int_initsegment {
  return { type => 'initsegment',
	   size => shift };
}

sub create_from_eq_list {
  return { type  => 'alias',
	   alias => $_[0]{atomo} }
}

sub create_from_tup_list {
  my @list = @_;
  my $type = { type => 'tuple' };
  for my $field (@list) {
    my @lista = @{$field->{lista}};
    my $name = shift @lista;
    $type->{field}{$name->{atomo}} = Camila::Type->new_from_list(@lista);
  }
  return $type;
}

sub show {
  my $type = shift;
  if ($type->{type} eq "alias") {
    return $type->{alias}
  }

  elsif ($type->{type} eq "ff") {
    return $type->{from}->show." -> ".$type->{to}->show
  }

  elsif ($type->{type} eq "set") {
    return $type->{of}->show."-set"
  }

  elsif ($type->{type} eq "seq") {
    return $type->{of}->show."-seq"
  }

  elsif ($type->{type} eq "initsegment") {
    return $type->{size}
  }

  elsif ($type->{type} eq "tuple") {
    return "( ".join(", ",map{ "$_: ".$type->{field}{$_}->show } keys %{$type->{field}})." )"
  }
}

1;
__END__
