#!/usr/bin/perl
# -*- Coding: utf-8 -*-
#
#      ::: RssC ::: RSS Concoction :::
#
# 使ひ方:
#
#       rc.cgi/rss/http://www.example.org/
#     (Last-Modified, If-Modified-Since對應)
#
#
package rssc_cgi;
use strict;
use warnings;
use lib '.';
use URI;
use URI::QueryParam;
use RssC::Checker;
use RssC::Formatter;
use RssC::DB;
use HTTP::Date;
use Template;
our $VERSION = '1.0';

eval q{
    use CGI::Fast;
};
if ($@) {
    # FastCGI is not available
    eval q{
        use CGI;
    };
    if ($@) {
        die "Neither CGI nor CGI::Fast are available";
    }
    else {
        cgi_main(CGI->new);
    }
}
else {
    while (my $q = CGI::Fast->new) {
        $q or exit 0;
	
        cgi_main($q);

        eval {
            DB->do(q{ROLLBACK});
        };
    }
}

sub cgi_main {
    my $q = shift;
    eval {
        if ($q->path_info) {
            disp_rss($q);
        }
        else {
            my $cmd = $q->param('cmd');
            if (!$cmd) {
                disp_index($q);
            }
            elsif ($cmd eq 'rss') {
                disp_rss_url($q);
            }
            elsif ($cmd eq 'set') {
                do_set_title($q);
            }
            elsif ($cmd eq 'del') {
                do_delete_title($q);
            }
            else {
                die "Invalid command: $cmd\n";
            }
        }
    };
    if (my $err = $@) {
        print $q->header(
            -status => '500 Internal Server Error',
            -type   => 'text/plain');
        print "Error: $err";
    }
}

sub disp_rss {
    my $q = shift;

    my $qstr = $ENV{QUERY_STRING};
    my $uri = URI->new(
        substr($q->path_info, 1) . (length $qstr ? '?'.$qstr : ''));
    $uri->fragment(undef);
    $uri = $uri->canonical;
    my ($lastmod, $title) = RssC::Checker->check($uri);
    
    if (defined($_ = $q->http('If-Modified-Since'))) {
        my $ifmod = str2time($_);
        if ($ifmod >= $lastmod) {
            print $q->header(
                -status => '304 Not Modified',
                -Last_Modified => time2str($lastmod));
            return;
        }
    }

    # user_titleを見る
    my ($user_title) = DB->selectrow_array(q{
        SELECT user_title
          FROM user_title
          LEFT JOIN uri USING (uri_id)
         WHERE uri = ?
    }, undef, $uri->as_string);
    
    $user_title and
      $title = $user_title;
    
    my $fm = RssC::Formatter->new(
        $uri, $lastmod, $title);
    print $q->header(
        -type => 'application/rss+xml; charset=UTF-8',
        -Last_Modified => time2str($lastmod));
    print $fm->format;
}

