#!/usr/local/bin/perl

# $Id: qtl,v 1.4 2007/06/05 19:27:48 kclark Exp $

=head1 NAME

qtl - web-based QTL admin tool

=head1 SYNOPSIS

Point browser to:

  http://dev.gramene.org/db/admin/qtl

=head1 DESCRIPTION

A web-based QTL admin tool.

=cut

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

use strict;
use CGI;
use Gramene::Config;
use Gramene::CDBI::Qtl;
use Gramene::QTL::DB;
use Gramene::Utils 'pager';
use Date::Format;
use Digest::MD5 'md5_hex';
use Email::Valid;
use Template;
use Mail::Sendmail;
use Time::ParseDate;
use Time::Seconds;

use constant FROM_ADDRESS => 'qtl-admin@gramene.org';
use constant DATE_FORMAT  => '%d-%b-%y';

my %actions = (
    add_xref                        => \&add_xref,
    add_qtl_ontology_association    => \&add_qtl_ontology_association,
    add_trait_ontology_association  => \&add_trait_ontology_association,
    add_trait_synonym               => \&add_trait_synonym,
    confirm_delete                  => \&confirm_delete,
    create_qtl                      => \&create_qtl,
    delete_xref                     => \&delete_xref,
    delete_trait                    => \&delete_trait,
    delete_trait_synonym            => \&delete_trait_synonym,
    delete_qtl                      => \&delete_qtl,
    delete_qtl_ontology_association => \&delete_qtl_ontology_association,
    delete_trait_ontology_association => \&delete_trait_ontology_association,
    home                            => \&home,
    search                          => \&search,
    trait_search                    => \&trait_search,
    update_trait                    => \&update_trait,
    update_trait_synonym            => \&update_trait_synonym,
    update_qtl                      => \&update_qtl,
    view_data_summary               => \&view_data_summary,
    view_qtl                        => \&view_qtl,
    view_trait                      => \&view_trait,
    view_trait_category             => \&view_trait_category,
    view_trait_categories           => \&view_trait_categories,
);

    #    invite_form           => \&invite_form,
    #    send_invite           => \&send_invite,
    #    view_invites          => \&view_invites,
    #    view_invitation       => \&view_invitation,
    #    view_curator          => \&view_curator,
    #    view_curators         => \&view_curators,
    #    view_session          => \&view_session,
    #    view_sessions         => \&view_sessions,
    #    view_upload           => \&view_upload,
    #    view_uploads          => \&view_uploads,

my $q            = CGI->new;
my $action       = $q->param('action') || 'home';
my $qdb          = Gramene::QTL::DB->new( admin => 1 );
my $config       = $qdb->config;
my $t            = Template->new(
    INCLUDE_PATH => $config->{'template_dir'},
    WRAPPER      => 'admin_wrapper',
    VARIABLES    => {
      cgi        => $q,
    }
);

eval {
    my $subref = $actions{ $action } or die "'$action' is not a valid action";
    $subref->( $qdb, $q, $t );
};

if ( my $err = $@ ) {
    process_template( 
        $q, $t, 'admin_error.tmpl', { title => 'Error', errmsg => $err } 
    );
}

# -------------------------------------------------------------
sub add_qtl_ontology_association {
    my ( $qdb, $q, $t )  = @_;
    
    $qdb->add_qtl_ontology_association( $q->Vars ) or die $qdb->error;

    return redirect_qtl_details( $q );
}

# -------------------------------------------------------------
sub add_trait_ontology_association {
    my ( $qdb, $q, $t )  = @_;
    
    $qdb->add_trait_ontology_association( $q->Vars ) or die $qdb->error;

    return $q->redirect( 
        $q->url . '?action=view_trait&trait_id=' . $q->param('trait_id')
    );
}

# -------------------------------------------------------------
sub add_xref {
    my ( $qdb, $q, $t )  = @_;
    
    $qdb->add_xref( $q->Vars ) or die $qdb->error;

    return redirect_qtl_details( $q );
}

