# 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: Context.pm 3043 2008-03-31 14:00:38Z josh $

package BigMed::Context;
use HTML::Template;
use strict;
use utf8;
use Carp;


###########################################################
# CONSTRUCTOR
###########################################################

sub new {
    my $class = shift;
    croak 'usage: $class->new(%params)' if @_ % 2;
    my %param = @_;
    my $site = $param{site};
    if (!$site || !$param{site}->isa('BigMed::Site')) {
        croak 'site object required in BigMed::Context constructor';
    }

    my $section = $param{section};
    if ($section && !ref $section) {
        defined ( $section = $site->section_obj_by_id($section) )
          or return undef;
    }
    
    my $self = {
        site          => $site,
        section       => $section,
        content       => $param{content},
        level         => $param{level},
        remove_detail => $param{remove_detail} || {},
        relation_cache => $param{relation_cache},
    };
    bless $self, $class;
}

###########################################################
# ACCESSORS
###########################################################

sub site { $_[0]->{site} }

sub section { $_[0]->{section} }

sub content { $_[0]->{content} }
sub set_content { $_[0]->{content} = $_[1] }

sub relation_cache { $_[0]->{relation_cache} }
sub set_relation_cache { $_[0]->{relation_cache} = $_[1] }

sub active_descendants { $_[0]->{active_descendants} }
sub set_active_descendants { $_[0]->{active_descendants} = $_[1] }

sub ordered_descendants { $_[0]->{ordered_descendants} }
sub set_ordered_descendants { $_[0]->{ordered_descendants} = $_[1] }

sub level { $_[0]->{level} }

sub format_class { $_[0]->{format_class} }
sub set_format_class { $_[0]->{format_class} = $_[1] }

sub format_name { $_[0]->{format_name} }
sub set_format_name { $_[0]->{format_name} = $_[1] }

sub widget_map { $_[0]->{widget_map} ? %{ $_[0]->{widget_map} } : () }
sub set_widget_map { $_[0]->{widget_map} = $_[1] }

sub detail_templates { $_[0]->{detail_tmpl} ? @{ $_[0]->{detail_tmpl} } : () }
sub set_detail_templates { $_[0]->{detail_tmpl} = $_[1] }

sub level_templates { $_[0]->{detail_tmpl} ? @{ $_[0]->{level_tmpl} } : () }
sub set_level_templates { $_[0]->{level_tmpl} = $_[1] }

sub extras_templates { $_[0]->{extras} ? @{ $_[0]->{extras} } : () }
sub set_extras_templates { $_[0]->{extras} = $_[1] }

sub collectors { $_[0]->{detail_tmpl} ? @{ $_[0]->{collectors} } : () }
sub set_collectors { $_[0]->{collectors} = $_[1] }

sub collector_groups { $_[0]->{cgroups} ? @{ $_[0]->{cgroups} } : () }
sub set_collector_groups { $_[0]->{cgroups} = $_[1] }

sub dirpath { $_[0]->{dirpath} }
sub set_dirpath {  $_[0]->{dirpath} = $_[1] }

sub widget_value {  $_[0]->{inherit}->{$_[1]} }
sub set_widget_value {  $_[0]->{inherit}->{$_[1]} = $_[2] }

sub stash {  $_[0]->{stash}->{$_[1]} }
sub set_stash {  $_[0]->{stash}->{$_[1]} = $_[2] }

sub widget_template_path { $_[0]->{wi_path} }
sub set_widget_template_path { $_[0]->{wi_path} = $_[1] }

sub set_inherit { $_[0]->{inherit} = $_[1] }

sub remove_detail { $_[0]->{remove_detail} ? %{ $_[0]->{remove_detail} } : () }

sub defer_overflow { $_[0]->{defer_overflow} }
sub set_defer_overflow { $_[0]->{defer_overflow} = $_[1] }

sub is_active {
    my $context = shift;
    return $context->{is_active} if defined $context->{is_active};
    
    my $section = $context->section; #assume homepage if no section
    my $is_active = !$section || $context->site->is_section_active($section);
    $is_active ||= 0;
    $context->{is_active} = $is_active;
    return $is_active;
}

###########################################################
# TEMPLATE METHODS
###########################################################

