#!/opt/bin/perl

# usage: res2pm

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

print <<EOF;
=head1 NAME

Deliantra::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 Deliantra::Data;

EOF

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


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 $grove_builder = XML::Grove::Builder->new;
my $parser = XML::Parser::PerlSAX->new ( Handler => $grove_builder );
my $type = $parser->parse ( Source => { SystemId => "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 "", map $_->{Data}, @{shift->{Contents}};
   $_ =~ s/^\s+//;
   $_ =~ s/\s+$//;
   $_ =~ s/\s+/ /g;
   $_
}

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

   my $arch = {
      type => $e->{Attributes}->{type},
      name => $e->{Attributes}->{editor},
      desc => string $e,
      $e->{Attributes}->{arch_begin} ? (end => $e->{Attributes}->{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->{Attributes}->{value};
   } elsif ($arch->{type} =~ s/^bool_special$/bool/) {
      $arch->{value} = [$e->{Attributes}->{false}, $e->{Attributes}->{true}];
   }

   push @$sect, [$e->{Attributes}->{arch} || $e->{Attributes}->{arch_begin}, $arch];
}

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

   my %main;

   for my $e (grep { $_->isa ('XML::Grove::Element') } @{$e->{Contents}}) {
      if ($e->{Name} eq "required") {
         # not used
         #for my $i (grep $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
         #   $type->{required}{$i->{Attributes}->{arch}} = $i->{Attributes}->{value};
         #}
      } elsif ($e->{Name} eq "attribute") {
         parse_attr $e, $type->{attr} ||= [];
      } elsif ($e->{Name} eq "ignore") {
         for my $i (grep $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
            if ($i->{Name} eq "ignore_list") {
               push @{$type->{ignore}}, $ignore_list{$i->{Attributes}->{name}} ||= [];
            } elsif ($i->{Name} eq "attribute") {
               push @{$type->{ignore}}, $i->{Attributes}->{arch};
            }
         }
      } elsif ($e->{Name} eq "import_type") {
         #push @{$type->{import}}, $type{$e->{Attributes}->{name}} ||= {};
         push @{$type->{import}}, $e->{Attributes}->{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 $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
            parse_attr $i, \@attr;
         }
         push @{ $type->{section} }, [$e->{Attributes}->{name} => \@attr];
      } else {
         warn "unknown types subelement ", $e->{Name};
      }
   }

   $type
}

for my $e (grep $_->isa ('XML::Grove::Element'), @{$type->root->{Contents}}) {
   if ($e->{Name} eq "bitmask") {
      my $bm = $bitmask{$e->{Attributes}->{name}} ||= {};
      for my $b (grep $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
         $bm->{$b->{Attributes}->{bit}} = $b->{Attributes}->{name};
      }
   } elsif ($e->{Name} eq "list") {
      my $list = $list{$e->{Attributes}->{name}} ||= {};
      for my $b (grep $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
         $list->{$b->{Attributes}->{value}} = $b->{Attributes}->{name};
      }
   } elsif ($e->{Name} eq "ignore_list") {
      my $list = $ignore_list{$e->{Attributes}->{name}} ||= [];
      for my $b (grep $_->isa ('XML::Grove::Element'), @{$e->{Contents}}) {
         push @$list, $b->{Attributes}->{arch};
      }
   } elsif ($e->{Name} eq "default_type") {
      parse_type $e, \%default_attr;
   } elsif ($e->{Name} eq "type") {
      my $type = $type{$e->{Attributes}->{name}} ||= {};

      $type->{name} = $e->{Attributes}->{name};

      parse_type $e, $type;

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

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

my $type = $parser->parse ( Source => { SystemId => "res/typenumbers.xml" } );

for (grep $_->isa ('XML::Grove::Element'), @{$type->root->{Contents}}) {
   $typename{$_->{Attributes}->{number}} = $_->{Attributes}->{name};
}

my $spell = $parser->parse ( Source => { SystemId => "res/spells.xml" } )
   or die;

for (grep $_->isa ('XML::Grove::Element'), @{$spell->root->{Contents}}) {
   $spell{$_->{Attributes}->{id}} = $_->{Attributes}->{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

