package OpenILS::WWW::Social;

# Copyright (C) 2010 Laurentian University
# Dan Scott <dscott@laurentian.ca>
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

use strict; use warnings;

use Apache2::Log;
use Apache2::Const -compile => qw(OK REDIRECT DECLINED NOT_FOUND :log);
use APR::Const    -compile => qw(:error SUCCESS);
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::RequestUtil;
use CGI;
use Template;

use OpenSRF::EX qw(:try);
use OpenSRF::Utils qw/:datetime/;
use OpenSRF::Utils::Cache;
use OpenSRF::System;
use OpenSRF::AppSession;

use OpenILS::Utils::Fieldmapper;
use OpenSRF::Utils::Logger qw/$logger/;
use OpenILS::Application::AppUtils;
use OpenILS::Utils::CStoreEditor qw/:funcs/;
use OpenILS::Utils::ModsParser;
use XML::LibXML;
use DateTime;

my $log = 'OpenSRF::Utils::Logger';
my $U = 'OpenILS::Application::AppUtils';

my ($bootstrap, $editor, $actor, $templates, $LocalTZ);
my $i18n = {};
my $init_done = 0; # has child_init been called?

# helper functions inserted into the TT environment
my $_TT_helpers = {

    # turns a date into something TT can understand
    format_date => sub {
        my $date = shift;
        $date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($date));
        return sprintf(
            "%0.2d:%0.2d:%0.2d %0.2d-%0.2d-%0.4d",
            $date->hour,
            $date->minute,
            $date->second,
            $date->day,
            $date->month,
            $date->year
        );
    },

    # escapes a string for inclusion in an XML document.  escapes &, <, and > characters
    escape_xml => sub {
        my $str = shift;
        $str =~ s/&/&amp;/sog;
        $str =~ s/</&lt;/sog;
        $str =~ s/>/&gt;/sog;
        return $str;
    },

};

sub import {
    my $self = shift;
    $bootstrap = shift;
}

sub child_init {
    OpenSRF::System->bootstrap_client( config_file => $bootstrap );
    
    my $conf = OpenSRF::Utils::SettingsClient->new();
    my $idl = $conf->config_value("IDL");
    Fieldmapper->import(IDL => $idl);
    $templates = $conf->config_value("dirs", "templates");
    OpenILS::Utils::CStoreEditor::init();
    $editor = new_editor();
    load_i18n();

   # Getting the timezone is slow; do it once
    $LocalTZ = DateTime::TimeZone->new( name => 'local' );
 
    $init_done = 1;
}

sub handler {
    my $apache = shift;

    child_init() unless $init_done;

    return Apache2::Const::DECLINED if (-e $apache->filename);

    my $ctx = {};

    $ctx->{'helpers'} = $_TT_helpers;

    $ctx->{'uri'} = $apache->uri;

    # Get our locale from the URL
    (my $locale = $apache->path_info) =~ s{^.*?/([a-z]{2}-[A-Z]{2})/.*?$}{$1};
    if (!$locale) {
        $locale = 'en-US';
    }

    # If locale exists, use it; otherwise fall back to en-US
    if (exists $i18n->{$locale}) {
        $ctx->{'i18n'} = $i18n->{$locale};
    } else {
        $ctx->{'i18n'} = $i18n->{'en-US'};
    }

    my $tt = Template->new({
        INCLUDE_PATH => $templates
    }) || die "$Template::ERROR\n";

    # So what object are we dealing with here?
    if ($apache->uri =~ m{/social(/[a-z]{2}-[A-Z]{2})?/user/}) {
        if ($apache->uri =~ m{.atom$}) {
            return user_activity_stream($apache);
        } else {
            return display_user($apache, $tt, $ctx);
        }
    } elsif ($apache->uri =~ m{/social(/[a-z]{2}-[A-Z]{2})?/thing/}) {
        # A "thing" is represented by a biblio.record_entry
        # It is not necessarily a book, thus "thing"
        if ($apache->uri =~ m{.atom$}) {
            return thing_activity_stream($apache);
        } else {
            return display_thing($apache, $tt, $ctx);
        }
    }
}

# XXX Need to build an HTML-friendly template for displaying a thing
# and all of the social activity around it
sub display_thing {
    return;
}

