#===============================================================================
#
#  DESCRIPTION: ordered and unordered lists
#
#       AUTHOR:  Aliaksandr P. Zahatski, <zahatski@gmail.com>
#===============================================================================
#$Id$
package Perl6::Pod::Block::item;

=pod

=head1 NAME

Perl6::Pod::Block::item - lists

=head1 SYNOPSIS

     =item  Happy
     =item  Dopey
     =item  Sleepy

     =item1  Animal
     =item2     Vertebrate
     =item2     Invertebrate

=head1 DESCRIPTION

Lists in Pod are specified as a series of contiguous C<=item> blocks. No
special "container" directives or other delimiters are required to
enclose the entire list. For example:

     The seven suspects are:

     =item  Happy
     =item  Dopey
     =item  Sleepy
     =item  Bashful
     =item  Sneezy
     =item  Grumpy
     =item  Keyser Soze

List items have one implicit level of nesting:

Lists may be multi-level, with items at each level specified using the
C<=item1>, C<=item2>, C<=item3>, etc. blocks. Note that C<=item> is just
an abbreviation for C<=item1>. For example:

     =item1  Animal
     =item2     Vertebrate
     =item2     Invertebrate

     =item1  Phase
     =item2     Solid
     =item2     Liquid
     =item2     Gas
     =item2     Chocolate

Note that item blocks within the same list are not physically nested.
That is, lower-level items should I<not> be specified inside
higher-level items:

    =comment WRONG...
    =begin item1          --------------
    The choices are:                    |
    =item2 Liberty        ==< Level 2   |==<  Level 1
    =item2 Death          ==< Level 2   |
    =item2 Beer           ==< Level 2   |
    =end item1            --------------

    =comment CORRECT...
    =begin item1          ---------------
    The choices are:                     |==< Level 1
    =end item1            ---------------
    =item2 Liberty        ==================< Level 2
    =item2 Death          ==================< Level 2
    =item2 Beer           ==================< Level 2

=head2 Ordered lists

An item is part of an ordered list if the item has a C<:numbered>
configuration option:

     =for item1 :numbered
     Visito
    
     =for item2 :numbered
     Veni
   
     =for item2 :numbered
     Vidi
  
     =for item2 :numbered
     Vici

Alternatively, if the first word of the item consists of a single C<#>
character, the item is treated as having a C<:numbered> option:

     =item1  # Visito
     =item2     # Veni
     =item2     # Vidi
     =item2     # Vici


To specify an I<unnumbered> list item that starts with a literal C<#>, either
make the octothorpe verbatim:


    =item V<#> introduces a comment

or explicitly mark the item itself as being unnumbered:

    =for item :!numbered
    # introduces a comment

=head2 Unordered lists

List items that are not C<:numbered> are treated as defining unordered
lists. Typically, such lists are rendered with bullets. For example:

    =item1 Reading
    =item2 Writing
    =item3 'Rithmetic

=head2 Multi-paragraph list items

Use the delimited form of the C<=item> block to specify items that
contain multiple paragraphs. For example:

     Let's consider two common proverbs:
  
     =begin item :numbered
     I<The rain in Spain falls mainly on the plain.>
  
     This is a common myth and an unconscionable slur on the Spanish
     people, the majority of whom are extremely attractive.
     =end item
  
     =begin item :numbered
     I<The early bird gets the worm.>
 
     In deciding whether to become an early riser, it is worth
     considering whether you would actually enjoy annelids
     for breakfast.
     =end item

     As you can see, folk wisdom is often of dubious value.

=head2 Definition lists

    =defn  MAD
    Affected with a high degree of intellectual independence.

    =defn  MEEKNESS
    Uncommon patience in planning a revenge that is worth while.

    =defn
    MORAL
    Conforming to a local and mutable standard of right.
    Having the quality of general expediency.

=head1 METHODS

=cut

use strict;
use warnings;
use Data::Dumper;
use Perl6::Pod::Block;
use base 'Perl6::Pod::Block';
use Perl6::Pod::Utl;

