package dtRdr::Library;

use warnings;
use strict;
use Carp;

# somebody said "use Universal", so bah
sub import {}

=head1 NAME

dtRdr::Library - library class frontend/base

=head1 SYNOPSIS

This module is still in need of some major hacking to get the plugin
loader worked out.  Metadata and other API aspects are also undecided.

=cut

use dtRdr::Library::YAMLLibrary; # XXX need plugin loader here

# NOTE I think all of these should be read-only, since the underlying
# implementation typically needs to save the attributes if they change.
use Class::Accessor::Classy;
ro 'id';
ro 'name';
ro 'type';
ro 'location';
rw 'book_data'; # XXX should be ro?
ro 'directory';
no  Class::Accessor::Classy;
{
  package dtRdr::LibraryData::BookInfo;
  use Class::Accessor::Classy;
  with 'new';
  ro 'id';
  ro 'book_id';
  ro 'title';
  ro 'uri';
  ro 'type';
  ro 'library';
  no  Class::Accessor::Classy;
  # TODO id re-arranging metheds swap_id, move_before -- callbacks to library
}
# and maybe...
# {
#   package dtRdr::LibraryData::LibraryInfo;
#   use Class::Accessor::Classy;
#   with 'new';
#   ro 'id';
#   ro 'name';
#   no  Class::Accessor::Classy;
# }

=head1 Name

dtRdr::Library.pm - Library interface

=cut

# The default structure of a library object is a hash. The following
# are the standard elements:
#
# books = array ref of book objects
# metadata = array ref of metadata objects
# library_info = Book info hashes
#
# Subclass methods:
#
# _load_books - should load in the basic book info from whatever
#               backing store that they're in. Does not create book
#               objects, but does load in the info the library needs
#               to load in the book objects
	# NOTE let's call these "book handles" --Eric
#
# _load_metadata - Load in all the metadata objects from the library
#
# _load_book_objects - Load in all the book objects for the books in
#                      the library

use dtRdr::Traits::Class qw(
  NOT_IMPLEMENTED
  );

=head1 Class Methods

=head2 class_by_type

  dtRdr::Library->class_by_type($type);

=cut
sub class_by_type {
  my $self = shift;
  my ($type) = @_;

  # XXX any color of black...
  return('dtRdr::Library::' . $type);
} # end subroutine class_by_type definition
########################################################################


=head1 Constructor

=head2 new

Create a new empty library object.

  my $library = dtRdr::Library->new();

=cut

sub new {
  my $package = shift;
  my $class = ref($package) || $package;
  my $self = {
    metadata => [],
    # books    => [], # XXX need to be able to do this here
    library_info => {},
	  };
  bless($self, $class);
  return($self);
} # end subroutine new definition
########################################################################

=item load_uri

Load the library stored at C<URI> and set the location property.

=cut

sub load_uri { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

=item books

Return a list of book objects for the books stored in a library object

=cut

sub get_books {
  my $self = shift;
  if (!defined $self->{books}) {
    $self->_load_book_objects;
  }
  return @{$self->{books}};
}

=item get_metadata

Return a list of all the metadata objects stored in this library

=cut

sub get_metadata {
  my $self = shift;
  if(defined $self->{metadata}) {
    return @{$self->{metadata}};
  }
  else { # this wasn't even returning a value!
    do('./util/BREAK_THIS') or die;
    $self->_fetch_all_metadata();
  }
}

=item get_book_info

Return a list of book info objects.

  my @infos = $lib->get_book_info;

=cut

sub get_book_info {
  my $self = shift;
  return @{$self->book_data};
}

=item open_book

Return a book object matching a given key/value lookup pair.

  $lib->open_book(id => $id);

or

  $lib->open_book(title => $title);

or

  $lib->open_book(book_id => $book_id);

=cut

sub open_book {
  my $self = shift;
  (@_ % 2) and croak('odd number of elements in argument list');
  my (%args) = @_;
  my @valid = qw(id title book_id);
  my ($key) = grep({exists($args{$_})} @valid);
  $key or croak("no valid key in ", join(keys(%args)));

  my @books = $self->find_book_by($key, $args{$key});
  @books or die "no books matching $key eq $args{$key}";
  (@books == 1) or die "too many books @books";
  my $B = $books[0];
  # this will get us by until config is operable
  # (and shouldn't break after it works either)
  require dtRdr::Plugins::Book;
  dtRdr::Plugins::Book->init();

  # requires that config sets type -> class prefs
  my $book_class = dtRdr::Plugins::Book->class_for_type($B->type);
  $book_class or die "cannot get a plugin for $B->{type}";
  0 and warn "book class: $book_class";
  my $book_object = $book_class->new();

  # TODO add abstraction somewhere in here
  #      (e.g. it might be http://, absolute, etc)
  my $uri = $self->directory . '/' . $B->uri;
  0 and warn "book is $uri";
  $book_object->load_uri($uri);

  # XXX does it need the library?
  # $book_object->set('library', $self);

  return($book_object);
} # end subroutine open_book definition
########################################################################

=head2 find_book_by

Virtual:  find a book with a for a given $key/$value match.

  $info = $lib->find_book_by($key, $value);

=cut

sub find_book_by { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

=item add_metadata

Add the C<metadata> object to the C<book>, stored in the library

=cut

sub add_metadata { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

=item delete_metadata($book, $metadata)

Remove the C<metadata> from the specified C<book>, as it's stored in
the library.

=cut

sub delete_metadata { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

=head2 add_book

=cut

sub add_book { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

=item remove_book

Remove the book.

All metadata for the book will be deleted from the library.

=cut

sub remove_book { my $self = shift; $self->NOT_IMPLEMENTED(@_); }

# XXX kill these {{{
sub get_info {
  my ($self, $info) = @_;
  return $self->{library_info}{$info};
}

sub get_all_info {
  my $self = shift;
  return %{$self->{library_info}};
}

sub set_info { my $self = shift; $self->NOT_IMPLEMENTED(@_); }
# XXX kill those }}}

=head1 AUTHOR

Dan Sugalski, <dan@sidhe.org>

Eric Wilhelm <ewilhelm at cpan dot org>

=head1 COPYRIGHT

Copyright (C) 2006 by Dan Sugalski, Eric L. Wilhelm, and OSoft, All
Rights Reserved.

=head1 NO WARRANTY

Absolutely, positively NO WARRANTY, neither express or implied, is
offered with this software.  You use this software at your own risk.  In
case of loss, no person or entity owes you anything whatsoever.  You
have been warned.

=head1 LICENSE

The dotReader(TM) is OSI Certified Open Source Software licensed under
the GNU General Public License (GPL) Version 2, June 1991. Non-encrypted
and encrypted packages are usable in connection with the dotReader(TM).
The ability to create, edit, or otherwise modify content of such
encrypted packages is self-contained within the packages, and NOT
provided by the dotReader(TM), and is addressed in a separate commercial
license.

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.

=cut

1;
# vim:ts=2:sw=2:et:sta
