#!/usr/bin/perl

#
use strict;
my $local_site; # site we are generating for
my $rootnode = undef;
my %sites;
########################### read config from file ##########################
my $config_file_ln = 0; # current line number
# read line, combining escaped (ending in \) lines into one, removing
# leading and trailing whitespace, comments and empty lines
sub read_line {
 my $line = undef;
 my $i;
 for ($i = 0; <CONFIG_FILE>; ++$i) {
  chomp;
  ++$config_file_ln;
  s/^\s*//; s/\s*$//;
  next if $_ eq '';
  # comments
  next if /^[\;\#]/ || /^\/\//;
  $line = "$line$_";
  if ($line =~ /\\$/) {
   chop $line;
  } else {
   last;
  }
 }
 return $line;
}
sub read_config_die {
 print "line $config_file_ln: $_[0]\n";
 exit;
}
sub read_node {
 my ($node) = @_;
 my $prevnode;
 return if $node->{type} eq 'seperator';
 my %valid_variables = (
  title => 1,
  description => 1,
  site => 1,
  body => 1,
  email => 1,
 );
 while ($_ = read_line()) {
  my @fields = split(/\s+/);
  if ($fields[0] eq "end") {
   if ($fields[1] && $fields[1] ne $node->{location}) {
    read_config_die "'end $fields[1]' but this is " . 
        $node->{location};
   }
   last;
  } elsif ($node->{type} eq "node" 
        && $fields[0] =~/^(dir|seperator|link|file|node)$/ ) {
   my $subnodes = [];
  
   my $nodename = '';
   $nodename = $fields[1] if ($fields[1]);
   my $subnode = {
    location => $nodename,
    parent => $node,
    type => $fields[0],
    subnodes => $subnodes,
    title => $nodename,
   };
   if ($prevnode) {
    $subnode->{prevnode} = $prevnode;
    $prevnode->{nextnode} = $subnode;
   }
   bless $subnode;
   $subnodes = $node->{subnodes};
   push(@$subnodes, $subnode);
   read_node($subnode);
   $prevnode = $subnode if $subnode->{type} eq 'node';
  } elsif (/^\S+\s*\=/) {
   # value
   
   my ($variable, $value) = ($_, $_);
   $variable =~ s/\s*\=.*$//;
   $value =~ s/^\S+\s*\=\s*//;
   if (!$valid_variables{$variable}) {
    read_config_die "invalid variable $variable specified";
   }
   $node->{$variable} = $value;
  } elsif ($fields[0] eq "site") {
   $sites{$fields[1]} = $fields[2];
  } else {
   read_config_die "invalid line '$_'";
  }
 }
}
sub read_config {
 %sites = {};
 $sites{'*'} = 'all sites';
 my $subnodes = [];
 open(CONFIG_FILE, 'fnet.txt') or die "cant open fnet.txt";
 $config_file_ln = 0;
 $rootnode = {
  location => '',
  type => 'node',
  site => '*',
  subnodes => $subnodes,
 };
 read_node $rootnode;
 close(CONFIG_FILE);
}
sub get_node_property {
 my ($node, $property) = @_;
 for (;; $node=$node->{parent}) {
  if ($node->{$property}) {
   return $node->{$property};
  }
  last if (!$node->{parent})
 }
 return undef;
}
sub get_node_site {
 my ($node) = @_;
 my $site = get_node_property($node, 'site');
 $site = $local_site if ($site eq '*');
 die "site $site not specified!" if (!$sites{$site});
 return $site;
}
sub get_node_url {
 my ($node) = @_;
 my $url = '';
 return $node->{location} if ($node->{type} eq 'link');
 for (my $n = $node; $n->{parent}; $n = $n->{parent}) {
  $url = '/' . $n->{location} . $url; 
 }
 $url = $sites{get_node_site($node)} . $url;
 $url .= '/' if ($node->{type} eq 'node' || $node->{type} eq 'dir');
 return $url;
}
sub get_node_relative_url {
 my ($source, $target) = @_;
 return $target->{location} if ($target->{type} eq 'link');
 if (get_node_site($source) ne get_node_site($target)) {
  return get_node_url($target); 
 }
 return $target->{location} if ($target->{type} eq 'file');
 return $target->{location} . '/';
}
######################### sitemap #################################
my $depth = 0;
sub generate_sitemap_node {
 my ($node) = @_;
 my $subnodes = $node->{subnodes};
 print SITEMAP '<a href="' . get_node_url($node) . '">';
 print SITEMAP $node->{title};
 print SITEMAP "</a>\n";
 if ($node->{type} eq 'node') {
  ++$depth;
  print SITEMAP ' ' x $depth . "<ul>\n";
  foreach (@$subnodes) {
   next if ($_->{type} eq 'link'
         || $_->{type} eq 'seperator');
   print SITEMAP (' ' x $depth) . "<li>";
   
   generate_sitemap_node $_, $depth;
  }
  print SITEMAP ' ' x $depth . "</ul>\n";
  --$depth;
 }
}
sub generate_sitemap {
 my ($file) = @_;
 open(SITEMAP, ">$file") or die "cant open $file";
 print SITEMAP "<html>\n";
 print SITEMAP "<head><title>Sitemap</title></head>\n";
 print SITEMAP "<body " . get_node_property($rootnode, 'body') . ">\n";
 print SITEMAP "<h2>Sitemap</h2>\n";
 print SITEMAP "<hr>\n";
 generate_sitemap_node $rootnode, 0;
 print SITEMAP "<hr>\n";
 print SITEMAP '<a href="' . get_node_property($rootnode, 'email') ;
 print SITEMAP '">email</a>' . "\n";
 print SITEMAP "</body>\n";
 print SITEMAP "</html>\n";
 close SITEMAP;
}
############################ main node pages ############################
sub generate_page_tree {
 my ($node) = @_;
 my $text = "";
 if ($node->{parent}) {
  $text = generate_page_tree($node->{parent});
 }
 $text .= '<a href="' . get_node_url($node) . '">';
 $text .= $node->{title};
 $text .= '</a>';
 return $text . " > \n";
}
sub nodelink {
 my ($rel, $node) = @_;
 if ($node) {
  print NODE_PAGE "<link ";
  print NODE_PAGE "rel=\"$rel\" ";
  print NODE_PAGE "href=\"" . get_node_url($node) . "\" ";
  print NODE_PAGE "title=\"" . $node->{title} . "\" ";
  print NODE_PAGE ">\n";
 }
}
sub generate_page {
 my ($node, $filename) = @_;
 open (NODE_PAGE, ">$filename") or die "cant open $filename for writing";
 print NODE_PAGE "<html>\n";
 print NODE_PAGE "<head>\n";
 print NODE_PAGE "<title>" . $node->{title} . "</title>\n";
 # mozilla site nav links
 print NODE_PAGE "<link rel=\"ToC\" href=\"" . 
   get_node_url($rootnode) . "sitemap.html\">\n";
 nodelink "Top", $rootnode;
 nodelink "Up", $node->{parent};
 nodelink "Prev", $node->{prevnode};
 nodelink "Next", $node->{nextnode};
 print NODE_PAGE "</head>\n";
 print NODE_PAGE "<body ". get_node_property($node, 'body') .">\n";
 print NODE_PAGE "<h2>" . $rootnode->{title} . "</h2>\n";
 if ($node->{parent}) {
  print NODE_PAGE generate_page_tree($node->{parent});
  print NODE_PAGE $node->{title};
 }
 if ($node->{description}) {
  print NODE_PAGE "<br><br>\n" if $node->{parent};
  print NODE_PAGE $node->{description} . "\n";
 }
 print NODE_PAGE "<ul>\n";
 my $subnodes = $node->{subnodes};
 foreach (@$subnodes) {
  if ($_->{type} eq 'seperator') {
   print NODE_PAGE "</ul><hr><ul>\n";
   next;
  }
  print NODE_PAGE "<li> ";
  print NODE_PAGE "<a href=\"" . get_node_relative_url($node, $_);
  print NODE_PAGE "\">" . $_->{title} . "</a>\n";
  if ($_->{description}) {
   print NODE_PAGE "<br>" . $_->{description} . "\n";
  }
 }
 print NODE_PAGE "</ul>\n";
 print NODE_PAGE "<hr>\n";
 print NODE_PAGE "<a href=\"" . get_node_property($node, 'email') . "\">email</a>\n";
 print NODE_PAGE "</body>\n</html>\n";
 close NODE_PAGE;
}
sub generate_tree {
 my ($node, $dir) = @_;
 mkdir $dir if $dir;
 generate_page $node, $dir . 'index.shtml';
 my $subnodes = $node->{subnodes};
 foreach (@$subnodes) {
  # only generate local nodes
  
  if ($_->{type} eq 'node' && get_node_site($_) eq $local_site) {
   generate_tree($_, $dir . $_->{location} . '/') ;
  }
 }
}
if (!$ARGV[0]) {
 print "Usage: $0 site\n";
 exit;
}
$local_site = $ARGV[0];
read_config;
die "Specified site $local_site does not exist!" if (!$sites{$local_site});
generate_sitemap('sitemap.html');
generate_tree($rootnode);