# The user URIs identify the user by ID because usernames and email can change
# Grab the user object from the database while we're at it
sub _get_base_user {
    my $apache = shift;

    (my $uid = $apache->uri) =~ s{.*/social(/[a-z]{2}-[A-Z]{2})?/user/(\d+).*?$}{$2};

    my $user = $editor->retrieve_actor_user($uid);

    return $user;
}

# Things are identified strictly by their record ID
sub thing_activity_stream {
    my ($apache) = @_;

    (my $thing = $apache->uri) =~ s{.*/social(/[a-z]{2}-[A-Z]{2})?/thing/(\d+).*?$}{$2};

    if (!$thing) {
        return Apache2::Const::OK;
    }

    $apache->content_type('application/atom+xml');

    my $stream = create_thing_feed($apache, $thing);

    print $stream->toString(1);
    
    return Apache2::Const::OK;
}

# Generate the Activity Stream for a given user
sub user_activity_stream {
    my ($apache) = @_;

    my $user = _get_base_user($apache);
    if (!$user) {
        return Apache2::Const::OK;
    }

    $apache->content_type('application/atom+xml');

    my $stream = create_user_feed($apache, $user);
    print $stream->toString(1);
    
    return Apache2::Const::OK;
}

# Generate the Activity Stream for a given thing
sub create_thing_feed {
    my ($apache, $thing) = @_;

    my ($doc, $feed) = base_feed($apache);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode('Activity stream for the object "' . get_bib_and_mods($thing)->title . '"');
    $feed->addChild($title);

    create_thing_entries($apache, $doc, $thing);

    return $doc;
}

# All Activity Stream feeds have a common base
# XXX We're assuming HTTP, not HTTPS here...
sub base_feed {
    my ($apache) = @_;
    
    my $now = DateTime->now(time_zone => $LocalTZ);

    my $host = $apache->hostname;
    my $uri = $apache->uri;
    my $html_uri = $uri;
    $html_uri =~ s/.atom$//;

    my $doc = XML::LibXML->createDocument();
    my $feed = $doc->createElementNS("http://www.w3.org/2005/Atom", "feed");
    $doc->setDocumentElement($feed);

    $feed->setNamespace("http://www.w3.org/2005/Atom");
    $feed->setNamespace("http://activitystrea.ms/spec/1.0/", "activity", 0);
    $feed->setNamespace("http://portablecontacts.net/spec/1.0", "poco", 0);

    my $feed_id = $doc->createElementNS(undef, "id");
    $feed_id->appendTextNode(generate_tag($host, $uri, $now));
    $feed->addChild($feed_id);

    my $updated = $doc->createElementNS(undef, "updated");
    $updated->appendTextNode($now->strftime('%FT%TZ'));
    $feed->addChild($updated);

    # Link to our HTML representation
    my $l_html = $doc->createElementNS(undef, "link");
    $l_html->setAttributeNS(undef, "rel", "alternate");
    $l_html->setAttributeNS(undef, "type", "text/html");
    $l_html->setAttributeNS(undef, "href", "http://$host$html_uri");
    $feed->addChild($l_html);

    # Link to our self
    my $l_self = $doc->createElementNS(undef, "link");
    $l_self->setAttributeNS(undef, "rel", "self");
    $l_self->setAttributeNS(undef, "type", "application/atom+xml");
    $l_self->setAttributeNS(undef, "href", "http://$host$uri");
    $feed->addChild($l_self);

    return ($doc, $feed);
}

# Standardized form of representing the user's full name
sub generate_user_name {
    my ($user) = @_;

    my $display_name = $user->first_given_name . ' ';
    $display_name .= ($user->second_given_name || '') . ' ';
    $display_name .= $user->family_name || '';
    $display_name =~ s/ +/ /g;

    return $display_name;
}

sub create_user_feed {
    my ($apache, $user) = @_;

    my ($doc, $feed) = base_feed($apache);
    my $display_name = generate_user_name($user);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode("Personal activity stream for " . ($display_name || ("person " . $user->id)));
    $feed->addChild($title);

    add_author($doc, $user, $feed);

    create_user_entries($apache, $doc, $user, $display_name || $user->usrname);

    return $doc;
}