sub build_markup {
    my ( $self, $tmpl_file, %param ) = @_;
    my $path = $param{__alt_path} || $self->widget_template_path;
    my $tmpl = HTML::Template->new(
        filename          => $tmpl_file,
        path              => $path,
        die_on_bad_params => 0,
        cache             => 1,
        loop_context_vars => 1
    );
    $tmpl->param(%param);
    $tmpl->output;
}

###########################################################
# MARKERS
###########################################################

sub mark_homepage() {
    my $context = shift;
    my $obj     = shift;
    $context->{on_homepage}->{ $obj->id } = 1;
}

sub mark_section() { #should call this only for *main* sections
    my $context = shift;
    my $obj     = shift;
    $context->{on_section}->{ $obj->id } = 1;
}

sub on_homepage {
    my $context = shift;
    my $obj = shift;
    return $context->{on_homepage}->{ $obj->id } if defined $obj;
    return %{ $context->{on_homepage} };
}
sub on_section {
    my $context = shift;
    my $obj = shift;
    return $context->{on_section}->{ $obj->id }
      if defined $obj;
    return %{ $context->{on_section} };
}

sub set_on_homepage { $_[0]->{on_homepage} = $_[1]; }
sub set_on_section { $_[0]->{on_section} = $_[1]; }



1;

__END__

=head1 BigMed::Context

=head1 DESCRIPTION

The BigMed::Context object holds information about the current status of the
file-building process and is used by BigMed::Builder and BigMed::Format
to communicate relevant details for building widgets and generating files.

=head1 SYNOPSIS

    my $context = BigMed::Context->new(
        site    => $site_obj,
        section => $section_obj,    #undefined if building top level
        content       => $filtered_content_selection,
        level         => $level,                      # top | section | detail
        remove_detail => {$page_id => 1},             #optional
    );

    
=head1 METHODS

=head2 Construction

=over 4

=item * new

    my $context = BigMed::Context->new(
        site    => $site_obj,
        section => $section_obj,    #undefined if building top level
        content => $filtered_content_selection,
        level   => $level,                        # top | section | detail
        remove_detail => {$page_id => 1},             #optional
    );

Returns a BigMed::Context object. Accepts the following key/value pairs:

=over 4

=item * site => $site_obj

=item * section => $section_obj

Undefined if building the top-level of the site.

=item * content => $filtered_content_selection

The results of a BigMed::Data C<select> method call, containing the
BigMed::Content::Page objects to build for this context.

=item * level => $level

The level of the site to build. Values are: top, section, detail

=item * remove_detail => \%page_id_info

A hash representing the pages whose detail pages should be removed for this
context. The keys are IDs of the BigMed::Content::Page and the values are
true.

=back

=back

=head2 Getters/Setters

=over 4

=item * $context->site

Returns the site object. (Note that there is no setter for the site, this is
set at object construction).

=item * $context->section

Returns the section object (undefined if building the top/homepage level).
(Note that there is no setter for the site, this is set at object
construction).

=item * $context->is_active

Returns true if the current section and all parents are active, false if not.

=item * $context->level

Returns the level currently being built (either 'top' or 'section').
(Note that there is no setter for the site, this is set at object
construction).

=item * $context->content

Returns the content selection of BigMed::Content::Page objects for the
current section/level.

=item * $context->set_content( $selection )

Sets the context's content selection to the argument value.

=item * $context->active_descendants

Returns a reference to a hash, whose keys are the section ids of the active
subsections of the current section, values are true.

=item * $context->set_active_descendants( \%hash )

Sets the context's active_descendants value.

=item * $context->ordered_descendants

Returns a reference to the _all_active_descendants_by_id array for the
current section.

=item * $context->set_ordered_descendants( \@array )

Sets the context's ordered_descendants value.

=item * $context->relation_cache

Returns the cached hash reference of relationship selections
(keyed to class name) for the site.

=item * $context->set_relation_cache( $selection )

Sets the context's relationship selection cache to the argument value.

=item * $context->format_class

Returns the BigMed::Format subclass whose files are currently being built.

=item * $context->set_format_class($class)

Sets the BigMed::Format subclass whose files are currently being built.

=item * $context->format_name

Returns the label name of the BigMed::Format subclass whose files are
currently being built.

=item * $context->set_format_name($name)

Sets the label name of the BigMed::Format subclass whose files are
currently being built.

