/usr/local/CPAN/Doc-Simply/Doc/Simply/Render/HTML.pm


package Doc::Simply::Render::HTML;

use Any::Moose;
use Doc::Simply::Carp;

use Doc::Simply::Render::HTML::TT;

use Text::MultiMarkdown qw/markdown/;
use Template;
use HTML::Declare qw/LINK SCRIPT STYLE/;

use constant YUI_reset_fonts_grids_base => "http://yui.yahooapis.com/combo?2.8.1/build/reset-fonts-grids/reset-fonts-grids.css&2.8.1/build/base/base-min.css";
use constant YUI_reset => "http://yui.yahooapis.com/combo?2.8.1/build/reset/reset-min.css";


has tt => qw/is ro lazy_build 1 isa Template/;
sub _build_tt {
    my $self = shift;
    my $method = "build_tt";
    croak "Don't have method \"$method\"" unless my $build = $self->can($method);
    my $got = $build->($self, @_);

    return $got if blessed $got && $got->isa("Template");
    return Template->new($got) if ref $got eq "HASH";
    return Template->new unless $got;

    croak "Don't know how to build Template with $got";
}

sub build_tt {
    return {
        Doc::Simply::Render::HTML::TT->build,
    };
}

sub process_tt {
    my $self = shift;
    my %given = @_;

    my ($input, $output, $context, @process);

    {
        $input = $given{input};
        croak "Wasn't given input" unless defined $input;
    }

    {
        $output = $given{output};
        my $output_content;
        $output = \$output_content unless exists $given{output};

        if (blessed $output) {
            if ($output->isa("Path::Resource")) {
                $output = $output->file;
            }
            if ($output->isa("Path::Class::File")) {
                $output = "$output";
            }
        }

        if (defined $output && ! ref $output) {
            $output = Path::Class::File->new($output);
            $output->parent->mkpath unless -d $output->parent;
            $output = "$output";
        }
    }

    {
        $context = $given{context} || {};
    }

    if ($given{process}) {
        @process = @{ $given{process} };
    }
    else {
        @process = qw/binmode :utf8/;
    }

    my $tt = $self->tt;
    $tt->process($input, $context, $output, @process) or croak "Couldn't process $input => $output: ", $tt->error;

    return $$output unless exists $given{output};

    return $output if ref $output eq "SCALAR";
}

sub css_render {
    my $self = shift;
    my $given = shift;

    croak "Don't understand $given" unless ref $given eq "HASH";

    my $value;
    if ($value = $given->{link}) {
        return LINK { rel => 'stylesheet', type => 'text/css', href => $value };
    }
    elsif ($value = $given->{content}) {
        $value = $$value if ref $value eq "SCALAR";
        return STYLE { type => 'text/css', _ => $value };
    }
    else {
        croak "Don't understand \"@{[ %$given ]}\"";
    }
}

sub js_render {
    my $self = shift;
    my $given = shift;

    croak "Don't understand $given" unless ref $given eq "HASH";

    my $value;
    if ($value = $given->{link}) {
        return SCRIPT { type => 'text/jascript', src => $value, content => [] };
    }
    else {
        croak "Don't understand \"@{[ %$given ]}\"";
    }
}

sub render {
    my $self = shift;
    my %given = @_;

    my $document = $given{document} or croak "Wasn't given document to format";
    my $root = $document->root;

    my ($content, @css, @js);

    my @index;

    {
        my %state;
        $content = "";
        $root->walk_down({ callback => sub {
            my $node = shift;
            my $_content = $node->content;
            if ($node->tag =~ m/^head\d+$/) {
                push @index, $node;
                if ($_content =~ m/^\s*NAME\s*$/ && ! $state{got_name}) {
                    # TODO Move this into the parser
                    $state{saw_name} = 1;
                }
                $_content = join '', "<a name=\"$_content\"></a>", $_content;
            }
            else {
                if ($state{saw_name} && $_content =~ m/\S/) {
                    delete $state{saw_name};
                    my ($title, $name, $subtitle) = ($_content);
                    chomp $title;
                    $title =~ m/^\s*([^-]+)?(?:\s*-\s+(.*))?$/;
                    $name = $1;
                    $subtitle = $2;
                    @{ $document->appendix }{qw/name title subtitle/} = ($name, $title, $subtitle);
                    $state{got_name} = 1;

                }
            }
            $content .= $self->_format_tag($node->tag, $_content);
            return 1;
        } });
        $content = markdown $content, { heading_ids => 0 };
    }

    my $style = lc ($given{style} || "standard");

    if ($style eq "standard") {
        push @css, $self->css_render({ link => YUI_reset_fonts_grids_base });
        push @css, $self->css_render({ content => Doc::Simply::Render::HTML::TT->css_standard });
    }
    elsif ($style eq "base") {
        push @css, $self->css_render({ link => YUI_reset_fonts_grids_base });
    }
    elsif ($style eq "reset") {
        push @css, $self->css_render({ link => YUI_reset });
    }
    else {
        croak "Don't understand style \"$style\"";
    }

    {
        my $css = $given{css} || [];
        for (@$css) {
            push @css, $self->css_render($_);
        }
    }

    {
        my $css = $given{js} || [];
        for (@$css) {
            push @css, $self->js_render($_);
        }
    }

    $self->process_tt( input => "document", context => { index => \@index, document => $document, content => $content, css => \@css, js => \@js } );
}

sub _format_tag {
    my $self = shift;
    my $tag = shift;
    my $content = shift;

    if ($tag =~ m/^head(\d)/) {
        return "<h$1 class=\"content-head$1 content-head\">$content</h$1>\n";
    }

    return $content;
}

#my $content = $document->content_from;
#warn markdown $content;

1;