# Copyright 2002-2008 Josh Clark and Global Moxie, LLC. This code cannot be 
# redistributed without permission from globalmoxie.com.  For more
# information, consult your Big Medium license.
#
# $Id: Pointer.pm 3043 2008-03-31 14:00:38Z josh $

package BigMed::Pointer;
use strict;
use utf8;
use Carp;

use base qw(BigMed::Data);


###########################################################
# SET POINTER DATA SCHEMA
###########################################################

my @data_schema = (
    {
        name  => 'site',
        type  => 'system_id',
        index => 1,
    },
    {
        name     => 'source_table',
        type     => 'simple_text',
        index    => 1,
    },
    {
        name     => 'source_id',
        type     => 'system_id',
        index    => 1,
    },
    {
        name     => 'target_table',
        type     => 'simple_text',
        index    => 1,
    },
    {
        name     => 'target_id',
        type     => 'system_id',
        index    => 1,
    },
    {
        name  => 'type',
        type  => 'simple_text',
        index => 1,
    },
    {
        name  => 'metadata',
        type  => 'key_value',
    },
);

BigMed::Pointer->set_schema(
    elements => \@data_schema,
);

###########################################################
# SOURCE/TARGET FETCHERS
###########################################################

sub obj_pointers {
    my $pointer_class = shift;
    my $data_obj = shift;
    my $cache = shift; #optional selection of pointers to select
    my $id = $data_obj->id or croak 'content object has no id';
    my $sid = $data_obj->site or croak 'content object has no site';
    my $pointers = $data_obj->stash('pointers');
    if ( !$pointers ) {    #load the cache
        my $seek = $cache || $pointer_class;
        $pointers = $seek->select(
            {   site         => $sid,
                source_table => $data_obj->data_source,
                source_id    => $id,
            },
          )
          or return undef;
        $data_obj->set_stash( 'pointers', $pointers );
    }
    $pointers;
}

sub reset_obj_cache {
    my $self = shift;
    my $data_obj = shift or return;
    $data_obj->set_stash('pointers', undef);
}

sub fetch_source {
    my $site = $_[0]->site or croak 'No site in pointer';
    my $table = $_[0]->source_table or croak 'No source table in pointer';
    my $id = $_[0]->source_id or croak 'No source id in pointer';
    return BigMed::Data->source_class($table)->fetch({site=>$site,id=>$id}, {limit=>1});
}

sub fetch_target {
    my $site = $_[0]->site or croak 'No site in pointer';
    my $table = $_[0]->target_table or croak 'No target table in pointer';
    my $id = $_[0]->target_id or croak 'No target id in pointer';
    return BigMed::Data->source_class($table)->fetch({site=>$site,id=>$id}, {limit=>1});
}

1;

=head1 NAME

BigMed::Pointer - Big Medium pointer object, for tracking relationships between
data-backed objects.

=head1 DESCRIPTION

BigMed::Pointer enables one object to point at another object, establishing
a relationship between the two objects. This is particularly intended for
use between objects that don't necessarily have monogamous relationships
(a page object can point to multiple media objects which in turn can be
pointed to by other page objects).

These pointer objects also make it easy to find objects that refer to each other
when, for example, updates are required in either linking or linked objects.

=head1 USAGE

BigMed::Pointer is a subclass of BigMed::Data. In addition to the methods 
documented below, please see the BigMed::Data documentation for details about
topics including:

=over 4

=item Creating a new data object

=item Saving a data object

=item Finding and sorting saved data objects

=item Data access methods

=item Error handling

=back

=head1 METHODS

=head2 Data Access Methods

BigMed::Pointer objects hold the following pieces of data. They can be
accessed and set using the standard data access methods described in the
BigMed::Data documentation. See the L<"Searching and Sorting"> section below
for details on the data columns available to search and sort BigMed::Site
objects.

=over 4

=item * id

The numeric ID of the pointer object

=item * site

The numeric ID of the site to which the two objects belong

=item * source_table

The source name where the source (pointing) object is located.

=item * source_id

The numeric ID of the source (pointing) object.

=item * target_table

The source name where the target (pointed) object is located.

=item * target_id

The numeric ID of the target (pointed) object.

=item * type

The relationship type (e.g. author, media, body_link etc). For more info on
relationship types, see e.g. the documentation for BigMed::Content.

=item * metadata

Hash of preference info for this relationship (e.g., info about how and where
to display the target object data on the source object's page).

=item * mod_time

Timestamp for when the last time the object was saved.

=item * create_time

Timestamp for when the object was first created.

=back

=head3 Searching and Sorting

You can look up and sort records by any combination of the following fields.
See the C<fetch> and C<select> documentation in BigMed::Data for more info.

=over 4

=item * id

=item * mod_time

=item * site

=item * source_table

=item * source_id

=item * target_table

=item * target_id

=item * type

=back

=head2 Object Retrieval Methods

=head3 * C<< BigMed::Pointer->obj_pointers($data_obj, $select) >>

Returns a data selection object (see BigMed::Data) with the results
of a search for all pointers pointing from the data object passed
as the argument. The search results are cached (clear the cache
via C<reset_obj_cache>.

The optional second argument is a BigMed::Pointer selection to use
as the base of the pointer search for improved performance.

=head3 * C<< $pointer->fetch_source >>

Returns the source (pointing) object from the data store. Returns an empty
string if the object does not exist, or undef if there's an I/O error.

    defined( $source_obj = $pointer->fetch_source() )
      or $pointer->error_stop;
    unless ($source_obj) {
        #no such object in the data store
    }

=head3 * C<< $pointer->fetch_target >>

Returns the target (pointed) object from the data store. As with C<fetch_source>,
returns an empty string if hte object does not exist, or undef if there's an
I/O error.

    defined( $source_obj = $pointer->fetch_source() )
      or $pointer->error_stop;
    unless ($source_obj) {
        #no such object in the data store
    }

=head2 Utility Methods

=head3 C<< BigMed::Pointer->reset_obj_cache( $obj ) >>

Clears the cache set for the object by the C<obj_pointers> method.

=head1 SEE ALSO

=over 4

=item * BigMed::Data

=item * BigMed::Content

=back

=head1 AUTHOR & COPYRIGHTS

This module and all Big Medium modules are copyright Josh Clark
and Global Moxie. All rights reserved.

Use of this module and the Big Medium content
management system are governed by Global Moxie's software licenses
and may not be used outside of the terms and conditions outlined
there.

For more information, visit the Global Moxie website at
L<http://globalmoxie.com/>.

Big Medium and Global Moxie are service marks of Global Moxie
and Josh Clark. All rights reserved.

=cut
