# -*- cperl -*-
# -----------------------------------------------------------------------------
# $Id: Index.pm,v 1.6 2004/12/11 05:41:54 admin Exp $
# -----------------------------------------------------------------------------
package Celaenito::Httpd::Index;
use strict;
use warnings;
use HTTP::Status;
use POE::Kernel;
use Celaenito::Config;
use Celaenito::HyperEstraier;
use Celaenito::Template;
use Celaenito::StaticFile;
use Celaenito::Permission;
use Celaenito::DB;
use Celaenito::Curi;
use Celaenito::FileStorage;
use Celaenito::Httpd;
use Kibibyte qw(kibibyte_format);
use Pager;
use URI::QueryParam;
use SQLTime;

sub handler {
    my ($req, $resp) = @_;

    not CAN_SEE($req) and
      return need_auth_handler(@_);
    
    if ($req->uri->path eq '/') {
	return index_handler(@_);
    }
    elsif ($req->uri->path eq '/-/queue') {
	return queue_handler(@_);
    }
    elsif ($req->uri->path eq '/-/log') {
	return log_handler(@_);
    }
    else {
	return notfound_handler(@_);
    }
}

sub split_interval ($) {
    my $sec = $_[0] * 60;
    
    my $day = int($sec / 60 / 60 / 24);
    $sec -= $day * 24 * 60 * 60;

    my $hour = int($sec / 60 / 60);
    $sec -= $hour * 60 * 60;

    my $min = int($sec / 60);
    $sec -= $min * 60;

    ($day, $hour, $min, $sec);
}

sub index_handler {
    my ($req, $resp) = @_;
    my $t = {};

    $t->{estraier} = defined EST;

    if (LOGINNED_P($req)) {
	$t->{user} = {
	    name       => LOGIN_USERNAME($req),
	    can_config => CAN_CONFIG($req),
	    can_add    => CAN_ADD($req),
	};
    }

    $t->{login_failure} = $req->uri->query_param('login_failure');

    foreach ([version => 'latest'], ['query' => 'http://']) {
	$req->uri->query_param($_->[0]) or
	  $req->uri->query_param($_->[0] => $_->[1]);
    }
    $t->{query} = $req->uri->query_form_hash;

    my @agents = $poe_kernel->call(
	jobqueue => 'get_agents');
    $t->{dlfiles} = [];
    foreach my $agent (@agents) {
	defined $agent->urlid or next;
	    
	my $ent = {};
	push @{$t->{dlfiles}}, $ent;
	    
	my $info = DB->selectrow_hashref(
	    q{SELECT * FROM target_url WHERE urlid = ?}, undef, $agent->urlid);
	my $options = eval ($info->{options} || '{}');

	if (my $interval = $options->{auto_update_interval}) {
	    $ent->{ao_interval} = $interval;
	    ($ent->{ao_day}, $ent->{ao_hour}, $ent->{ao_min})
	      = split_interval($interval);
	}

	$ent->{progress}    = defined $agent->progress ?
	  sprintf('%.2f%%', $agent->progress) : '-';
	$ent->{size}        = defined $agent->size ?
	  Kibibyte::format($agent->size, '%.2f %s') : '-';
	$ent->{priority}    = $info->{priority};
	$ent->{recursive}   = $options->{recursive_fetch};
	$ent->{auto_update} = $options->{auto_update_interval};
	$ent->{urlid}       = $info->{urlid};
	$ent->{url}         = $info->{url};
	$ent->{label}       = $info->{label} || '';
    }

    $t->{queue} = expand_queued_files($req);
    $t->{log} = expand_recent_logs($req);

    $t->{title} = config('ui.title');
	
    # FIXME: 統計はキャッシュに保存
    my $stat = $t->{stat} = {};
    $stat->{total_files}  = FS->total_files;
    $stat->{total_size}   = kibibyte_format('%.2f %s', FS->total_size);
    $stat->{total_urls}   = do {
	($_) = DB->selectrow_array(q{SELECT COUNT(*) FROM target_url});
	$_;
    };
    $stat->{num_agents}   = do {
	$poe_kernel->call(jobqueue => 'count_agents');
    };
    $stat->{queued_files} = do {
	($_) = DB->selectrow_array(
	    q{SELECT COUNT(*) FROM job_queue WHERE status = "wait"});
	$_;
    };
    $stat->{postponed_files} = do {
	($_) = DB->selectrow_array(
	    q{SELECT COUNT(*) FROM job_queue
               WHERE status = "wait" AND begin_time <= NOW()});
	$_;
    };
    if (EST) {
	$stat->{est_urls} = EST->doc_num;
	$stat->{est_words} = EST->word_num;
	$stat->{est_size} = kibibyte_format('%.2f %s', EST->size);
    }

    my $out;
    TMPL->process('index.tt', $t, \$out)
      or die Template->error;
    
    $resp->content($out);
    return RC_OK;
}

sub queue_handler {
    my ($req, $resp) = @_;
    my $t = {};

    $t->{title} = config('ui.title');
    $t->{queue} = expand_queued_files($req);
    
    my $out;
    TMPL->process('queue_envelope.tt', $t, \$out)
      or die Template->error;
    
    $resp->content($out);
    return RC_OK;
}