sub new {
    my $class = shift;
    my $self  = $class->SUPER::new(@_);

    #check if item numbered
    #    my $content = $self->{content}->[0];
    if ( $self->{content}->[0] =~ s/^(\s*\#\s*)// ) {

        #set numbered attr
        #TODO $self->set_attr;
        push @{ $self->{attr} },
          {
            ''      => ':numbered',
            'name'  => 'numbered',
            'type'  => 'bool',
            'items' => 1
          };
    }

    # for definition get TERM
    #The first non-blank line of content is treated as a term being defined,
    #and the remaining content is treated as the definition for the term
    if ( $self->item_type eq 'definition' ) {
        my $first_para = $self->{'content'}->[0];
        if ( $first_para =~ s/^\s*(.*)[\r\n]// ) {
            $self->{term} = $1;
        }
        $self->{'content'}->[0] = $first_para;
    }
    return $self;
}

sub item_type {
    my $self = shift;

    #determine item type
    my $pod_attr = $self->get_attr;

    #for defn block name
    return 'definition'
      if $self->name eq 'defn';

    my $type = 'unordered';
    if ( $self->is_numbered ) {
        $type = 'ordered';
    }
    $type;
}

sub is_numbered {
    my $self     = shift;
    my $pod_attr = $self->get_attr;
    return $pod_attr->{numbered} || 0;
}

sub item_level {
    my $self = shift;
    $self->{level} || 1;    #default 1 level for items
}

=head2 to_xhtml

=over 1

=item Unordered lists

  =item Milk
  =item Toilet Paper
  =item Cereal
  =item Bread

  # <ul> - unordered list; bullets
  <ul>
   <li>Milk</li>
   <li>Toilet Paper</li>
   <li>Cereal</li>
   <li>Bread</li>
  </ul>

=item Ordered
    
    =for item :numbered
    Find a Job
    =item # Get Money
    =item # Move Out

  # <ol> - ordered list; numbers (<ol start="4" > for :continued)
    <ol>
     <li>Find a Job</li>
     <li>Get Money</li>
     <li>Move Out</li>
    </ol>

=item  definition list; dictionary

     =defn Fromage
     French word for cheese.
     =defn Voiture
     French word for car.

    * <dl> - defines the start of the list
    * <dt> - definition term
    * <dd> - defining definition

    <dl>
     <dt><strong>Fromage</strong></dt>
     <dd>French word for cheese.</dd>
     <dt><strong>Voiture</strong></dt>
     <dd>French word for car.</dd>
    </dt>

L<http://www.tizag.com/htmlT/lists.php>

=back
   
=cut

sub get_item_sign {
    my $self = shift;
    my $el = shift;
    my $name = $el->name;
    return $name unless $name eq 'item';
    my $sign = join '_'=> $name, $el->item_level, $self->item_type;
    return $sign
}

sub to_xhtml {
    my ( $self, $to, $prev, $next ) = @_;
    my $w = $to->w;


    my ( $list_name, $items_name ) = @{
        {
            ordered    => [ 'ol', 'li' ],
            unordered  => [ 'ul', 'li' ],
            definition => [ 'dl', 'dd' ]
        }->{ $self->item_type }
      };
    if (!$prev || $self->get_item_sign($prev) ne $self->get_item_sign($self) ) {
        #nesting first (only 2> )
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1 ;
            $w->start_nesting(  $tonest  ) if $tonest;
        }

        $w->raw("<$list_name>");
    }
    if ( $self->item_type eq 'definition' ) {
        $w->raw('<dt><strong>');
        $to->visit( Perl6::Pod::Utl::parse_para( $self->{term} ) );
        $w->raw('</strong></dt>')

    }

    #parse first para
    $self->{content}->[0] =
      Perl6::Pod::Utl::parse_para( $self->{content}->[0] );
    $w->raw("<$items_name>");
    $to->visit_childs($self);
    $w->raw("</$items_name>");
    if (!$next || $self->get_item_sign($next) ne $self->get_item_sign($self) ) {
        $w->raw("</$list_name>");
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1  ;
            $w->stop_nesting(  $tonest  ) if $tonest;
        }

    }


}

