#!/usr/bin/perl -w
# This file is part of Hubbub.
# Licensed under the MIT License,
#                http://www.opensource.org/licenses/mit-license.php
# Copyright 2010 Daniel Silverstone <dsilvers@netsurf-browser.org>
#                John-Mark Bell <jmb@netsurf-browser.org>

use strict;

use constant ENTITIES_FILE => 'build/Entities';
use constant ENTITIES_INC  => 'src/tokeniser/entities.inc';

open(INFILE, "<", ENTITIES_FILE) || die "Unable to open " . ENTITIES_FILE;

my %entities;

while (my $line = <INFILE>) {
   last unless (defined $line);
   next if ($line =~ /^#/);
   chomp $line;
   next if ($line eq '');
   my @elements = split /\s+/, $line;
   my $entity = shift @elements;
   my $code = shift @elements;
   $entities{$entity} = $code;
}

close(INFILE);

my $output = <<'EOH';
/*
 * This file is part of Hubbub.
 * Licensed under the MIT License,
 *                http://www.opensource.org/licenses/mit-license.php
 * Copyright 2010 The NetSurf Project.
 *
 * Note: This file is automatically generated by make-entities.pl
 *
 * Do not edit file file, changes will be overwritten during build.
 */


EOH

# Build a Trie of the entities

my $heapindex = 0;

my @nodelist;

sub insert_node {
   my ($parent, $key, $code) = @_;
   my ($pivot, $tail);

   if (length($key) == 0) {
      $pivot = ''; $tail = '';
   } elsif (length($key) == 1) {
      $pivot = $key; $tail = '';
   } else {
      $pivot = substr($key, 0, 1);
      $tail = substr($key, 1);
   }

   unless (defined($parent)) {
      $parent = { pivot => $pivot, heapindex => $heapindex };
      push @nodelist, $parent;
      $heapindex++;
   }

   if ($pivot lt $parent->{pivot}) {
      $parent->{lt} = insert_node($parent->{lt}, $key, $code);
   } elsif ($pivot eq $parent->{pivot}) {
      if ($pivot eq '') {
         $parent->{value} = $code;
      } elsif (substr($tail, 0, 1) eq '') {
         $parent->{value} = $code;
         $parent->{eq} = insert_node($parent->{eq}, $tail, $code);
      } else {
         $parent->{eq} = insert_node($parent->{eq}, $tail, $code);
      }
   } else {
      $parent->{gt} = insert_node($parent->{gt}, $key, $code);
   }
   return $parent;
}

my $trie;

foreach my $key (keys %entities) {
   $trie = insert_node($trie, $key, $entities{$key});
}

# Serialise the Trie to the output string

$output .= "static hubbub_entity_node dict[] = {\n";

foreach my $node (@nodelist) {
   my $split = $node->{pivot};
   my $lt = $node->{lt};
   my $eq = $node->{eq};
   my $gt = $node->{gt};
   my $value = $node->{value};

   $lt = $lt->{heapindex} if defined($lt);
   $lt = "-1" unless defined($lt);

   $eq = $eq->{heapindex} if defined($eq);
   $eq = "-1" unless defined($eq);

   $gt = $gt->{heapindex} if defined($gt);
   $gt = "-1" unless defined($gt);

   $split = ord($split) if ($split ne '');
   $split = 0 if ($split eq '');

   $value = "0" unless defined($value);

   $output .= "\t{ $split, $lt, $eq, $gt, $value },\n";
}

$output .= "};\n\n";

$output .= "static int32_t dict_root = " . $trie->{heapindex} . ";\n";

# Write file out

if (open(EXISTING, "<", ENTITIES_INC)) {
   local $/ = undef();
   my $now = <EXISTING>;
   undef($output) if ($output eq $now);
   close(EXISTING);
}

if (defined($output)) {
   open(OUTF, ">", ENTITIES_INC);
   print OUTF $output;
   close(OUTF);
}