sub add_author {
    my ($doc, $user, $anchor) = @_;

    my $display_name = generate_user_name($user);

    # Introduce the actor (atom:author)
    my $author = $doc->createElementNS(undef, "author");

    # atom:name link, required in atom:author elements
    my $aname = $doc->createElementNS(undef, "name");
    my $aname_done = 0;

    # Get the best name we can; flesh out Portable Contacts while we're at it
    if ($display_name) {
        my $dname = $doc->createElementNS(undef, "poco:displayName");
        $dname->appendTextNode($display_name);
        $anchor->addChild($dname);

        $aname->appendTextNode($display_name);
        $author->addChild($aname);
        $aname_done = 1;
    }

    my $uname = $doc->createElementNS(undef, "poco:preferredUsername");
    if ($user->usrname) {
        $uname->appendTextNode($user->usrname);
        if (!$aname_done) {
            $aname->appendTextNode($user->usrname);
            $author->addChild($aname);
            $aname_done = 1;
        }
    } else {
        # This is a poor excuse for an author name; oh well
        $uname->appendTextNode($user->id);
        if (!$aname_done) {
            $aname->appendTextNode($user->id);
        }
        $author->addChild($aname);
    }
    $anchor->addChild($author);

    if ($user->email) {
        my $email = $doc->createElementNS(undef, "email");
        $email->appendTextNode($user->email);
        $author->addChild($email);
    }
    $anchor->addChild($uname);
}

sub create_user_entries {
    my ($apache, $doc, $user, $user_name) = @_;

    my $activities = $editor->search_social_activity_stream(
        { actor => $user->id },
        { order_by => { socas => "stamped DESC" }, limit => 10 }
    );

    foreach my $activity (@$activities) {
        generate_activity_entries($activity, $apache, $doc, $user, $user_name);
    }
}

sub create_thing_entries {
    my ($apache, $doc, $thing) = @_;

    my $activities = $editor->search_social_activity_stream(
        { object => $thing },
        { order_by => { socas => "stamped DESC" }, limit => 10 }
    );

    foreach my $activity (@$activities) {
        my $user = $editor->retrieve_actor_user($activity->actor);
        my $display_name = generate_user_name($user);
        generate_activity_entries($activity, $apache, $doc, $user, $display_name || $user->usrname);
    }
}


sub generate_activity_entries {
    my ($activity, $apache, $doc, $user, $user_name) = @_;

    my $entry = $doc->createElementNS(undef, "entry");

    if ($activity->activity eq "add_bookbag") {
        _add_bookbag($activity, $user_name, $apache, $doc, $entry);
    } elsif ($activity->activity eq "add_bookbag_item") {
        _add_bookbag_item($activity, $user_name, $apache, $doc, $entry);
    } elsif ($activity->activity eq "add_review") {
        _add_review($activity, $user_name, $apache, $doc, $entry);
    } elsif ($activity->activity eq "circ") {
        _circ($activity, $user_name, $apache, $doc, $entry);
    }

    # Required by Atom Activity spec
    my $published = $doc->createElementNS(undef, "published");
    my $date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($activity->stamped));
    $published->appendTextNode($date->strftime('%FT%TZ'));
    $entry->addChild($published);

    # Required by Atom spec
    my $updated = $doc->createElementNS(undef, "updated");
    $updated->appendTextNode($date->strftime('%FT%TZ'));
    $entry->addChild($updated);

    add_author($doc, $user, $entry);

    $doc->documentElement()->addChild($entry);
}

