#!/usr/bin/env perl

=head1 NAME

ct2

=head1 DESCRIPTION

Convert my modified version of markdown into various document formats

this will create a ~/.ct2 directory and add some files to it, such as your
basic config and the initial templates

=head1 AUTHOR

 kevin mulholland, moodfarm@cpan.org

=cut

use v5.10;
use strict;
use warnings;
use Data::Printer;
use POSIX qw(strftime);
use Try::Tiny;
use Path::Tiny;
use App::Basis;
use App::Basis::Config;
use App::Basis::ConvertText2;

# -----------------------------------------------------------------------------

my $MARKUP_DIR = "$ENV{HOME}/." . get_program();
$MARKUP_DIR = $ENV{MARKUP_DIR} if ( $ENV{MARKUP_DIR} );

my $CACHE_DIR = "/tmp/" . getpwuid($>) . "/cache";

my $TEMPLATE = <<EOD;
<!DOCTYPE html>
<html>
    <head>
        <title>%TITLE%</title>
        <meta name="Created" content="%DATE%" />
        <meta name="Author" content="%AUTHOR%" />
        <meta name="Copyright" content="%COPYRIGHT%" />
        <meta name="summary" content="%SUMMARY%" />
        <meta name="keywords" content="%KEYWORDS%" />
        <meta name="revision" content="%REVISION%" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

        <style type='text/css'>
            \@page { 
                size: %PAGE_SIZE% %ORIENTATION% ; 
                margin: 90pt 30pt 40pt 30pt ;
                \@top { 
                    margin: -10pt 0pt 0pt -90pt ;
                }
                \@bottom-right { content: counter(page) ;}
            }            }
            body {font-style: sans-serif;}
            /* toc */
            #toc { 
              padding: 0.4em;
              page-break-after: always;
            }
            #toc p {
                font-weight: bold;
                font-size: 32;
            }
            #toc h3 {
              text-align: center
            }
            #toc ul {
              columns: 1;
            }
            #toc ul, #toc li {
              list-style: none;
              margin: 0;
              padding: 0;
              padding-left: 10px ;
            }
            #toc a::after {
              content: leader('.') target-counter(attr(href), page);
              font-style: normal;
            }
            #toc a {
                text-decoration: none ;
                color: black;
            }

            /* tables*/
            table { page-break-inside: avoid ;}
            table.footer { font-size: 10px; width: 100%;}
            table.footer td.commercial { 
                font-weight: bold; 
                font-size: 12px;
                text-align: center;
            }
            /* nice markup for source code */
            table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
                margin: 0; padding: 0; vertical-align: baseline; border: none; 
            }
            table.sourceCode { width: 100%; line-height: 100%; }
            td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
            td.sourceCode { padding-left: 5px; }
            code > span.kw { color: #007020; font-weight: bold; }
            code > span.dt { color: #902000; }
            code > span.dv { color: #40a070; }
            code > span.bn { color: #40a070; }
            code > span.fl { color: #40a070; }
            code > span.ch { color: #4070a0; }
            code > span.st { color: #4070a0; }
            code > span.co { color: #60a0b0; font-style: italic; }
            code > span.ot { color: #007020; }
            code > span.al { color: #ff0000; font-weight: bold; }
            code > span.fu { color: #06287e; }
            code > span.er { color: #ff0000; font-weight: bold; }

        </style>
    </head>
    <body>
        <h1>%TITLE%</h1>
        <!-- uncomment this if you need a Table of Contents -->
        <!-- <div id='toc' >
            %TOC%
        </div> -->

        %_CONTENTS_%

        <table class='footer' width='100%'>
            <tr><td>(c) %COPYRIGHT%</td><td align='right'>%DATE%</td>
        </table>
    </body>
</html>
EOD

# -----------------------------------------------------------------------------

sub other_debug {
    my ( $state, $debug ) = @_;

    # return if ( $state ne 'DEBUG' );

    my $msg = $state;
    $msg .= " $debug" if ($debug);

    say STDERR localtime() . " " . get_program() . " $msg";
}

# -----------------------------------------------------------------------------

sub create_defaults {
    my ( $dir, $verbose ) = @_;
    my $default = "$dir/templates/default";
    my ( $r, $o, $e );

    die "dir option required" if ( !$dir );

    if ( !-d $default ) {

        # create the defaults if they do not exist
        try { path($default)->mkpath } catch {};
        msg_exit("Could not create default templates dir in $dir") if ( !-d $default );
    }

    # create HTML template
    path("$default/template.html")->spew_utf8($TEMPLATE) if ( !-f "$default/template.html" );

    my $config = App::Basis::Config->new( filename => "$default/config" );

    # if there is no data in the config then lets create some
    if ( !$config->has_data() ) {
        $config->set( '/page/size',        'A4' );
        $config->set( '/page/orientation', 'Portrait' );
        my $author = getpwuid($>);
        $config->set( '/author',    $author );
        $config->set( '/copyright', "Property of $author 2014" );
        $config->store();
    }
}

# -----------------------------------------------------------------------------

sub read_settings {
    my ( $template, $dir ) = @_;
    my %settings;

    die "dir option required" if ( !$dir );

    $template ||= 'default';
    $template =~ s/\v//g;
    my $templatedir = "$dir/templates/$template";
    if ( !-d $templatedir ) {
        debug( "INFO", "Template '$template' does not exist, using default" );
        $templatedir = "$dir/templates/default";
    }
    $settings{config} = App::Basis::Config->new( filename => "$templatedir/config" );

    $settings{template}     = $template;
    $settings{template_dir} = $templatedir;
    $settings{template}     = path("$templatedir/template.html")->slurp_utf8;

    return \%settings;
}

# -----------------------------------------------------------------------------
# main

my %opt = init_app(
    help_text => "Convert my modified markdown text files into other formats, by default will 
  create HTML in same directory as the input file, will only process .md files.
If there is no output option used the output will be to file of same name as input filename but
with an extension (if provided) from the document, use format: keyword (pdf html doc).",
    help_cmdline => "filename",
    options      => {
        'verbose|v'    => 'verbose mode',
        'clean|c'      => 'Clean up the cache before use',
        'template|s=s' => 'name of template to use',
        'embed|e'      => 'Embed images into HTML, do not use this if converting to doc/odt or pdf via libreoffice',
        'prince|p'     => 'Convert to PDF using prince rather than libreoffice, can handle embedded images',
        'output|o=s'   => {
            desc    => 'Filename to store the output as, extension will control conversion',
            default => "",
        }
    }
);

set_debug( \&other_debug ) if ( $opt{verbose} );

$opt{config_dir} ||= $MARKUP_DIR;
create_defaults( $opt{config_dir} );

$opt{filename} = $ARGV[0];
$opt{filename} =~ s/^~/$ENV{HOME}/ if ( $opt{filename} );

if ( $opt{filename} ne '-' && !( -f $opt{filename} && $opt{filename} =~ /\.md$/i ) ) {
    show_usage("filename must exist and be .md");
}

my $story;
if ( $opt{filename} eq '-' ) {
    $story = do { local $/; <STDIN> };
}
else {
    $story = path( $opt{filename} )->slurp_utf8;
}

show_usage("Bad markup file $opt{filename}") if ( !$story );

# anything in the replace hash will get replaced in the final document
my $replace = {

    # '%TITLE%'   => '',    # this comes from the first markdown level 1 header
    # '%DATE%' => strftime( "%Y-%m-%d", gmtime() ),    # :date in document overrides
    # '%COPYRIGHT%'   => $settings->{config}->get("copyright")        || '',    # :copyright in document overrides
    # '%AUTHOR%'      => $settings->{config}->get("author")           || '',    # :author in document overrides
    # '%PAGE_SIZE%'   => $settings->{config}->get("page/size")        || '',
    # '%ORIENTATION%' => $settings->{config}->get("page/orientation") || '',
    # '%KEYWORDS%' => '',   # get from document :keywords or :tags
    # '%SUMMARY%' => '',   # get from document :summary
    # '%REVISION%' => '',   # get from document :revision
};

# get any template from the stop of the story
my $settings;
my ($template) = ( $story =~ /^template:\s?(.*?)$/sm );

# document template overwritten by the command line option
$template = $opt{template} if ( $opt{template} );

$settings = read_settings( $template, $opt{config_dir} );

# add in template defaults if needed
$replace->{DATE} ||= strftime( "%Y-%m-%d", gmtime() );
$replace->{COPYRIGHT}   ||= $settings->{config}->get("copyright");
$replace->{AUTHOR}      ||= $settings->{config}->get("author");
$replace->{PAGE_SIZE}   ||= $settings->{config}->get("page/size");
$replace->{ORIENTATION} ||= $settings->{config}->get("page/orientation");

my $format = App::Basis::ConvertText2->new(
    name      => get_program(),
    use_cache => 1,
    cache_dir => $CACHE_DIR,
    template  => $settings->{template},
    replace   => $replace,
    verbose   => $opt{verbose},
    embed     => $opt{embed},
);
$format->clean_cache() if ( $opt{clean} );

my $data = $format->parse($story);

# decide on output filename from any format keyword
# all the keywords are in UPPER-CASE
my $keywords = $format->replace;
if ( !$opt{output} && $keywords->{FORMAT} ) {

    # same name as input
    $opt{output} = $opt{filename};

    # change extension
    $opt{output} =~ s/\.md$/.$keywords->{FORMAT}/i;
}

if ( $opt{output} ) {
    my $status = $format->save_to_file( $opt{output}, $opt{prince} );

    if ( $opt{verbose} && $status ) {
        say "Created $opt{output}";
    }
    elsif ( !$status ) {
        say "Failed to create $opt{output}";
    }
}
else {
    say STDERR "Ignoring $opt{filename}, could not determine a filename to output to, no :format option in file?" if ( $opt{verbose} );
}
