package AMF::Spec;

use strict;

use vars qw( $spec $nouns $verbs $types $adjectives 
             $default_prefix $default_namespace
           );

$spec = {};

$nouns = $spec -> {nouns} = {};
$verbs = $spec -> {verbs} = {};
$types = $spec -> {types} = {};

$adjectives = $spec -> {adjectives} = {};

$spec -> {namespaces} = {};  ###  prefix => uri
$spec -> {main_ns} = undef;  ###  ??

$spec -> {depends} = [];


use Carp::Assert;

sub define_noun {
  my $name = shift;
  assert( shift eq 'type' );
  my $type = shift;
  
  assert( not ref $name );
  assert( not $nouns -> {$name} );
  assert( not ref $type );

  $nouns -> {$name} = { type => $type };
  return ();
}


sub define_type {
  my $name = shift;
  my $type = shift;
  
  assert( not ref $name );
  assert( (not $types -> {$name} ), "type $name redefined?");
  $types -> {$name} = $type -> [0];

  return ();
}

sub structure {
  my $items = shift;

  my $struct = {};

  foreach ( @$items ) {

    my $type = shift @$_;
    my $name = shift @$_;

    if ( defined $struct -> {$name} ) {
      print "bad structure element $name: repeated";
    }

    $struct -> {$name} = [ $type, @$_ ];
  }

  return ( $struct );
}

use Carp qw( &confess );

sub verb {
  my @arg  = @_;

  my $items = pop @arg;
  assert( scalar @arg );

  assert( ref $items eq 'ARRAY' );
  my $to = $items -> [0];

  assert( ref $to    eq 'ARRAY' );
  shift @$to;

  my @res;

  foreach ( @arg ) {
    push @res, [ '_verb', $_, 'to', @$to ];
  }

  return @res;
}



sub dump_spec {
  use Data::Dumper;
  print "AMF::Spec: -------\n";
  print Dumper( $spec ) ;
  print "\n";
  return;
}


sub verbpair {
  my $first  = shift;
  my $second = shift;

  assert( $first );
  assert( $second );

  $verbs -> {$first}  = { reverse => $second };
  $verbs -> {$second} = { reverse => $first  };
}


sub namespace {
  my $prefix = shift;
  my $uri    = shift;

  assert( $prefix );
  assert( $uri    );
  assert( not $spec -> {namespaces} {$prefix} );

  $spec -> {namespaces} {$prefix} = $uri;
}


sub default_namespace { 
  my $prefix = shift;

  assert( $prefix );

  my $uri = $spec -> {namespaces} {$prefix};
  assert( $uri    );

  $spec -> {main_ns} = $prefix;
  $default_prefix    = $prefix;
  $default_namespace = $uri;
  $spec -> {default_namespace} = $uri;
}




sub process {

  my $ns_hash  = $spec -> {namespaces};
  my $uri_hash = $spec -> {namespace_uris} = {};
  foreach ( keys %$ns_hash ) {
    my $v = $ns_hash -> {$_};
    $uri_hash -> {$v} = $_;
  }

  foreach ( keys %$types ) {
    my $na = $_;
    my $ty = $types -> {$na};
    
    if ( ref $ty eq 'HASH' ) {
      foreach my $el ( keys %$ty ) {
        my $de = $ty -> {$el};
        
        if ( $de -> [0] eq '_verb' ) {
          my $re = $verbs ->{$el};
          if ( not $re ) {
            print "verb $el has no reverse\n";
#            if ( not $ty->{$re} ) {
##              $ty -> {$re} = [@$de];              
#            }
          }
        }
      }
    }
  }
}


sub depend {
  my $module = shift;
  push @{ $spec->{depends} }, $module;
}
  

1;