sub disp_index {
    my $q = shift;
    my $t = Template->new(
        -fpath => 'tmpl/index.html');

    my $uri_id;
    if ($uri_id = $q->param('edit')) {
        my $row = DB->selectrow_hashref(q{
            SELECT uri.uri_id AS uri_id,
                   uri,
                   title,
                   user_title
              FROM uri
              LEFT JOIN title ON (uri.uri_id = title.uri_id)
              LEFT JOIN user_title ON (uri.uri_id = user_title.uri_id)
             WHERE uri.uri_id = ?
        }, undef, $uri_id);
	
        if (not $row) {
            die "No such id: $uri_id\n";
        }
	
        $t->form_edit->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(cmd => 'set');
                $uri->query_param(uri_id => $row->{uri_id});
                $uri;
            });
        $t->form_edit->set_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(title => $row->{user_title});
                $uri;
            });
        $t->form_edit->add(
            uri => $row->{uri},
            original_title => $row->{title} || '',
           );
    }
    elsif ($uri_id = $q->param('del')) {
        my $row = DB->selectrow_hashref(q{
            SELECT uri.uri_id AS uri_id,
                   uri,
                   title,
                   user_title
              FROM uri
              LEFT JOIN title ON (uri.uri_id = title.uri_id)
              LEFT JOIN user_title ON (uri.uri_id = user_title.uri_id)
             WHERE uri.uri_id = ?
        }, undef, $uri_id);
	
        if (not $row) {
            die "No such id: $uri_id\n";
        }

        $t->form_del->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(cmd => 'del');
                $uri->query_param(uri_id => $row->{uri_id});
                $uri;
            });
        $t->form_del->add(
            uri => $row->{uri},
            title => $row->{user_title},
            original_title => $row->{title} || '',
           );
    }
    else {
        $t->form_url->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(cmd => 'rss');
                $uri;
            });
        $t->form_url->add;
	
        $t->form_add->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(cmd => 'set');
                $uri;
            });
        $t->form_add->add;
    }

    my $sth = DB->prepare(q{
        SELECT uri.uri_id AS uri_id,
               uri,
               title,
               user_title
          FROM uri
          LEFT JOIN title ON (uri.uri_id = title.uri_id)
          LEFT JOIN user_title ON (uri.uri_id = user_title.uri_id)
         WHERE user_title IS NOT NULL
         ORDER BY uri
    });
    $sth->execute;
    my $any_rows;
    while (my $row = $sth->fetchrow_hashref) {
        $any_rows = 1;

        $t->title_list->row->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(
                    edit => $row->{uri_id});
                $uri;
            }, 'edit');
	
        $t->title_list->row->add_hidden_form(
            do {
                my $uri = URI->new($q->url);
                $uri->query_param(
                    del => $row->{uri_id});
                $uri;
            }, 'del');
	
        $t->title_list->row->add(
            uri   => $row->{uri},
            title => $row->{user_title},
           );
    }
    if (!$any_rows) {
        $t->title_list->no_rows->add;
    }
    $t->title_list->add;
    
    print $q->header(
        -type => 'text/html; charset=UTF-8');
    print $t->str;
}

sub disp_rss_url {
    my $q = shift;
    my $t = Template->new(
        -fpath => 'tmpl/index.html');

    if ($q->param('cancel')) {
        print $q->redirect($q->url);
        return;
    }

    my $rss_uri = URI->new(
        sprintf(
            'http://%s%s/%s',
            $q->http('Host'),
            $q->url(-absolute => 1),
            $q->param('uri')))->canonical;

    $t->rss->add(
        rss => $rss_uri->as_string);

    $t->form_url->back->add;
    
    $t->form_url->rss->add(
        rss => $rss_uri->as_string);

    $t->form_url->add_hidden_form(
        do {
            my $uri = URI->new($q->url);
            $uri->query_param(cmd => 'rss');
            $uri;
        });
    $t->form_url->add;

    print $q->header(
        -type => 'text/html; charset=UTF-8');
    print $t->str;
}

sub do_set_title {
    my $q = shift;

    my $title = $q->param('title');
    if ($title and !$q->param('cancel')) {

        DB->do(q{BEGIN});
	
        if (my $uri = $q->param('uri')) {
            my $uri_id = RssC::Checker->uri_id($uri);
	    
            DB->do(q{
                REPLACE INTO user_title
                        (uri_id, user_title)
                 VALUES (?     , ?         )
            }, undef, $uri_id, $title);
        }
        elsif (my $uri_id = $q->param('uri_id')) {
            DB->do(q{
                REPLACE INTO user_title
                        (uri_id, user_title)
                 VALUES (?     , ?         )
            }, undef, $uri_id, $title);
        }

        DB->do(q{COMMIT});
    }

    print $q->redirect($q->url);
}

sub do_delete_title {
    my $q = shift;

    my $uri_id = $q->param('uri_id');
    if (defined $uri_id and !$q->param('cancel')) {
        DB->do(q{
            DELETE FROM user_title
             WHERE uri_id = ?
        }, undef, $uri_id);
    }

    print $q->redirect($q->url);
}