sub _add_review {
    my ($activity, $user_name, $apache, $doc, $entry) = @_;
    # verb = post (http://activitystrea.ms/schema/1.0/post)
    # object = list (http://activitystrea.ms/schema/1.0/review)

    my $review = $editor->retrieve_social_user_review($activity->object);
    my $mods = get_bib_and_mods($activity->target);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode("$user_name reviewed " . $mods->title);
    $entry->addChild($title);

    my $summary = $doc->createElementNS(undef, "summary");
    $summary->appendTextNode("$user_name reviewed " . $mods->title);
    $entry->addChild($summary);

    my $content = $doc->createElementNS(undef, "content");
    $content->setAttributeNS(undef, "type", "text/html");
    $content->appendTextNode($review->value);
    $entry->addChild($content);

    my $id = $doc->createElementNS(undef, "id");
    $id->appendTextNode(generate_tag($apache->hostname, '/opac/social/create/review/' . $activity->object));
    $entry->addChild($id);

    my $verb = $doc->createElementNS(undef, "activity:verb");
    $verb->appendTextNode("http://activitystrea.ms/schema/1.0/post");
    $entry->addChild($verb);

    my $object = $doc->createElementNS(undef, "activity:object");
    my $object_type = $doc->createElementNS(undef, "activity:object-type");
    $object_type->appendTextNode("http://activitystrea.ms/schema/1.0/review");
    $object->addChild($object_type);

    my $object_id =  $doc->createElementNS(undef, "id");
    $object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/review/' . $activity->object));
    $object->addChild($object_id);

    my $object_content =  $doc->createElementNS(undef, "content");
    $object_content->setAttributeNS(undef, "type", "text/html");
    $object_content->appendTextNode($review->value);
    $object->addChild($object_content);

    my $object_link =  $doc->createElementNS(undef, "link");
    $object_link->setAttributeNS(undef, "rel", "alternate");
    $object_link->setAttributeNS(undef, "type", "text/html");
    $object_link->setAttributeNS(undef, "href", 'http://' . $apache->hostname . '/opac/social/review/' . $activity->object);
    $object->addChild($object_link);

    # Must be empty if the review does not have a user-generated title
    my $object_title = $doc->createElementNS(undef, "title");
    $object->addChild($object_title);
    $entry->addChild($object);

    my $target = $doc->createElementNS(undef, "activity:target");
    my $t_object_type = $doc->createElementNS(undef, "activity:object-type");
    $t_object_type->appendTextNode("http://activitystrea.ms/schema/1.0/list");
    $target->addChild($t_object_type);

    my $t_object_id =  $doc->createElementNS(undef, "id");
    $t_object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/thing/' . $activity->target));
    $target->addChild($t_object_id);

    my $t_object_title = $doc->createElementNS(undef, "title");
    $t_object_title->appendTextNode($mods->title);
    $target->addChild($t_object_title);

    $entry->addChild($target);

}


sub _circ {
    my ($activity, $user_name, $apache, $doc, $entry) = @_;
    # verb = post (http://activitystrea.ms/schema/1.0/post)
    # object = list (http://activitystrea.ms/schema/1.0/list)

    my $circ = $editor->retrieve_action_circulation($activity->object);
    my $mods = get_bib_and_mods($activity->target);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode("$user_name returned " . $mods->title);
    $entry->addChild($title);

    my $summary = $doc->createElementNS(undef, "summary");
    $summary->appendTextNode("$user_name returned " . $mods->title);
    $entry->addChild($summary);

    my $content = $doc->createElementNS(undef, "content");
    $content->appendTextNode("$user_name returned " . $mods->title);
    $entry->addChild($content);

    my $id = $doc->createElementNS(undef, "id");
    $id->appendTextNode(generate_tag($apache->hostname, '/opac/social/create/circ/' . $activity->object));
    $entry->addChild($id);

    my $verb = $doc->createElementNS(undef, "activity:verb");
    $verb->appendTextNode("http://activitystrea.ms/schema/1.0/post");
    $entry->addChild($verb);

    my $object = $doc->createElementNS(undef, "activity:object");
    my $object_type = $doc->createElementNS(undef, "activity:object-type");
    $object_type->appendTextNode("http://activitystrea.ms/schema/1.0/list");
    $object->addChild($object_type);

    my $object_id =  $doc->createElementNS(undef, "id");
    $object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/circ/' . $activity->object));
    $object->addChild($object_id);

    my $object_title = $doc->createElementNS(undef, "title");
    $object_title->appendTextNode("Circulation");
    $object->addChild($object_title);
    $entry->addChild($object);
}


sub _add_bookbag {
    my ($activity, $user_name, $apache, $doc, $entry) = @_;
    # verb = post (http://activitystrea.ms/schema/1.0/post)
    # object = list (http://activitystrea.ms/schema/1.0/list)

    my $bb = $editor->retrieve_container_biblio_record_entry_bucket($activity->object);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode("$user_name created the bookbag " . $bb->name);
    $entry->addChild($title);

    my $summary = $doc->createElementNS(undef, "summary");
    $summary->appendTextNode("$user_name created the bookbag " . $bb->name);
    $entry->addChild($summary);

    my $content = $doc->createElementNS(undef, "content");
    $content->appendTextNode("$user_name created the bookbag " . $bb->name);
    $entry->addChild($content);

    my $id = $doc->createElementNS(undef, "id");
    $id->appendTextNode(generate_tag($apache->hostname, '/opac/social/create/bookbag/' . $activity->object));
    $entry->addChild($id);

    my $verb = $doc->createElementNS(undef, "activity:verb");
    $verb->appendTextNode("http://activitystrea.ms/schema/1.0/post");
    $entry->addChild($verb);

    my $object = $doc->createElementNS(undef, "activity:object");
    my $object_type = $doc->createElementNS(undef, "activity:object-type");
    $object_type->appendTextNode("http://activitystrea.ms/schema/1.0/list");
    $object->addChild($object_type);

    my $object_id =  $doc->createElementNS(undef, "id");
    $object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/bookbag/' . $activity->object));
    $object->addChild($object_id);

    my $object_title = $doc->createElementNS(undef, "title");
    $object_title->appendTextNode($bb->name);
    $object->addChild($object_title);
    $entry->addChild($object);
}

