#!/usr/bin/perl -w
use strict;
use Perl::Util qw(:all);
use Data::Hub qw($Hub);
use Data::Hub::Util qw(path_name);
binmode STDOUT, ':utf8';

sub usage {
  my $name = path_name($0);
  print STDOUT <<__end;
usage:
  $name -h|-help
  $name path [options]
path:
  Path of the template to compile
options:
  -d|-debug   Interactive command-line debugger
  -p|-prompt  Prompt for undefined scalar values
  -b|-begin   Begin sequence, default: [#
  -e|-end     End sequence, default: ]
  -t|-type    Parser type (Parse::Template::___) default is 'Standard'
  -use        Address to data which is placed in the context
  ...         Other options are placed in the context (used)
notes:
* The address specified by -use must be beneath the cwd
* Prompting cannot be used while debugging.
* These hashes are placed on to the context stack:
    1) The -use option (if present)
    2) The environment (\%ENV)
    3) The options hash
* The options hash allows you to define template values on the command line. 
  For instance:
    $name template.txt -month 'December' -year '1973'
  Will result in an options hash of:
    month => 'December',
    year => '1973'
__end
}

our $OPTS = $$Hub{'/sys/OPTS'};
our $ARGV = $$Hub{'/sys/ARGV'};

sub _take_opt {
  for (delete @$OPTS{@_}) {
    return $_ if defined;
  }
  undef;
}

if (_take_opt('h', 'help')) {
  usage();
  exit 0;
}

my $TYPE = _take_opt('t', 'type') || 'Standard';
my $DEBUG = _take_opt('d', 'debug');
my $PROMPT = _take_opt('p', 'prompt');
my $BEG = _take_opt('b', 'begin');
my $END = _take_opt('e', 'end');
my $template_text = '';
my $template_addr = '';
if (my $filename = shift @$ARGV) {
  $template_addr = $Hub->path_to_addr($filename)
    or die "Cannot resolve: $filename\n";
} else {
  {
    local $/ = undef; # slurp
    $template_text = <STDIN>;
  }
}
my $parser_opts = {};
$BEG and $$parser_opts{'begin'} = $BEG;
$END and $$parser_opts{'end'} = $END;
my $out = '';
$$parser_opts{'out'} = \$out;

eval {require "Parse/Template/$TYPE.pm"};
die $@ if $@;
my $p = "Parse::Template::$TYPE"->new($Hub, -opts => $parser_opts);
if ($DEBUG) {
  require Parse::Template::Debug::Debugger;
  Parse::Template::Debug::Debugger::attach($p);
} elsif ($PROMPT) {
  require Parse::Template::Debug::Prompt;
  Parse::Template::Debug::Prompt::attach($p);
}
if (my $mounts = _take_opt('mount')) {
  foreach my $mount_spec (isa($mounts, 'ARRAY') ? @$mounts : ($mounts)) {
    my ($mount_point, $abs_path) = split /\s*=\s*/, $mount_spec;
    $Hub->mount($mount_point, $abs_path);
  }
}
if (my $use = _take_opt('use')) {
  $p->use($$Hub{$_}) for split /\s*[,]\s*/, $use;
}
$p->use($$Hub{'/sys/ENV'});
$p->use($$Hub{'/sys/OPTS'});
if ($template_addr) {
  $p->compile($template_addr);
}
if ($template_text) {
  $p->compile_text(\$template_text);
}
if (!$DEBUG) {
  print $out;
}