sub to_docbook {

    #setup first number for ordered lists
    # 'continuation' docbook attribute
    # http://www.docbook.org/tdg/en/html/orderedlist.html
    #        if ( exists $attr->{number_value} ) {
    #            unless ( exists $rattr->{number_start} ) {
    #                $rattr->{number_start} = $attr->{number_value};
    #            }
    #        }
    my ( $self, $to, $prev, $next ) = @_;
    my $w = $to->w;

    my ( $list_name, $items_name ) = @{
        {
            ordered    => [ 'orderedlist',  'listitem' ],
            unordered  => [ 'itemizedlist', 'listitem' ],
            definition => [ 'variablelist', 'listitem' ]
        }->{ $self->item_type }
      };
    if (!$prev || $self->get_item_sign($prev) ne $self->get_item_sign($self) ) {
        #nesting first (only 2> )
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1 ;
            $w->start_nesting(  $tonest  ) if $tonest;
        }

        $w->raw("<$list_name>");
    }

            

    if ( $self->item_type eq 'definition' ) {
        $w->raw('<varlistentry>');
        $to->visit( Perl6::Pod::Utl::parse_para( $self->{term} ) );
        $w->raw('</varlistentry>')

    }

    #parse first para
    $self->{content}->[0] =
      Perl6::Pod::Utl::parse_para( $self->{content}->[0] );
    if ( ( $self->item_type eq 'unordered'  )
                    && 
            ( $self->item_level > 1 )
    ) {
    #marker
    #get list from http://www.sagehill.net/docbookxsl/Itemizedlists.html
    my @markers = qw/bullet opencircle box /;
    my $marker  = $markers[ ($self->item_level - 1) % 3  ];
    $w->raw("<$items_name mark='$marker'>");
    } else {
     $w->raw("<$items_name>");
    }
    $to->visit_childs($self);
    $w->raw("</$items_name>");

    if (!$next || $self->get_item_sign($next) ne $self->get_item_sign($self) ) {
        $w->raw("</$list_name>");
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1  ;
            $w->stop_nesting(  $tonest  ) if $tonest;
        }

    }

}

sub to_latex {
    my ( $self, $to, $prev, $next ) = @_;
    my $w = $to->w;

    my ( $list_name, $items_name ) = @{
        {
            ordered    => [ 'enumerate',  'item' ],
            unordered  => [ 'itemize', 'item' ],
            definition => [ 'description', 'item' ]
        }->{ $self->item_type }
      };
    if (!$prev || $self->get_item_sign($prev) ne $self->get_item_sign($self) ) {
        #nesting first (only 2> )
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1 ;
            $w->start_nesting(  $tonest  ) if $tonest;
        }

    $w->say('\begin{' . $list_name . '}');
    }

    $w->raw('\item');

    if ( $self->item_type eq 'definition' ) {
        $w->raw('[');
        $self->visit( Perl6::Pod::Utl::parse_para( $self->{term} ) );
        $w->raw(']')

    }
    $w->raw(' ');#space

    #parse first para
    $self->{content}->[0] =
      Perl6::Pod::Utl::parse_para( $self->{content}->[0] );
    $to->visit_childs($self);
    if ( $self->get_attr->{pause} ) {
        $w->say('\pause');
    }

    if (!$next || $self->get_item_sign($next) ne $self->get_item_sign($self) ) {
        $w->say('\end{' . $list_name . '}');
        unless (exists $self->get_attr->{nested}) {
            my $tonest = $self->item_level - 1  ;
            $w->stop_nesting(  $tonest  ) if $tonest;
        }

   }
}

1;
__END__


=head1 SEE ALSO

L<http://zag.ru/perl6-pod/S26.html>,
Perldoc Pod to HTML converter: L<http://zag.ru/perl6-pod/>,
Perl6::Pod::Lib

=head1 AUTHOR

Zahatski Aliaksandr, <zag@cpan.org>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2009-2012 by Zahatski Aliaksandr

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.

=cut

