#!/opt/bin/perl

# usage: res2pm

open STDOUT, ">:utf8", "Crossfire/Data.pm"
   or die "Crossfire/Data.pm: $!";

print <<EOF;
=head1 NAME

Crossfire::Data - various data structures useful for understanding archs and objects

=head1

THIS FILE IS AUTOGENERATED, DO NOT EDIT!

It's a translation of the following files:

 res/spells.xml
 res/types.xml
 res/typenumbers.xml

See F<res/README> for more info.

=cut

package Crossfire::Data;

EOF

use Data::Dumper;
use XML::Parser::Grove;

sub dump_hash {
   my ($names, $refs) = @_;

   $d = new Data::Dumper ($refs, [map "*$_", @$names]);
   $d->Terse (1);
   $d->Indent (1);
   $d->Quotekeys (0);
   $d->Useqq (0);
   $d->Useperl(1);
   $d->Sortkeys (sub {
      [sort {
         $a > 0 && $b > 0 ? $a <=> $b
                          : $a cmp $b
      } keys %{+shift}]
   });

   my @vals = $d->Dump;

   while (@vals) {
      my $v = shift @vals;
      $v =~ s/^                /\t\t/gm;
      $v =~ s/^        /\t/gm;
      $v =~ s/\s+$//;

      my $name = shift @$names;
      my $ref = shift @$refs;

      my $sigil = ref $ref eq "ARRAY" ? '@' : '%';

      print "our $sigil$name = $v;\n\n";
   }
}

my $type = XML::Parser->new (Style => 'grove')->parsefile ("res/types.xml");

my %bitmask;
my %list;
my %type;
my %typename;
my @attr0;
my %attr;
my %ignore_list;
my %default_attr;
my %spell;

sub string($) {
   local $_ = join "", @{shift->contents};
   $_ =~ s/^\s+//;
   $_ =~ s/\s+$//;
   $_ =~ s/\s+/ /g;
   $_
}

sub parse_attr {
   my ($e, $sect) = @_;

   my $arch = {
      type => $e->attr ("type"),
      name => $e->attr ("editor"),
      desc => string $e,
      $e->attr("arch_begin") ? (end => $e->attr("arch_end")) : (),
   };

   delete $arch->{name} unless defined $arch->{name};
   delete $arch->{desc} unless length  $arch->{desc};

   if ($arch->{type} =~ s/^(bitmask)_(.*)/$1/) {
      $arch->{value} = $bitmask{$2} ||= {};
   } elsif ($arch->{type} =~ s/^(list)_(.*)/$1/) {
      $arch->{value} = $list{$2} ||= {};
   } elsif ($arch->{type} eq "fixed") {
      $arch->{value} = $e->attr ("value");
   } elsif ($arch->{type} =~ s/^bool_special$/bool/) {
      $arch->{value} = [$e->attr ("false"), $e->attr ("true")];
   }

   push @$sect, [$e->attr ("arch") || $e->attr("arch_begin"), $arch];
}

sub parse_type {
   my ($e, $type) = @_;

   my %main;

   for my $e (grep ref, @{$e->contents}) {
      if ($e->name eq "required") {
         # not used
         #for my $i (grep ref, @{$e->contents}) {
         #   $type->{required}{$i->attr ("arch")} = $i->attr ("value");
         #}
      } elsif ($e->name eq "attribute") {
         parse_attr $e, $type->{attr} ||= [];
      } elsif ($e->name eq "ignore") {
         for my $i (grep ref, @{$e->contents}) {
            if ($i->name eq "ignore_list") {
               push @{$type->{ignore}}, $ignore_list{$i->attr ("name")} ||= [];
            } elsif ($i->name eq "attribute") {
               push @{$type->{ignore}}, $i->attr ("arch");
            }
         }
      } elsif ($e->name eq "import_type") {
         push @{$type->{import}}, $type{$e->attr ("name")} ||= {};
      } elsif ($e->name eq "use") {
         $type->{use} = string $e;
      } elsif ($e->name eq "description") {
         $type->{desc} = string $e;
      } elsif ($e->name eq "section") {
         my @attr;
         for my $i (grep ref, @{$e->contents}) {
            parse_attr $i, \@attr;
         }
         push @{ $type->{section} }, [$e->attr ("name") => \@attr];
      } else {
         warn "unknown types subelement ", $e->name;
      }
   }

   $type
}

for my $e (grep ref, @{$type->root->contents}) {
   if ($e->name eq "bitmask") {
      my $bm = $bitmask{$e->attr ("name")} ||= {};
      for my $b (grep ref, @{$e->contents}) {
         $bm->{$b->attr ("bit")} = $b->attr ("name");
      }
   } elsif ($e->name eq "list") {
      my $list = $list{$e->attr ("name")} ||= {};
      for my $b (grep ref, @{$e->contents}) {
         $list->{$b->attr ("value")} = $b->attr ("name");
      }
   } elsif ($e->name eq "ignore_list") {
      my $list = $ignore_list{$e->attr ("name")} ||= [];
      for my $b (grep ref, @{$e->contents}) {
         push @$list, $b->attr ("arch");
      }
   } elsif ($e->name eq "default_type") {
      parse_type $e, \%default_attr;
   } elsif ($e->name eq "type") {
      my $type = $type{$e->attr ("name")} ||= {};

      $type->{name} = $e->attr ("name");

      parse_type $e, $type;

      if ($e->attr ("number") > 0) {
         $attr{$e->attr ("number")} = $type;
      } elsif ($e->attr ("name") eq "Misc") {
         delete $type->{required};
      } else {
         push @attr0, $type;
      }

   } else {
      warn "unknown types element ", $e->name;
   }
}

my $type = XML::Parser->new (Style => 'grove')->parsefile ("res/typenumbers.xml");

for (grep ref, @{$type->root->contents}) {
   $typename{$_->attr ("number")} = $_->attr ("name");
}

my $spell = XML::Parser->new (Style => 'grove')->parsefile ("res/spells.xml")
   or die;

for (grep ref, @{$spell->root->contents}) {
   $spell{$_->attr ("id")} = $_->attr ("name");
}

dump_hash ["BITMASK", "LIST", "IGNORE_LIST", "DEFAULT_ATTR", "TYPE", "ATTR", "TYPENAME", "SPELL"],
          [\%bitmask, \%list, \%ignore_list, \%default_attr, \%type, \%attr, \%typename, \%spell];

print <<EOF;

=head1 AUTHOR

 Marc Lehmann <schmorp@schmorp.de>
 http://home.schmorp.de/

 The source files are part of the CFJavaEditor.

=cut

1
EOF

