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

package BigMed::App::Web::PageNav;
use strict;
use warnings;
use utf8;
use base qw(Exporter);
@BigMed::App::Web::PageNav::EXPORT = qw(appweb_pagenav_menu);
use Carp;
$Carp::Verbose = 1;

my $NAV_NDISPLAY = 10;    #max number of menu items

sub appweb_pagenav_menu {
    my $app = shift;      #bigmed::app::web object
    my %arg = @_;

    my ( $offset, $this_total, $total_records, $per_page, $rurl, $previous,
        $next )
      = @arg{
        qw(offset this_total total_records per_page url_callback previous next)
      };
    return ( q{}, q{} ) if !$this_total;

    foreach my $req (qw(total_records per_page url_callback)) {
        croak "appweb_pagenav_menu requires $req argument" if !$arg{$req};
    }

    $offset ||= 0;
    my $browse_start = $offset + 1;
    my $browse_end   = $offset + $this_total;
    my $browse_text  = $app->language(
        [   'EDITOR_Browsing records', $browse_start,
            $browse_end,               $total_records
        ]
    );
    return ( q{}, $browse_text )
      if $total_records <= $this_total;    #only 1 page

    my @buttons;
    my $npages = int( $total_records / $per_page );
    $npages++ if $total_records % $per_page;
    my $pnum = int( $offset / $per_page ) + 1;
    $pnum++ if $offset % $per_page;

    $previous ||= $app->language('BM_Previous');
    my $prev_url = $pnum > 1 ? $rurl->( ( $pnum - 2 ) * $per_page ) : q{};
    push @buttons, { text => $previous, url => $prev_url };

    my ( $p_start, $p_end );
    if ( $npages <= $NAV_NDISPLAY ) {
        $p_start = 1;
        $p_end   = $npages;
    }
    else {
        $p_start =
            $pnum > $NAV_NDISPLAY / 2
          ? $pnum - int( $NAV_NDISPLAY / 2 )
          : 1;
        $p_end = $p_start + $NAV_NDISPLAY - 1;
        if ( $p_end > $npages ) {
            $p_end   = $npages;
            $p_start = $p_end - $NAV_NDISPLAY + 1;
        }
    }
    foreach my $num ( $p_start .. $p_end ) {
        my $navurl = $rurl->( ( $num - 1 ) * $per_page );
        push @buttons,
          { text => $num, url => $navurl, selected => $num == $pnum };
    }

    $next ||= $app->language('BM_Next');
    my $next_url =
        $pnum < $npages
      ? $rurl->( ($pnum) * $per_page )
      : q{};
    push @buttons, { text => $next, url => $next_url };

    my $menu_html = $app->html_template_screen(
        'wi_pagenav_menu.tmpl',
        browse_text => $browse_text,
        buttons     => \@buttons,
    );

    return ( $menu_html, $browse_text );
}

1;

__END__

=head1 BigMed::App::Web::PageNav

Mixin adds a method to BigMed::App::Web objects to generate html
page-navigation menu for multi-page menus.

=head1 SYNOPSIS

    package MyApp;
    use base qw(BigMed::App::Web);
    use BigMed::App::Web::PageNav
    use strict;
    use warnings;
    
    #any BigMed::App::Web subclass
    my $app = MyApp->new();
    
    my ( $menu_html, $browse_text ) = $app->appweb_pagenav_menu(
        offset        => 20,       #zero-based offset from start of full set
        this_total    => 10,       #num shown on current page
        total_records => 97,       #num in full set
        per_page      => $10,      #num to show per page
        url_callback  => \&sub,    #url-builder
    );

    # $menu_html is the html to display
    # $browse_text: "Browsing 21-30 of 97 items"

=head1 DESCRIPTION

This module exports a single method, C<appweb_pagenav_menu>, for use
by an object of any BigMed::App::Web subclass.

=head1 USAGE

C<appweb_pagenav_menu> returns a two-item array:

=over 4

=item 1. The html for the navigation menu (empty string if all items fit
on a single page or if there are no items displayed).

=item 2. Simple sentence describing where you are in the full set of
items: "Browsing 21-30 of 97 items"

=back

The method should be called as an object class with a hash of the following
required arguments:

=over 4

=item * C<<offset => $n>>

Zero-based offset from start of full set (same value as the offset that you
would pass to the BigMed::Data select method to get the collection).

=item * C<<this_total => $n>>

Number of items displayed on the current page.

=item * C<<total_records => $n>>

Total number in full set.

=item * C<<per_page => $n>>

Number of items to display per page.

=item * C<<url_callback => $n>>

Coderef to routine that will return a URL for each page. The routine
receives a single argument, the offset number for the page (zero-based
offset from the start of the full set).

=item * C<<previous => 'Previous'>>

Text to use for the "Previous" link (if none provided, uses the current
BigMed::Language translation).

=item * C<<next => 'Next'>>

Text to use for the "Next" link (if none provided, uses the current
BigMed::Language translation).

=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