=item * $context->widget_map

Returns a hash of widget values where the keys are stringified values of
the widget tags and the values are corresponding widget objects.

=item * $context->set_widget_map(\%widget_map)

Sets the widget map to the hash reference in the argument.

=item * $context->detail_templates

Returns an array of all detail-level template references for the current
format in the current section. These template references are the same type
of hash references that you get via BigMed::Format's C<templates> method.

=item * $context->set_detail_templates

Sets the context's detail_templates value to the array reference in the
argument.

=item * $context->level_templates

Returns an array of the level templates for the current level (either "top"
or "section") in the current format and section. These template references are
the same type of hash references that you get via BigMed::Format's
C<templates> method.

=item * $context->set_level_templates(\@templates)

Sets the context's level_templates value to the array reference in the
argument.

=item * $context->extras_templates

Returns an array of the current level/format templates that have level_extras
callbacks registered. These template references are the same type of hash
references that you get via BigMed::Format's C<templates> method.

=item * $context->set_extras_templates(\@templates)

Sets the context's extras_templates value to the array reference in the
argument.

=item * $context->collectors

Returns an array of collector widget objects to gather for this context,
sorted in descending order of priority.

=item * $context->set_collectors(\@collectors)

Sets the context's collectors value to the array reference in the
argument.

=item * $context->collector_groups

Returns an array of all collector groups included in the active selection
of collector widgets.

=item * $context->set_collector_groups(\@groups)

Sets the context's collector_groups value to the array reference in the
argument.

=item * $context->stash($key)

Returns the value associated with the argument $key from the context's
stash.

=item * $context->set_stash($key, $value)

Set any arbitrary value for any arbitrary key. A handy way to store
values for the current context setting.

=item * $context->dirpath

Returns the directory path to build files for the current context.

=item * $context->set_dirpath($path)

Sets the directory path to build files for the current context.

=item * $context->widget_value($widget_name)

Returns the cached value, if any, for the systemwide or sectionwide widget
named in the first argument.

=item * $context->set_widget_value($widget_name, $value)

Caches the value for the systemwide or sectionwide widget named in the first
argument.

=item * $context->set_inherit(\%widget_value)

Sets the hash of cached widget values available via C<widget_value>
(basically a way to do a bunch of set_widget_value calls in one fell
swoop). Overwrites any existing widget values.

=item * $context->remove_detail()

Returns a hash indicating which pages to remove for this context. The keys
are IDs of BigMed::Content::Page objects and the values are true.

=item * $context->defer_overflow()

Returns true if the section is currently set to defer building of overflow
link pages.

=item * $context->set_defer_overflow(1)

Sets the value of the defer_overflow flag to the value of the argument.

=back

=head2 HTML::Template Access

=over 4

=item * $context->build_markup($template_file, %template_param)

Runs the template_param hash through the template file specified in
the first argument, via HTML::Template and returns the result string.
Since the context object is available to widget assemblers and handlers,
this is the best way to pour widget data into templates.

By default, the templates from the format-specific template directory
are used, but you can specify an alternate directory path (which is passed
to HTML::Template) by entering it in a __alt_path parameter in the
parameter hash.

=item * $context->widget_template_path

Returns the widget_template_path value to supply to HTML::Template's
path parameter.

=item * $context->set_widget_template_path

Sets the object's widget_template_path value.

=back

=head2 Marker Methods

=over 4

=item * $context->mark_homepage->($obj)

Sets a flag to note that this object is part of the main list of homepage
links.

=item * $context->mark_section->($obj)

Sets a flag to note that this object appears on the main list of links on the
main parent section page (that is, the top-level section) of the current
section.

=item * $boolean = $context->on_homepage($obj)

Returns true if the object has been marked as being part of the main list
of homepage links.

=item * $boolean = $context->on_section($obj)

Returns true if the object has been marked as being part of the main list
of links of the main, top-level section parent of the current section.

=item * $context->set_on_homepage(\%on_homepage)

Sets the context's on_homepage map to the hash reference in the argument.
The keys are the object IDs that are part of the main list of homepage
links and the values are true.

=item * $context->set_on_section(\%on_section)

Sets the context's on_section map to the hash reference in the argument.
The keys are the object IDs that are part of the current section's main list
of links and the values are true.

=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

