package DTA::Controller::Root;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller' }

use Cache::FileCache;
use CGI qw(escapeHTML);
use DateTime;
use JSON qw( to_json );
use List::Util 'shuffle';
use POSIX qw(strftime);
use URI::Find;
use YAML qw(LoadFile);

# Sets the actions in this controller to be registered with no prefix
# so they function identically to actions created in MyApp.pm
__PACKAGE__->config(namespace => '');

=head1 NAME

DTA::Controller::Root - Root Controller for DTAQ

=head1 DESCRIPTION

=head1 METHODS

=head2 auto

=cut

sub auto : Private {
    my ( $self, $c ) = @_;
    $c->languages( ['de'] );

=for pod
    $c->stash(
        template => 'http/construction.tt',
    );
    $c->res->content_type( 'text/html' );
    $c->forward( $c->view('Plain') );
    $c->detach;
=cut

    my $xmlrep = $c->config->{xmlrep};

    # last read page
    # if ( $c->user ) {
    #     # skip if this is an AJAX request
    #     no warnings 'uninitialized';
    #     if ( $c->req->headers->header('x-requested-with') ne 'XMLHttpRequest' ) {
    #         $c->stash->{last_rv} = $c->model('DTADB::Review')->search(
    #             { account => $c->user->id },
    #             { order_by => 'time desc' },
    #         )->first,
    #     }
    # }

    $c->stash(
        # accounts => [ $c->model('DTADB::Account')->search( undef, { order_by => 'username' } )->all ],
        book_date => sub {
            my ( $item, $ts ) = @_;
            if ( $ts ) {
                 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime +(stat( sprintf "%s/%s.xml", $xmlrep, $item ))[9];
                return sprintf "%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec;
            }
            else {
                return POSIX::strftime( '%Y-%m-%d %H:%M:%S', localtime +(stat( sprintf "%s/%s.xml", $xmlrep, $item ))[9] );
            }
        },
        dta_comment => sub {
            my $text = shift;
            my $shorten = sub {
                my $str = shift;
                $str =~ s/^(.{30}).*/$1.../;
                return $str;
            };
            my $finder = URI::Find->new(sub {
                my ( $uri, $orig_uri ) = @_;
                return sprintf '<a href="%s">%s</a>', $uri, $shorten->( $orig_uri );
            });
            $finder->find(\$text, \&escapeHTML);
            return $text;
        },
        img => sub {
            my ( $item, $page ) = @_;
            my ($dir) = $item =~ /(\w+_\w+_\w+)/;
            return sprintf 'https://media.dwds.de/dta/images/%s/%s_%04d_80.jpg', $dir, $dir, $page;
        },
        tz => sub {
            my $dt = shift;
            return unless $dt;
            my $ret = $dt->set_time_zone('UTC')
                         ->set_time_zone('Europe/Berlin')."";
            $ret =~ s/T(0[0-6]|2[0-3])/TXX/;
            $ret =~ s/:\d\d$//;
            return $ret;
        },
        has_ddc => sub {
            # is called from templates to ensure that the given book exists in DDC
            # everyone outside DTA has to take care of setting up DDC
            # return 0 unless $c->config->{feature}->{ddc}->{enabled};
            my $dirname = shift;
            return unless $dirname;
            my $configs = File::Spec->catfile( $c->config->{ddc}->{config}, '*.con' );
            return unless $configs;
            #???
            qx(grep \Q$dirname\E $configs);
            # Exit status is 0 if match, 1 if no match and 2 for error
            return $? == 0 ? 1 : 0;
        },
        has_normxml => sub {
            my $dirname = shift;
            return -e sprintf '/home/ddc-dstar/dstar/corpora/dta/extra/xml_splice/%s.TEI-P5.spliced.xml', $dirname;
        },
        is_toxic => sub {
            my $dirname = shift;
            foreach my $subcorpus ( qw(dtae dtak) ) {
                open( my $fh, '<', sprintf('%s/bad.files', $c->config->{"dstar_".$subcorpus."_extra"}) ) or die $!;
                while ( my $line = <$fh> ) {
                    chomp $line;
                    next if $line =~ /^#/;
                    next if $line =~ /^$/;
                    no warnings;
                    return 1 if $dirname =~ qr/$line/;
                }
            }
            return 0;
        },
        has_tcf => sub {
            my $dirname = shift;
            return -e "/home/wiegand/dta-tcf-simple/$dirname.tcf.xml";
        },
        has_tcf_simple => sub {
            my $dirname = shift;
            return -e "/home/wiegand/dta-tcf-simple/$dirname.tcf.xml";
        },
        has_tcf_full => sub {
            my $dirname = shift;
            if ( -e sprintf("%s/xml_tcf/%s.TEI-P5.tcf.xml", $c->config->{dstar_dtae_extra}, $dirname) ) {
                return 1;
            }
            elsif ( -e sprintf("%s/xml_tcf/%s.TEI-P5.tcf.xml", $c->config->{dstar_dtak_extra}, $dirname) ) {
                return 1;
            }
            return;
        },
        has_lingxml => sub {
            my $dirname = shift;
            if ( -e sprintf("%s/xml_ling/%s.TEI-P5.ling.xml", $c->config->{dstar_dtae_extra}, $dirname) ) {
                return 1;
            }
            elsif ( -e sprintf("%s/xml_ling/%s.TEI-P5.ling.xml", $c->config->{dstar_dtak_extra}, $dirname) ) {
                return 1;
            }
            return;
        },
        recent => sub {
            open( my $fh, '<', $c->path_to('recent.yml')."" ) or die $!;
            my @ret;
            while( <$fh> ) {
                chomp;
                next if /^[#-]/;
                my ( $id, $date ) = split /\s*:\s*/;
                push @ret, [ $id, $date ];
            }
            return \@ret;
        },
        now => DateTime->now,
        'quotemeta' => sub { my $str = shift || ''; return quotemeta $str },
        bookinfo => sub {
            my $id = shift;
            my $book = $c->model('DTADB::Book')->search(
                {
                    'me.id_book' => $id,
                },
                {
                    cache    => 1,
                },
            )->first;
            return $book;
        },
        hab_link => sub {
            my $sig = shift;
            for ( $sig ) {
                # XXX
            }
            my $link = sprintf 'http://diglib.hab.de/drucke/%s/start.htm', $sig;
            return undef;
            return $link;
        }
    );

    # this needs &{ $c->stash->{recent} }
    # $c->stash->{in_dta_since} = sub {
    #     my $id = shift;
    #     my $recent = $c->stash->{recent}->();
    #     foreach my $entry ( @$recent ) {
    #         return $entry->[1] if $entry->[0] eq $id;
    #     }
    #     return;
    # };

    $c->stash(
        view => 'Web',
        content_class => 'web',
    );

    if ( ref $c->req->arguments eq 'ARRAY' and $c->req->arguments->[0] and $c->req->arguments->[0] eq 'news' and $c->req->arguments->[1] =~ /^(\d+)/ ) {
        $c->detach( "/news/entry" );
    }

    return 1;
}

=head2 index

=cut

sub index :Path :Args(0) {
    my ( $self, $c ) = @_;

    $c->forward('/suggest');
    $c->forward('dtastat');
    $c->forward('recent', [6]);

    $c->forward( 'random_snippets_metadata' );
    $c->forward( 'random_snippets_ddc' );

    $c->stash(
        template => 'web/index.tt',
        news => [ $c->model('DTADB::News')->search(
            {
                frontpage => 1,
            },
            {
                order_by => 'created DESC',
            },
        )->all ],
        startpage => 1,
    );
}

=head2 random_snippts_metadata

=cut

sub random_snippets_metadata :Private {
    my ( $self, $c ) = @_;
    open( my $fh, '<:utf8', $c->path_to('root/static/search_random/random-metadata.txt') ) or return [];
    my $content;
    {
        local $/;
        $content = <$fh>;
    }
    close $fh;

    my @list = ();
    my @entries = split /\n *\n/, $content;
    foreach my $entry ( @entries ) {
        my ( $ddc, $desc ) = split /\n/, $entry;
        push @list, [ $ddc, $desc ];
    }
    $c->stash->{random_snippets_metadata} = to_json( \@list );
}

=head2 random_snippets_ddc

=cut

sub random_snippets_ddc :Private {
    my ( $self, $c ) = @_;
    open( my $fh, '<', $c->path_to('root/static/search_random/random-ddc.txt')."" )or return [];
    my $content;
    {
        local $/;
        $content = <$fh>;
    }
    close $fh;

    my @list = ();
    my @entries = split /\n *\n/, $content;
    foreach my $entry ( @entries ) {
        my ( $url, $desc ) = split /\n/, $entry;
        push @list, [ $url, $desc ];
    }
    $c->stash->{random_snippets_ddc} = to_json( \@list );
}

=head2 recent

=cut
sub recent :Private {
    my ( $self, $c, $rows ) = @_;


    my @latest_books = ();
    my $rs = $c->model('DTADB::Book')->search({
        'me.ready' => { 'in' => [ 1, 2 ] },
    },{
        rows      => $rows || 50,
        prefetch  => qw/ source /,
        cache_for => 600,
        order_by  => [
            {'-desc' => 'date_ingest'},
            {'-asc' => 'me.id_book'}
        ],
    }
    );

    $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');

    while (my $hashref = $rs->next) {
        push @latest_books, $hashref;
    }
    $c->stash(
        web_recent => \@latest_books
    );
}

=head2 recent

deprecate and slow

sub recent :Private {
    my ( $self, $c ) = @_;

    my $cache = Cache::FileCache->new({
        cache_root         => $c->path_to( 'var', 'cache' )."",
        namespace          => 'web',
        default_expires_in => 60 * 60 * 24, # 1 day
    });

    my $web_recent = $cache->get( 'recent_books' );
    if ( !defined $web_recent || $c->req->params->{regen} ) {
        my $recent = $c->stash->{recent}->();
        my $web_recent = [];
        foreach my $entry ( @$recent ) {
            my $book = $c->model('DTADB::Book')->search(
                {
                    'me.id_book' => $entry->[0],
                },
                {
                },
            )->first;
            next unless $book;
            next if $book->ready !~ /^[12]$/;

            my ( $year, $month, $day ) = $entry->[1] =~ /([0-9]{4})-([0-9]{2})-([0-9]{2})/;
            my $dt = DateTime->new( year => $year, month => $month, day => $day, time_zone => 'Europe/Berlin' );
            $book->{__dtaq_date} = $dt;
            push @$web_recent, $book;
        }
        $cache->set( 'recent_books', $web_recent );
    }
    $c->stash( web_recent => $web_recent );
}
=cut

=head2 suggest

=cut

sub suggest :Private {
    my ( $self, $c ) = @_;

    my $dt = $c->stash->{now};
    my $day = $dt->strftime('%Y-%m-%d');

    my ( $day_only ) = $day =~ /-(\d+-\d+)$/;
    my $res = $c->model('DTADB::Event')->search(
        {
            -or => [
                -and => [
                    day    => $day,
                    repeat => 0,
                    draft  => 0,
                ],
                -and => [
                    day    => { -like => "%-$day_only" },
                    repeat => 1,
                    draft  => 0,
                ]
            ],
        },{
            prefetch => [ qw/ event_books event_images / ],
        }
    );
    $c->stash(
        events => [ $res->all ],
    );
}

=head2 dtastat

=cut

sub dtastat :Private {
    my ( $self, $c ) = @_;

    my $cache = Cache::FileCache->new({
        cache_root         => $c->path_to( 'var', 'cache' )."",
        namespace          => 'web',
        default_expires_in => 60 * 60 * 24, # 1 day
    });
    my $dtastat = $cache->get( 'dtastat' );

    if ( !defined $dtastat || $c->req->params->{regen} ) {
        my $books = $c->model('DTADB::Book')->search(
            {
                'me.ready' => { -in => [1, 2] },
            },
            {
                join => 'source',
            },
        );

        my $pages = $books->search(undef, { join => 'textpages' })->count;
        my $chars = $books->search(undef, {
            select => [ { sum => 'textpages.chars' } ],
            as     => [ 'chars' ],
            join   => 'textpages',
        })->single->get_column('chars');

        my $token;
        my @filenames = map { $_->dirname } $books->search()->all;
        while ( my @slice = splice @filenames, 0, 50 ) {
            my $filenames = join ',' => @slice;
            $filenames = '{' . $filenames . '}' if $filenames =~ /,/;
            $token += scalar `egrep -h '<measure type="tokens">[0-9]+' /home/wiegand/dta-fullxml-without-c/$filenames* | perl -ne '/>(\\d+)/ && (\$s+=\$1);END{print \$s}'`;
        }

        my $dtaq_books = $c->model('DTADB::Book')->search(
            {
                -and => [
                    'me.dirname'  => { '!=' => '' },
                    'me.dirname'  => { '!=' => undef },
                    'source.source'      => { '!=' => undef },
                ],
            },
            {
                prefetch    => [ 'source' ],
                join        => [ 'source' ],
            },
        )->count;

        $dtastat = {
            books => $books->count,
            pages => $pages,
            token => $token,
            chars => $chars,
            dtaq_books => $dtaq_books,
        };
        $cache->set( 'dtastat', $dtastat );
    }

    $c->stash( dtastat => $dtastat );
}

=head2 doku

=cut

sub doku :Local {
    my ( $self, $c, $topic ) = @_;
    $c->stash->{ content_class } = 'help-content';
    $c->forward("/help/doc", [$topic]);
}

=head2 set_pref

=cut

sub set_pref :Local {
    my ( $self, $c ) = @_;

    my $field = $c->req->params->{field};
    my $value = $c->req->params->{value};
    return unless $field;

    $c->session->{ $field } = $value;
    $c->res->body( ' ' );
}

=head2 get_pref

=cut

sub get_pref :Local {
    my ( $self, $c ) = @_;

    my $field = $c->req->params->{field};

    if ( exists $c->session->{$field} ) {
        my $ret = $c->session->{$field} || '';
        $c->res->body( $ret );
    }
}

=head2 clarin_kupro

=cut

sub clarin_kupro :Local {
    my ( $self, $c ) = @_;
    $c->res->redirect( $c->uri_for( '/doku/clarin_kupro_index' ) );
}

=head2 wm2014

=cut

sub wm2014 :Local {
    my ( $self, $c ) = @_;

    my @titles = qw(koch_kunstausdruecke_1903 koch_fussballspiel1900_1901 koch_fussballspiel1899_1900 koch_deutschespiele_1894 );
    my @books = $c->model('DTADB::Book')->search(
        {
            'me.dirname' => { -in => \@titles },
        },
        {
        },
    )->all;

    $c->stash(
        books    => \@books,
        template => 'wm2014.tt',
    );
}

=head2 temporary_not_available

=cut

sub temporary_not_available :Private {
    my ( $self, $c ) = @_;
    $c->res->status( 503 );
    $c->res->content_type( 'text/plain' );
    $c->res->body( 'Leider konnte der angeforderte Dienst nicht geladen werden. Bitte versuchen Sie es erneut. Bei anhaltenden Problemen kontaktieren Sie uns bitte unter <redaktion@deutschestextarchiv.de>.' );
}

=head2 default

Standard 404 error page

=cut

sub default :Path {
    my ( $self, $c ) = @_;
    if ( $c->req->action eq '/' ) {
        $c->detach( 'index' );
    }
    $c->response->body( 'Page not found.' );
    $c->response->status(404);
}

=head2 end

=cut

sub end : Private {
    my ( $self, $c ) = @_;
    return 1 if $c->response->status =~ /^(?:3\d\d)|(?:204)$/;
    return 1 if $c->response->body || $c->stash->{_output};

    if ( !defined $c->res->output || ( !$c->res->output && $c->res->output ne '0' && $c->res->output ne '' ) ) {
        my $view = $c->stash->{view} || 'HTML';
        $c->forward( $c->view($view) );
        if ( $c->stash->{form} ) {
            eval { $c->fillform( $c->stash->{form} ); 1 };
        }
        else {
            eval {
                $c->fillform( $c->req->parameters, {
                    fill_password => 0,
                    ignore_fields => [ 'mode' ],
                });
                1;
            };
        }
    }

    # custom 500 page
    if ( my @errors = @{$c->error} ) {
        foreach my $error (@errors) {
            $c->log->error( $error );
        }
        $c->clear_errors;

        my $template = 'http/500.tt';

        $c->stash(
            template => $template,
            errors   => \@errors,
        );
        $c->response->status(500);
        $c->res->content_type( 'text/html' );
        $c->forward( $c->view('Plain') );
    }
}


=head2 error_404

custom 404 error page

=cut

sub error_404 :Private {
    my ( $self, $c ) = @_;
    $c->stash(
        title       => 'Seite nicht gefunden',
        template    => 'common/err_404.tt',
    );
    $c->response->status(404);
    $c->detach();
}


__PACKAGE__->meta->make_immutable;

1;
__END__

=head1 AUTHOR

Frank Wiegand

=head1 LICENSE

This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
