package MT::Plugin::LibXSLT;

# mt-xslt.pl - A Plugin for XSL Transformation via XML::LibXSLT
# Author:  klm <klm at okowa dot org>
# License: same as Perl

use strict;
use MT;
use MT::Template::Context;
our $VERSION = 0.1;
our ($Parser, $Processor, %Cache);

eval { require MT::Plugin };
MT->add_plugin(MT::Plugin->new({
    name        => __PACKAGE__ . " v$VERSION",
    description => "A Plugin for XSL Transformation via XML::LibXSLT",
})) unless $@;

MT::Template::Context->add_container_tag(Transform => \&Transform);

sub Transform
{
    my ($ctx, $args, $cond) = @_;
    init();

    my $builder = $ctx->stash('builder');
    my $tokens = $ctx->stash('tokens');
    my $dir = $ctx->stash('blog')->site_path;

    my $text = $builder->build($ctx, $tokens);
    $text =~ s/^\s+//s;
    $text =~ s/\s+$//s;
    my $xml = $Parser->parse_string($text);

    my @cmds = map  { m[^/] ? $_ : "$dir/$_" }
               map  { $args->{$_} }
               sort { $a cmp $b }
               grep { /^_\d+$/ }
               keys %$args;

    my $xsl;
    foreach my $cmd (@cmds)
    {
        my @arg;
        push @arg, $1 while $cmd =~ /(\'[^\']+\'|\S+)/g;
        my $file = shift @arg;

        $xsl = get_stylesheet($file);
        $xml = $xsl->transform($xml, @arg);
    }
    return $xsl->output_string($xml);
}

sub init
{
    require XML::LibXML;
    require XML::LibXSLT;
    $Parser    ||= XML::LibXML->new  or die;
    $Processor ||= XML::LibXSLT->new or die;
}

sub get_stylesheet
{
    my $file  = shift;
    my $mtime = (stat $file)[9];
    
    $Cache{$file} and $Cache{$file}->[0] == $mtime
        and return $Cache{$file}->[1]; # hit

    my $style_doc  = $Parser->parse_file($file)
	or die "XML parse error: $file";
    my $stylesheet = $Processor->parse_stylesheet($style_doc)
	or die "XSL syntax error: $file";

    $Cache{$file} = [ $mtime, $stylesheet ];
    return $stylesheet;
}

1;