# -------------------------------------------------------------
sub add_trait_synonym {
    my ( $qdb, $q, $t ) = @_;
    my $trait_id        = $q->param('trait_id') || 0;
    
    $qdb->add_trait_synonym(
        trait_id => $trait_id,
        synonym  => $q->param('synonym') || '',
    ) or die $qdb->error;

    return $q->redirect( $q->url."?action=view_trait&trait_id=$trait_id" );
}

# -------------------------------------------------------------
sub confirm_delete {
    my ( $qdb, $q, $t ) = @_;

    process_template( $q, $t, 'admin_confirm_delete.tmpl', 
        { 
            title => 'Confirm Delete',
        } 
    );
}

# -------------------------------------------------------------
sub create_qtl {
    my ( $qdb, $q, $t ) = @_;

    my $error;
    if ( $q->param('submit') ) {
        my $qtl_id = $qdb->create_qtl(
            cmap_map_aid     => $q->param('cmap_map_aid')     || '',
            qtl_accession_id => $q->param('qtl_accession_id') || '',
            published_symbol => $q->param('published_symbol') || '',
            qtl_trait_id     => $q->param('qtl_trait_id')     ||  0,
            linkage_group    => $q->param('linkage_group')    || '',
            start_position   => $q->param('start_position'),
            stop_position    => $q->param('stop_position'),
            comments         => $q->param('comments')         || '',
            species          => $q->param('species')          || '',
        ) or $error = $qdb->error;

        if ( $qtl_id ) {
            $q->param( qtl_id => $qtl_id );
            return redirect_qtl_details( $q );
        }
    }

    my $traits = $qdb->get_traits( no_synonyms => 1 );
    process_template( $q, $t, 'admin_create_qtl.tmpl', 
        { 
            title   => 'Create QTL',
            traits  => $traits,
            err_msg => $error,
        } 
    );
}

# -------------------------------------------------------------
sub delete_trait_ontology_association {
    my ( $qdb, $q, $t )  = @_;
    
    my $Assoc = Gramene::CDBI::Qtl::TraitOntologyAssociation->retrieve(
        $q->param('trait_ontology_association_id')
    ) or die 'Bad id';

    $Assoc->delete;

    return $q->redirect( 
        $q->url . '?action=view_trait&trait_id=' . $q->param('trait_id')
    );
}


# -------------------------------------------------------------
sub delete_qtl_ontology_association {
    my ( $qdb, $q, $t )  = @_;
    
    $qdb->delete_qtl_ontology_association( $q->Vars ) or die $qdb->error;

    return redirect_qtl_details( $q );
}

# -------------------------------------------------------------
sub delete_xref {
    my ( $qdb, $q, $t ) = @_;

    $qdb->delete_xref( $q->Vars ) or die $qdb->error;

    return redirect_qtl_details( $q );
}

# ----------------------------------------------------
sub delete_trait {
    my ( $qdb, $q, $t ) = @_;

    my $trait_category_id = $qdb->delete_trait(
        trait_id => $q->param('trait_id') || 0,
    ) or die $qdb->error;

    return $q->redirect( 
        $q->url .
        "?action=view_trait_category&trait_category_id=$trait_category_id"
    );
}

# ----------------------------------------------------
sub delete_trait_synonym {
    my ( $qdb, $q, $t ) = @_;

    $qdb->delete_trait_synonym(
        trait_synonym_id => $q->param('trait_synonym_id') || 0,
    ) or die $qdb->error;

    return $q->redirect( 
        $q->url . '?action=view_trait&trait_id=' . $q->param('trait_id')
    );
}