sub _add_bookbag_item {
    my ($activity, $user_name, $apache, $doc, $entry) = @_;
    # verb = save (http://activitystrea.ms/schema/1.0/save)
    # object = article (ugh) (http://activitystrea.ms/schema/1.0/article)
    # target = list (http://activitystrea.ms/schema/1.0/list) 

    my $bb = $editor->retrieve_container_biblio_record_entry_bucket($activity->target);
    my $mods = get_bib_and_mods($activity->object);

    my $id = $doc->createElementNS(undef, "id");
    $id->appendTextNode(generate_tag($apache->hostname, '/opac/social/save/bookbag_item/' . $activity->target . '/' . $activity->object));
    $entry->addChild($id);

    my $title = $doc->createElementNS(undef, "title");
    $title->appendTextNode("$user_name added " . $mods->title . " to bookbag " . $bb->name);
    $entry->addChild($title);

    my $summary = $doc->createElementNS(undef, "summary");
    $summary->appendTextNode("$user_name added " . $mods->title . " to bookbag " . $bb->name);
    $entry->addChild($summary);

    my $content = $doc->createElementNS(undef, "content");
    $content->appendTextNode("$user_name added " . $mods->title . " to bookbag " . $bb->name);
    $entry->addChild($content);

    my $verb = $doc->createElementNS(undef, "activity:verb");
    $verb->appendTextNode("http://activitystrea.ms/schema/1.0/save");
    $entry->addChild($verb);

    my $object = $doc->createElementNS(undef, "activity:object");
    my $object_type = $doc->createElementNS(undef, "activity:object-type");
    $object_type->appendTextNode("http://activitystrea.ms/schema/1.0/article");
    $object->addChild($object_type);

    my $object_id =  $doc->createElementNS(undef, "id");
    $object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/bookbag/' . $activity->object));
    $object->addChild($object_id);

    my $object_title = $doc->createElementNS(undef, "title");
    $object_title->appendTextNode($mods->title);
    $object->addChild($object_title);

    $entry->addChild($object);

    my $target = $doc->createElementNS(undef, "activity:target");
    my $t_object_type = $doc->createElementNS(undef, "activity:object-type");
    $t_object_type->appendTextNode("http://activitystrea.ms/schema/1.0/list");
    $target->addChild($t_object_type);

    my $t_object_id =  $doc->createElementNS(undef, "id");
    $t_object_id->appendTextNode(generate_tag($apache->hostname, '/opac/social/thing/' . $activity->target));
    $target->addChild($t_object_id);

    my $t_object_title = $doc->createElementNS(undef, "title");
    $t_object_title->appendTextNode($bb->name);
    $target->addChild($t_object_title);

    $entry->addChild($target);
}