sub expand_queued_files {
    my ($req) = @_;
    my $uri = $req->uri;
    
    my $ret = {
	pager   => undef,
	entries => [],
    };

    my $pager = Pager->new(
	fetch => {
	    sql => q{
		SELECT *
		  FROM job_queue
		  LEFT JOIN target_url USING (urlid)
		 WHERE status = "wait"
		 ORDER BY begin_time ASC
		},
	    dbh => DB,
	},
	page_to_show   => scalar($uri->query_param('page')) || 1,
	pagenums_limit => 10,
	items_per_page => scalar($uri->query_param('limit')) || 10,
	show_meta => sub {
	    my %meta = @_;
	    $ret->{pager} = {
		page      => $meta{page},
		last_page => $meta{last_page},
		pages     => [$meta{pagelink_begin} .. $meta{pagelink_end}],
	    };
	},
	show_content => sub {
	    my $row = shift;
	    my $options = eval ($row->{options} || '{}');

	    my $ent = {};
	    push @{$ret->{entries}}, $ent;

	    if (my $interval = $options->{auto_update_interval}) {
		$ent->{ao_interval} = $interval;
		($ent->{ao_day}, $ent->{ao_hour}, $ent->{ao_min})
		  = split_interval($interval);
	    }
	    
	    $ent->{day}         = do {
		my (undef, undef, undef, $mday, $mon, $year) =
		  localtime(sqlparsetime($row->{begin_time}));
		sprintf '%04d-%02d-%02d', $year + 1900, $mon + 1, $mday;
	    };
	    $ent->{time}        = do {
		my ($sec, $min, $hour) =
		  localtime(sqlparsetime($row->{begin_time}));
		sprintf '%02d:%02d:%02d', $hour, $min, $sec;
	    };
	    $ent->{priority}    = $row->{priority};
	    $ent->{recursive}   = $options->{recursive_fetch};
	    $ent->{auto_update} = $options->{auto_update_interval};
	    $ent->{urlid}       = $row->{urlid};
	    $ent->{url}         = $row->{url};
	    $ent->{label}       = $row->{label} || '';
	},
       );
    $pager->execute;

    $ret;
}

sub log_handler {
    my ($req, $resp) = @_;
    my $t = {};

    $t->{title} = config('ui.title');
    $t->{log} = expand_recent_logs($req);
    
    my $out;
    TMPL->process('log_envelope.tt', $t, \$out)
      or die Template->error;
    
    $resp->content($out);
    return RC_OK;
}

sub expand_recent_logs {
    my ($req) = @_;
    my $uri = $req->uri;
    my $urlid = $uri->query_param('urlid'); # optional
    
    my $ret = {
	urlid   => $urlid,
	pager   => undef,
	entries => [],
    };

    my @where;
    if ($urlid) {
	push @where, 'urlid = '.DB->quote($urlid);
    }
    my $where = @where ? 'WHERE '.join(' AND ', @where) : '';

    my $pager = Pager->new(
	fetch => {
	    sql => qq{
		SELECT *
		  FROM job_log
                $where
		 ORDER BY exec_time DESC
		},
	    dbh => DB,
	},
	page_to_show   => scalar($uri->query_param('page')) || 1,
	pagenums_limit => 10,
	items_per_page => scalar($uri->query_param('limit')) || 10,
	show_meta => sub {
	    my %meta = @_;
	    $ret->{pager} = {
		page      => $meta{page},
		last_page => $meta{last_page},
		pages     => [$meta{pagelink_begin} .. $meta{pagelink_end}],
	    };
	},
	show_content => sub {
	    my $row = shift;

	    my $ent = {};
	    push @{$ret->{entries}}, $ent;

	    my ($exists) = DB->selectrow_array(
		q{SELECT COUNT(*) FROM target_url WHERE urlid = ?},
		undef, $row->{urlid});
	    if ($exists) {
		$ent->{urlid} = $row->{urlid};
	    }

	    $ent->{day}     = do {
		my (undef, undef, undef, $mday, $mon, $year) =
		  localtime(sqlparsetime($row->{exec_time}));
		sprintf '%04d-%02d-%02d', $year + 1900, $mon + 1, $mday;
	    };
	    $ent->{time}    = do {
		my ($sec, $min, $hour) =
		  localtime(sqlparsetime($row->{exec_time}));
		sprintf '%02d:%02d:%02d', $hour, $min, $sec;
	    };
	    $ent->{message} = $row->{message};
	    $ent->{urlid}   = $row->{urlid} || '';
	    $ent->{url}     = $row->{url} || '';
	},
       );
    $pager->execute;

    $ret;
}

sub query_handler {
    my ($req, $resp) = @_;

    my $query = $req->uri->query_param('query');
    if (!$query) {
	return notfound_handler(@_);
    }
    
    my $uri = URI->new($query);
    if (!$uri->scheme or !$uri->host) {
	return notfound_handler(@_);
    }

    my $version = $req->uri->query_param('version');
    my $redirect = celaenito_uri(
	host_uri => $req->uri,
	orig_uri => $uri,
	time     => $version,
       );
    
    $resp->header(Location => $redirect->as_string);
    return RC_SEE_OTHER;
}

1;