# -------------------------------------------------------------
sub delete_qtl {
    my ( $qdb, $q, $t ) = @_;
    $qdb->delete_qtl( qtl_id => $q->param('qtl_id') ) or die $qdb->error;

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

# -------------------------------------------------------------
sub home {
    my ( $qdb, $q, $t ) = @_;
    process_template( $q, $t, 'admin_home.tmpl', { title => 'QTL Admin' } );
}

# -------------------------------------------------------------
sub process_template {
    my ( $q, $t, $template, $args ) = @_;

    my $html;
    $t->process( $template, $args, \$html ) or $html = $t->error;

    print $q->header('text/html'), $html;
} 

# -------------------------------------------------------------
sub redirect_qtl_details {
    my $q                = shift;
    my $qtl_accession_id = $q->param('qtl_accession_id') || '';
    my $qtl_id           = $q->param('qtl_id') || $q->param('record_id') || 0;
    my $url              = sprintf( $q->url.'?action=view_qtl&%s=%s',
        $qtl_accession_id ? 'qtl_accession_id' : 'qtl_id',
        $qtl_accession_id ? $qtl_accession_id  : $qtl_id,
    );
    return $q->redirect( $url );
}

# -------------------------------------------------------------
sub search {
    my ( $qdb, $q, $t ) = @_;
    my $qtl;
    if ( $q->param('submit') ) {
        $qtl                  = $qdb->search(
            query             => $q->param('query')             || '',
            search_field      => $q->param('search_field')      || '',
            species_id        => $q->param('species_id')        || '',
            trait_category_id => $q->param('trait_category_id') ||  0,
            trait_id          => $q->param('trait_id')          ||  0,
            order_by          => $q->param('order_by')          || '',
        ) or die $qdb->error;

        if ( scalar @$qtl == 1 ) {
            $q->param( 'qtl_accession_id', $qtl->[0]{'qtl_accession_id'} );
            return redirect_qtl_details( $q );
        }
    }
    else {
        $qtl = [];
    }

    my $url = $q->url . '?' . join('&', map { "$_=".$q->param($_) } $q->param);

    my $db         = $qdb->db or die $qdb->error;
    my $trait_cats = $qdb->get_trait_categories;
    my $species    = $db->selectall_arrayref(
        'select * from species order by species', { Columns => {} }
    );

    my ( $pager, $data ) = pager(
        data             => $qtl,
        url              => $url,
        entries_per_page => 25,
        current_page     => $q->param('page_no'),
    );

    process_template(
        $q, $t, 'admin_search.tmpl',
        {
            pager            => $pager,
            qtl              => $data,
            trait_categories => $trait_cats,
            species          => $species,
            title            => 'QTL Admin',
        },
    );
}

# -------------------------------------------------------------
sub trait_search {
    my ( $qdb, $q, $t ) = @_;

    my $traits = [];
    if ( $q->param('query') ) {
        $traits        = $qdb->trait_search(
            field_name => $q->param('field_name') || '',
            query      => $q->param('query')      || '',
            order_by   => $q->param('order_by')   || '',
        ) or die $qdb->error;
    }

    my $url = $q->url . '?' . join('&', map { "$_=".$q->param($_) } $q->param);

    my ( $pager, $data ) = pager(
        data             => $traits,
        url              => $url,
        entries_per_page => 25,
        current_page     => $q->param('page_no'),
    );

    process_template(
        $q, $t, 'admin_trait_search.tmpl',
        {
            pager  => $pager,
            traits => $data,
            title  => 'QTL Trait Search',
        },
    );
}

# ----------------------------------------------------
sub view_data_summary {
    my ( $qdb, $q, $t )  = @_;

    my $db        = $qdb->db or die $qdb->error;
    my $no_qtl    = $db->selectrow_array('select count(*) from qtl');
    my $no_traits = $db->selectrow_array('select count(*) from qtl_trait');
    my $no_tsyn   = $db->selectrow_array(
        'select count(*) from qtl_trait_synonym'
    );
    my $no_cats   = $db->selectrow_array(
        'select count(*) from qtl_trait_category'
    );

    process_template(
        $q, $t, 'admin_data_summary.tmpl',
        {
            title        => 'QTL Data Summary',
            no_qtl       => $no_qtl,
            no_traits    => $no_traits,
            no_trait_syn => $no_tsyn,
            no_cats      => $no_cats,
        },
    );
}

# ----------------------------------------------------
sub view_qtl {
    my ( $qdb, $q, $t ) = @_;
    my $qtl             = $qdb->get_qtl( $q->Vars ) or die $qdb->error;
    my $ont             = $qdb->get_qtl_ontology_associations( 
        qtl_id => $qtl->{'qtl_id'} 
    );
    my $traits          = $qdb->get_traits( no_synonyms => 1 );
    my $xref_types      = $qdb->get_xref_types;
    my @species         = Gramene::CDBI::Qtl::Species->retrieve_all_sorted_by(
        'species'
    );

    process_template(
        $q, $t, 'admin_view_qtl.tmpl',
        {
            qtl                   => $qtl,
            species               => \@species,
            traits                => $traits,
            xref_types            => $xref_types,
            cmap_datasource       => $config->{'cmap_datasource'},
            ontology_associations => $ont,
        },
    );
}

# ----------------------------------------------------
sub view_trait {
    my ( $qdb, $q, $t ) = @_;
    my $trait_id = $q->param('trait_id') or die 'No trait id'; 
    my $db       = $qdb->db or die $qdb->error;
    my $sth      = $db->prepare(
        q[
            select q.qtl_trait_id, q.trait_symbol, q.trait_name,
                   q.to_accession, c.qtl_trait_category_id, c.trait_category
            from   qtl_trait q, qtl_trait_category c
            where  q.qtl_trait_id=?
            and    q.qtl_trait_category_id=c.qtl_trait_category_id
        ]
    );
    $sth->execute( $trait_id );
    my $trait = $sth->fetchrow_hashref;

    $trait->{'no_qtl'} = $db->selectrow_array(
        'select count(*) from qtl where qtl_trait_id=?',
        {}, ( $trait->{'qtl_trait_id'} )
    );

    $trait->{'synonyms'} = $db->selectall_arrayref(
        q[
            select qtl_trait_synonym_id, trait_synonym 
            from   qtl_trait_synonym 
            where  qtl_trait_id=?
        ],
        { Columns => {} }, 
        ( $trait->{'qtl_trait_id'} )
    );

    $trait->{'related_ontologies'} = $db->selectall_arrayref(
        q[
            select    oa.trait_ontology_association_id, oa.related_accession,
                      s.species_id, s.species, s.common_name
            from      trait_ontology_association oa 
            left join species s
            on        oa.species_id=s.species_id
            where     oa.to_accession=?
        ],
        { Columns => {} }, 
        ( $trait->{'to_accession'} )
    );

    my $cats    = $qdb->get_trait_categories;
    my $species = $db->selectall_arrayref(
        'select * from species order by species', { Columns => {} }
    );

    process_template(
        $q, $t, 'admin_view_trait.tmpl',
        { 
            title   => 'View Trait &quot;'.$trait->{'trait_symbol'}.'&quot;',
            trait   => $trait,
            species => $species,
            trait_categories => $cats,
        }
    );
}

# ----------------------------------------------------
sub view_trait_category {
    my ( $qdb, $q, $t ) = @_;
    my $trait_cat_id = $q->param('trait_category_id') or 
                       die 'No trait category ID';

    my $db  = $qdb->db or die $qdb->error;
    my $sth = $db->prepare(
        q[
            select qtl_trait_category_id, trait_category 
            from   qtl_trait_category 
            where  qtl_trait_category_id=?
        ]
    );
    $sth->execute( $trait_cat_id );
    my $trait_cat = $sth->fetchrow_hashref;

    $trait_cat->{'no_qtl'} = $db->selectrow_array(
        q[
            select count(q.qtl_id)
            from   qtl q, qtl_trait t
            where  q.qtl_trait_id=t.qtl_trait_id
            and    t.qtl_trait_category_id=?
        ],
        {},
        ( $trait_cat_id )
    );

    my $traits            = $qdb->get_traits( 
        with_qtl_counts   => 1,
        trait_category_id => $trait_cat_id,
        order_by          => $q->param('order_by') || '',
    ) or die $qdb->error;

    $trait_cat->{'no_traits'} = scalar @$traits;

    my $url = $q->url . '?' . join('&', map { "$_=".$q->param($_) } $q->param);

    my ( $pager, $data ) = pager(
        data             => $traits,
        url              => $url,
        entries_per_page => 25,
        current_page     => $q->param('page_no'),
    );

    process_template(
        $q, $t, 'admin_view_trait_category.tmpl',
        {
            title          => 'Trait Category &quot;'.
                              $trait_cat->{'trait_category'}.'&quot;',
            trait_category => $trait_cat,
            pager          => $pager,
            traits         => $data
        }
    );
}

# ----------------------------------------------------
sub view_trait_categories {
    my ( $qdb, $q, $t ) = @_;
    my $trait_cats = $qdb->get_trait_categories;
    my $db         = $qdb->db or die $qdb->error;
    my $traits     = $db->selectall_arrayref(
        q[
            select     count(q.qtl_trait_id) as no_qtl,
                       c.qtl_trait_category_id,
                       c.trait_category,
                       t.trait_name,
                       t.trait_symbol
            from       qtl_trait t
            left join  qtl q
            on         q.qtl_trait_id=t.qtl_trait_id
            inner join qtl_trait_category c
            on         c.qtl_trait_category_id=t.qtl_trait_category_id
            group by   c.qtl_trait_category_id,
                       c.trait_category,
                       t.trait_name,
                       t.trait_symbol
        ],
        { Columns => {} },
    );

    #
    # Group the traits by category.
    #
    my %counts;
    for my $trait ( @$traits ) {
        $counts{ $trait->{'qtl_trait_category_id'} }{'no_traits'}++;
        $counts{ $trait->{'qtl_trait_category_id'} }{'no_qtl'} +=
            $trait->{'no_qtl'};
    }

    for my $cat ( @$trait_cats ) {
        my $info = $counts{ $cat->{'qtl_trait_category_id'} };
        $cat->{'no_traits'} = $info->{'no_traits'};
        $cat->{'no_qtl'}    = $info->{'no_qtl'};
    }

    process_template(
        $q, $t, 'admin_view_trait_categories.tmpl',
        {
            title            => 'View Trait Categories',
            trait_categories => $trait_cats
        }
    );
}

# ----------------------------------------------------
sub update_trait {
    my ( $qdb, $q, $t ) = @_;

    $qdb->update_trait( $q->Vars ) or die $qdb->error;

    return $q->redirect( 
        $q->url . '?action=view_trait&trait_id=' . $q->param('trait_id')
    );
}

# ----------------------------------------------------
sub update_trait_synonym {
    my ( $qdb, $q, $t ) = @_;

    $qdb->update_trait_synonym(
        trait_synonym_id => $q->param('trait_synonym_id') ||  0,
        synonym          => $q->param('synonym')          || '',
    ) or die $qdb->error;

    return $q->redirect( 
        $q->url . '?action=view_trait&trait_id=' . $q->param('trait_id')
    );
}

# ----------------------------------------------------
sub update_qtl {
    my ( $qdb, $q, $t )  = @_;

    $qdb->update_qtl(
        qtl_id           => $q->param('qtl_id')           ||  0,
        qtl_accession_id => $q->param('qtl_accession_id') || '',
        published_symbol => $q->param('published_symbol') || '',
        qtl_trait_id     => $q->param('qtl_trait_id')     ||  0,
        linkage_group    => $q->param('linkage_group')    || '',
        start_position   => $q->param('start_position'),
        stop_position    => $q->param('stop_position'),
        comments         => $q->param('comments')         || '',
        species          => $q->param('species')          || '',
    ) or die $qdb->error;

    return redirect_qtl_details( $q );
}

# ---------------------------------------------------------
sub send_invite {
    my ( $qdb, $q, $t )  = @_;
    my $email_address = $q->param('email_address') or 
        die "No e-mail address\n";

    die "The address '$email_address' doesn't look valid\n"
        unless Email::Valid->address( $email_address );

    my $conf      = Gramene::Config->new;
    my $config    = $conf->get('qtl');
    my $secret    = $config->{'invite_secret'};
    my $db        = $qdb->db or die $qdb->error;
    my $sth       = $db->prepare(
        q[
            select invitation_id, email_address, date_invited, 
                   date_accepted, curator_id
            from   qtl_curator_invitation 
            where  email_address=?
        ]
    );
    $sth->execute( $email_address );
    my $invite = $sth->fetchrow_hashref;

    if ( $invite->{'curator_id'} ) {
        my $user_name = $db->selectrow_array(
            q[
                select user_name
                from   qtl_curator
                where  curator_id=?
            ],
            {},
            ( $invite->{'curator_id'} )
        );

        my $msg = "The invitation sent to e-mail address '" .
            $invite->{'email_address'} . 
            "' was accepted on " . $invite->{'date_accepted'} .
            " by the user '$user_name.'";

        process_template( $q, $t, 'admin_generic_message.tmpl', 
            { 
                title   => 'Invitation Already Accepted',
                message => $msg,
            }
        );
        return;
    }

    $sth = $db->prepare(
        q[
            select curator_id, user_name
            from   qtl_curator
            where  email_address=?
        ]
    );
    $sth->execute( $email_address );

    if ( my $curator = $sth->fetchrow_hashref ) {
        $sth = $db->prepare(
            q[
                select invitation_id, email_address, date_invited, 
                       date_accepted, curator_id
                from   qtl_curator_invitation 
                where  curator_id=?
            ]
        );
        $sth->execute( $curator->{'curator_id'} );
        my $orig_invite = $sth->fetchrow_hashref;
        my $msg = "A curator with the e-mail address '$email_address' ".
            "already exists.  The original invitation was sent to '".
            $orig_invite->{'email_address'} . "' on ". 
            $orig_invite->{'date_invited'};
        process_template( $q, $t, 'admin_generic_message.tmpl', 
            { 
                title   => 'Already a Curator',
                message => $msg,
            }
        );
        return;
    }

    my $invitation_id = $invite->{'invitation_id'};

    if ( $invitation_id && ! $q->param('force') ) {
        my $url = $q->url.'?'.$q->query_string.'&force=1';
        my $msg = "An invitation was sent to '" .
            $invite->{'email_address'} . "' on ".
            $invite->{'date_invited'} .
            "<br><a href=$url>Invite Again</a>\n";

        process_template( $q, $t, 'admin_generic_message.tmpl', 
            { 
                title   => 'Already Invited',
                message => $msg,
            }
        );
        return;
    }
    elsif ( $invitation_id && $q->param('force') ) {
        my @lt   = localtime;
        my $date = strftime( DATE_FORMAT, @lt );
        $db->do(
            q[
                update qtl_curator_invitation
                set    email_address=?, date_invited=?
                where  invitation_id=?
            ],
            {},
            ( $email_address, $date, $invitation_id )
        );
    }
    else {
        $invitation_id = $db->selectrow_array(
            'select max(invitation_id) from qtl_curator_invitation'
        );
        $invitation_id++;

        my @lt   = localtime;
        my $date = strftime( DATE_FORMAT, @lt );
        $db->do(
            q[
                insert 
                into   qtl_curator_invitation 
                       (invitation_id, email_address, date_invited)
                values (?, ?, ?)
            ],
            {},
            ( $invitation_id, $email_address, $date )
        );
    }

    my $subject = 'An Invitation to the Gramene QTL Community '.
        'Curation Project';
    my $url = 'http://dev.gramene.org/db/qtl/oc_login?' .
        'action=accept_invitation' .
        "&email_address=$email_address" .
        '&hash=' . md5_hex( $email_address, $secret );
    my $message = "You have been invited to join Gramene's QTL community ".
        "curation project.  To accept this invitation, please visit the ".
        "following URL:\n\n$url";

    sendmail(
        To      => $email_address,
        From    => FROM_ADDRESS,
        Subject => $subject,
        Message => $message,
    ) or die $Mail::Sendmail::error;

    process_template( $q, $t, 'admin_generic_message.tmpl', 
        { 
            title   => 'OK',
            message => "Invitation successfully sent to '$email_address'"
        }
    );
}

# ---------------------------------------------------------
sub invite_form {
    my ( $qdb, $q, $t )  = @_;
    process_template( $q, $t, 'admin_invite_form.tmpl', 
        { title => 'Community Curation Invitation Form' } );
}

# ---------------------------------------------------------
sub view_curator {
    my ( $qdb, $q, $t )  = @_;
    my $db         = $qdb->db or die $qdb->error;
    my $curator_id = $q->param('curator_id') or die 'No curator ID';
    my $sth        = $db->prepare(
        qq[
            select c.curator_id, c.user_name, c.real_name, c.organization,
                   c.email_address, c.password
            from   qtl_curator c
            where  c.curator_id=?
        ]
    );
    $sth->execute( $curator_id );
    my $curator = $sth->fetchrow_hashref;

    $curator->{'sessions'} = $db->selectall_arrayref(
        q[
            select   session_id, started_at, last_activity_at, logged_out_at
            from     qtl_curator_session
            where    curator_id=?
            order by started_at desc
        ],
        { Columns => {} },
        ( $curator_id )
    );

    my ( @durations, $total_time );
    for my $session ( @{ $curator->{'sessions'} } ) {
        my $start    = parsedate( $session->{'started_at'} );
        my $end      = parsedate( 
            $session->{'logged_out_at'} || $session->{'last_activity_at'} 
        ); 
        my $duration = $end - $start;
        next unless $duration > 0;
        my $s = Time::Seconds->new( $duration );
        $session->{'duration'} = sprintf( "%.2f", $s->minutes );
        push @durations, $duration;
        $total_time += $duration;
    }

    if ( @durations ) {
        my $s = Time::Seconds->new( $total_time / scalar @durations );
        $curator->{'average_session_length'} = sprintf( "%.2f", $s->minutes );
    }

    process_template( $q, $t, 'admin_view_curator.tmpl', 
        { title => 'View Curator', curator => $curator } );
}

# ---------------------------------------------------------
sub view_invitation {
    my ( $qdb, $q, $t )  = @_;
    my $db            = $qdb->db or die $qdb->error;
    my $invitation_id = $q->param('invitation_id') or die 'No invitation ID';
    my $sth           = $db->prepare(
        qq[
            select    i.invitation_id, i.email_address, i.date_invited, 
                      i.date_accepted, i.curator_id, c.user_name
            from      qtl_curator_invitation i
            left join qtl_curator c
            on        c.curator_id=i.curator_id
            where     i.invitation_id=?
        ]
    );
    $sth->execute( $invitation_id );
    my $invitation = $sth->fetchrow_hashref;

    process_template( $q, $t, 'admin_view_invitation.tmpl', 
        { title => 'View Invitation', invitation => $invitation } );
}

# ---------------------------------------------------------
sub view_invites {
    my ( $qdb, $q, $t )  = @_;
    my $db       = $qdb->db or die $qdb->error;
    my $order_by = $q->param('order_by') || 'date_invited';
    my $invites  = $db->selectall_arrayref(
        qq[
            select    i.invitation_id, i.email_address, 
                      i.date_invited, i.date_accepted, i.curator_id,
                      c.user_name, c.real_name, c.organization
            from      qtl_curator_invitation i
            left join qtl_curator c
            on        c.curator_id=i.curator_id
            order by  $order_by
        ],
        { Columns => {} }
    );

    process_template( $q, $t, 'admin_view_invites.tmpl', 
        { title => 'View Invites', invites => $invites } );
}

# ---------------------------------------------------------
sub view_curators {
    my ( $qdb, $q, $t )  = @_;
    my $db       = $qdb->db or die $qdb->error;
    my $order_by = $q->param('order_by') || 'user_name';
    my $curators = $db->selectall_arrayref(
        qq[
            select   c.curator_id, c.user_name, c.real_name, c.organization,
                     i.invitation_id, i.email_address, 
                     i.date_invited, i.date_accepted
            from     qtl_curator c, qtl_curator_invitation i
            where    c.curator_id=i.curator_id
            order by $order_by
        ],
        { Columns => {} }
    );

    for my $curator ( @$curators ) {
        $curator->{'no_sessions'} = $db->selectrow_array(
            'select count(*) from qtl_curator_session where curator_id=?',
            {}, ( $curator->{'curator_id'} )
        );
    }

    process_template( $q, $t, 'admin_view_curators.tmpl', 
        { title => 'View Curators', curators => $curators } );
}

# ---------------------------------------------------------
sub view_session {
    my ( $qdb, $q, $t )  = @_;
    my $session_id = $q->param('session_id') or die 'No session_id';
    my $db         = $qdb->db or die $qdb->error;
    my $sth        = $db->prepare(
        q[
            select s.session_id, s.curator_id, s.started_at,
                   s.last_activity_at, s.logged_out_at,
                   c.user_name
            from   qtl_curator_session s,
                   qtl_curator c
            where  s.session_id=?
            and    s.curator_id=c.curator_id
        ]
    );
    $sth->execute( $session_id );
    my $session = $sth->fetchrow_hashref;

    my $start    = parsedate( $session->{'started_at'} );
    my $end      = parsedate( 
        $session->{'logged_out_at'} || $session->{'last_activity_at'} 
    ); 
    my $duration = $end - $start;
    next unless $duration > 0;
    my $s = Time::Seconds->new( $duration );
    $session->{'duration'} = sprintf( "%.2f", $s->minutes );

    $session->{'uploads'} = $db->selectall_arrayref(
        q[
            select   incoming_file_name, system_file_name, size, uploaded_at
            from     qtl_curator_upload
            where    session_id=?
            order by uploaded_at
        ],
        { Columns => {} },
        ( $session_id )
    );

    my ( @sizes, $total_size );
    for my $upload ( @{ $session->{'uploads'} } ) {
        my $size = $upload->{'size'} or next;
        push @sizes, $size;
        $total_size += $size;
    }
    if ( @sizes ) {
        $session->{'average_upload_size'} = $total_size / scalar @sizes;
    }
    $session->{'total_upload_size'} = $total_size;

    process_template( $q, $t, 'admin_view_session.tmpl', 
        { title => 'View Session', session => $session } );
}

# ---------------------------------------------------------
sub view_sessions {
    my ( $qdb, $q, $t )  = @_;
    my $db = $qdb->db or die $qdb->error;

    my $sessions = $db->selectall_arrayref(
        q[
            select   s.session_id, s.curator_id, s.started_at,
                     s.last_activity_at, s.logged_out_at,
                     c.user_name
            from     qtl_curator_session s,
                     qtl_curator c
            where    s.curator_id=c.curator_id
            order by started_at desc
        ],
        { Columns => {} }
    );

    process_template( $q, $t, 'admin_view_sessions.tmpl', 
        { title => 'View Sessions', sessions => $sessions } );
}

# ---------------------------------------------------------
sub view_upload {
    my ( $qdb, $q, $t )  = @_;
    my $upload_id = $q->param('upload_id') or die 'No upload_id';
    my $db        = $qdb->db or die $qdb->error;
    my $sth       = $db->prepare(
        q[
            select u.upload_id, u.session_id, u.incoming_file_name,
                   u.system_file_name, u.size, u.uploaded_at,
                   u.processed_at, c.user_name, c.curator_id
            from   qtl_curator_upload u,
                   qtl_curator_session s,
                   qtl_curator c
            where  u.upload_id=?
            and    u.session_id=s.session_id
            and    s.curator_id=c.curator_id
        ]
    );
    $sth->execute( $upload_id );
    my $upload = $sth->fetchrow_hashref;

    process_template( $q, $t, 'admin_view_upload.tmpl', 
        { title => 'View Upload', upload => $upload } );
}

# ---------------------------------------------------------
sub view_uploads {
    my ( $qdb, $q, $t )  = @_;
    my $db = $qdb->db or die $qdb->error;

    my $uploads = $db->selectall_arrayref(
        q[
            select   u.upload_id, u.session_id, u.incoming_file_name,
                     u.system_file_name, u.size, u.uploaded_at,
                     u.processed_at, c.user_name, c.curator_id
            from     qtl_curator_upload u,
                     qtl_curator_session s,
                     qtl_curator c
            where    u.session_id=s.session_id
            and      s.curator_id=c.curator_id
            order by uploaded_at desc
        ],
        { Columns => {} }
    );

    process_template( $q, $t, 'admin_view_uploads.tmpl', 
        { title => 'View Uploads', uploads => $uploads } );
}

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

=pod

=head1 SEE ALSO

Gramene::QTL::DB.

=head1 AUTHOR

Ken Youens-Clark E<lt>kclark@cshl.orgE<gt>.

=cut