# Generate a unique tag for this feed or feed entry
sub generate_tag {
    my ($hostname, $uri, $now) = @_;

    if (!$now) {
        $now = DateTime->now(time_zone => $LocalTZ);
    }

    $hostname =~ s{^.*?([^\.]+\.[^\.]{2,4})/?$}{$1};
    $uri =~ s{#}{/}g;
    my $date = $now->strftime('%F');
    return "tag:$hostname,$date:$uri";
}

=pod

Need to build a $ctx structure for the user info like so:
    $ctx->{'user'}->{'avatar'}
    $ctx->{'user'}->{'email'}
    $ctx->{'user'}->{'name'}
    $ctx->{'user'}->{'usrname'}
    $ctx->{'home_library'}->{'name'}
    $ctx->{'circ_history'}->[ {'isbn', 'record_id', 'title', 'author', 'xact_finish' }, ]
=cut
sub display_user {
    my ($apache, $tt, $ctx) = @_;

    my $user = _get_base_user($apache);
    if (!$user) {
        $tt->process('social/user/about.tt2', $ctx) || die $tt->error();
        return Apache2::Const::OK;
    }

    # Check user settings here to prevent disclosing information they
    # do not want to disclose

    $ctx->{'user'}{'usrname'} = $user->usrname;
    $ctx->{'user'}{'email'} = $user->email || '';
    $ctx->{'user'}{'name'} = generate_user_name($user);

    my $home_ou = $editor->retrieve_actor_org_unit($user->home_ou);
    $ctx->{'home_library'}{'name'} = $home_ou->name;

    # Now get circs - expose most recent 10 circs by default?
    my $circs = $editor->search_action_circulation([
        { usr => $user->id, xact_finish => { '!=' => undef } },
        { order_by => { circ => 'xact_start DESC' }, limit => 10 }
    ]);

    my @circ_history;
    foreach my $circ (@$circs) {
        my $title = $U->simple_scalar_request(
            "open-ils.storage", 
            "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
            $circ->target_copy
        );

		next unless $title;

        my $mods = get_mods($title);

        push @circ_history, {
            record_id => $title->id,
            isbn => $mods->isbn,
            title => $mods->title,
            author => $mods->author,
            xact_finish => $circ->xact_finish
        };
    }

    if (@circ_history) {
        $ctx->{'circ_history'} = \@circ_history;
    }

    # Now expose public bookbags; set a reasonable limit
    my @bookbags;
    my $bbs = $editor->search_container_biblio_record_entry_bucket([
        { owner => $user->id, pub => 't', btype => 'bookbag' },
        { order_by => { cbreb => 'name ASC' }, limit => 100 }
    ]);

    foreach my $bb (@$bbs) {
        my $bbitems = $editor->search_container_biblio_record_entry_bucket_item([
            { bucket => $bb->id }
        ]);

        push @bookbags, { id => $bb->id, name => $bb->name, count => (scalar @$bbitems) };

    };

    if (@bookbags) {
        $ctx->{'bookbags'} = \@bookbags;
    }
#        my $bbitems = $editor->search_container_biblio_record_entry_bucket_item([
#            { bucket => $bb->id },
#            { order_by => { cbrebi => 'id ASC' }, limit => 100 }
#        ]);
#
#        foreach my $bbitem (@$bbitems) {
#            my $title = $editor->retrieve_biblio_record_entry($bbitem->target_biblio_record_entry);
#            get_mini_records($title, $bookbags);
#        }

    # Now expose published reviews; set a reasonable limit
    my @reviews;
    my $revs = $editor->search_social_user_review([
        { creator => $user->id, approved => 't' },
        { order_by => { socr => 'create_date DESC' }, limit => 100 }
    ]);

    foreach my $review (@$revs) {
        my $mods = get_bib_and_mods($review->record);

        push @reviews, {
            record_id => $review->record,
            isbn => $mods->isbn,
            title => $mods->title,
            author => $mods->author,
            review => $review->value
        };
    };

    if (@reviews) {
        $ctx->{'reviews'} = \@reviews;
    }

    $apache->content_type('text/html');

    $tt->process('social/user/about.tt2', $ctx) || die $tt->error();
    return Apache2::Const::OK;
}

sub get_bib_and_mods {
    my ($bib_id) = @_;
    
    my $bre = $editor->retrieve_biblio_record_entry($bib_id);

    my $mods = get_mods($bre);
}

sub get_mods {
    my ($bre) = @_;

    my $u = OpenILS::Utils::ModsParser->new();
    $u->start_mods_batch($bre->marc());
    my $mods = $u->finish_mods_batch();
    $mods->doc_id($bre->id) if $mods;
    my $isbn = $mods->isbn || '';
    $isbn =~ s/-//g;
    $isbn =~ s/(\d+).*?$/$1/g;
    $mods->isbn($isbn);

    return $mods;
}

# Load our localized strings - lame, need to convert to Locale::Maketext
sub load_i18n {
    foreach my $string_bundle (glob("$templates/password-reset/strings.*")) {
        open(I18NFH, '<', $string_bundle);
        (my $locale = $string_bundle) =~ s/^.*\.([a-z]{2}-[A-Z]{2})$/$1/;
        $logger->debug("Loaded locale [$locale] from file: [$string_bundle]");
        while(<I18NFH>) {
            my ($string_id, $string) = ($_ =~ m/^(.+?)=(.*?)$/);
            $i18n->{$locale}{$string_id} = $string;
        }
        close(I18NFH);
    }
}

1;

# vim: et:ts=4:sw=4
