package TWiki::Plugins::TablePlugin;
# Plugin for TWiki Collaboration Platform, http://TWiki.org/
#
# Copyright (C) 2001-2003 John Talintyre, jet@cheerful.com
# Copyright (C) 2001-2004 Peter Thoeny, peter@thoeny.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details, published at
# http://www.gnu.org/copyleft/gpl.html
#
# =========================
#
#
# Allow sorting of tables, plus setting of background colour for headings and data cells
# see TWiki.TablePlugin for details of use


# =========================

use Time::Local;


# =========================

sub new { 
	my $dummy = shift;
	my $config = shift;
	unshift @_,$dummy ;

   my ( $proto ) =@_ ;
   my $class = ref($proto) || $proto ;
   my $self;

	$self->{config}=$config;
   bless ( $self );

	$self->init_config();

   return $self ;
}



sub init_config { 

   my $self = shift;
	my $config = $self->{config} ;


$config->{TWiki}->{Plugins}->{TablePlugin}->{VERSION} = '1.013';  # 01 Aug 2004
$config->{TWiki}->{Plugins}->{TablePlugin}->{translationToken} = "\0";
$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre} = "";
$config->{TWiki}->{Plugins}->{TablePlugin}->{upchar} = "";
$config->{TWiki}->{Plugins}->{TablePlugin}->{downchar} = "";
$config->{TWiki}->{Plugins}->{TablePlugin}->{diamondchar} = "";
@{$config->{TWiki}->{Plugins}->{TablePlugin}->{isoMonth}}     = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );
{ my $count = 0;
  %{$config->{TWiki}->{Plugins}->{TablePlugin}->{mon2num}} = map { $_ => $count++ } @{$config->{TWiki}->{Plugins}->{TablePlugin}->{isoMonth}};
}
@{$config->{TWiki}->{Plugins}->{TablePlugin}->{fields}} = ( "text", "attributes", "th td X", "numbers", "dates" );

}# END of init_config
# X means a spanned cell

# =========================
sub initPlugin
{ 
   my $self = shift;
	my $config = $self->{config} ;


 
	 $config->{TWiki}->{Plugins}->{TablePlugin}->init_config () ;

    ( $config->{TWiki}->{Plugins}->{TablePlugin}->{topic}, $config->{TWiki}->{Plugins}->{TablePlugin}->{web}, $config->{TWiki}->{Plugins}->{TablePlugin}->{user}, $config->{TWiki}->{Plugins}->{TablePlugin}->{installWeb} ) = @_;

    # check for Plugins.pm versions
    if( $config->{TWiki}->{Plugins}->{VERSION} < 1 ) {
        $config->{TWiki}->{Func}->writeWarning ( "Version mismatch between TablePlugin and Plugins.pm" );
        return 0;
    }

    # Get plugin debug flag
    $config->{TWiki}->{Plugins}->{TablePlugin}->{debug} = $config->{TWiki}->{Func}->getPreferencesFlag ( "TABLEPLUGIN_DEBUG" );

    $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} = 0;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount} = 0;

    $config->{TWiki}->{Plugins}->{TablePlugin}->{twoCol} = 1;

    my $cgi = $config->{TWiki}->{Func}->getCgiQuery ();
    if( ! $cgi ) {
        return 0;
    }

    my $plist = $cgi->query_string();
    $plist =~ s/\;/\&/go;
    $plist =~ s/\&?sortcol.*up=[0-9]+\&?//go;
    $plist .= "\&" if $plist;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{url} = $cgi->url . $cgi->path_info() . "?" . $plist;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{url} =~ s/\&/\&amp;/go;

    $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} = $cgi->param( 'sortcol' );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{requestedTable} = $cgi->param( 'table' );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{up} = $cgi->param( 'up' );

    $config->{TWiki}->{Plugins}->{TablePlugin}->{doBody} = 0;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{doAttachments} = 0;
    my $tmp = $config->{TWiki}->{Func}->getPreferencesValue ( "TABLEPLUGIN_SORT" );
    if( ! $tmp || $tmp =~ /^all$/oi ) {
        $config->{TWiki}->{Plugins}->{TablePlugin}->{doBody} = 1;
        $config->{TWiki}->{Plugins}->{TablePlugin}->{doAttachments} = 1;
    } elsif( $tmp =~ /^attachments$/oi ) {
        $config->{TWiki}->{Plugins}->{TablePlugin}->{doAttachments} =1;
    }

    $config->{TWiki}->{Plugins}->{TablePlugin}->{pluginAttrs} = $config->{TWiki}->{Func}->getPreferencesValue ( "TABLEPLUGIN_TABLEATTRIBUTES" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{prefsAttrs}  = $config->{TWiki}->{Func}->getPreferencesValue ( "TABLEATTRIBUTES" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->setDefaults () ;

    # Plugin correctly initialized
    $config->{TWiki}->{Func}->writeDebug ( "- $config->{TWiki}->{Plugins}->{TablePlugin}->initPlugin ( $config->{TWiki}->{Plugins}->{TablePlugin}->{web}.$config->{TWiki}->{Plugins}->{TablePlugin}->{topic} ) is OK" ) if $config->{TWiki}->{Plugins}->{TablePlugin}->{debug};
    return 1;
}

# =========================
sub outsidePREHandler
{ 
   my $self = shift;
	my $config = $self->{config} ;


### my ( $text ) = @_;   # do not uncomment, use $_[0] instead

    #$config->{TWiki}->{Func}->writeDebug ( "- TablePlugin::outsidePREHandler( $config->{TWiki}->{Plugins}->{TablePlugin}->{web}.$config->{TWiki}->{Plugins}->{TablePlugin}->{topic} )" ) if $config->{TWiki}->{Plugins}->{TablePlugin}->{debug};

    # Table of format: | cell | cell |
    # PTh 25 Jan 2001: Forgiving syntax, allow trailing white space
    $_[0] =~ s/%TABLE{(.*)}%/$config->{TWiki}->{Plugins}->{TablePlugin}->handleTableAttrs ($1)/eo;
    if( $_[0] =~ /^(\s*)\|.*\|\s*$/ ) {
        $_[0] =~ s/^(\s*)\|(.*)/$config->{TWiki}->{Plugins}->{TablePlugin}->processTR ($1,$2)/eo;
        $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} = 1;
    } elsif( $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} ) {
        $_[0] = $config->{TWiki}->{Plugins}->{TablePlugin}->emitTable ()  . "$_[0]";
        $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} = 0;
        undef $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort};
    }

    # This handler is called by getRenderedVersion, in loop outside of <PRE> tag.
    # This is the place to define customized rendering rules.
    # Note: This is an expensive function to comment out.
    # Consider startRenderingHandler instead
}

# =========================
sub endRenderingHandler
{ 
   my $self = shift;
	my $config = $self->{config} ;


### my ( $text ) = @_;   # do not uncomment, use $_[0] instead

    #$config->{TWiki}->{Func}->writeDebug ( "- TablePlugin::endRenderingHandler( $config->{TWiki}->{Plugins}->{TablePlugin}->{web}.$config->{TWiki}->{Plugins}->{TablePlugin}->{topic} )" ) if $config->{TWiki}->{Plugins}->{TablePlugin}->{debug};

    # This handler is called by getRenderedVersion just after the line loop
    if( $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} ) {
        $_[0] .= $config->{TWiki}->{Plugins}->{TablePlugin}->emitTable () ;
        $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} = 0;
        undef $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort};
    }
    if( $_[0] =~/tablepluginfixlinkcolor/ ) {
         $_[0] =~ s/(<font )tablepluginfixlinkcolor.*?(color=\")([^\"]*)(\">.*?<\/font>)/$config->{TWiki}->{Plugins}->{TablePlugin}->fixLinkColor ("$1$2$3$4",$3)/geo;
    }
}

# =========================
sub setDefaults
{ 
   my $self = shift;
	my $config = $self->{config} ;


    $config->{TWiki}->{Plugins}->{TablePlugin}->{doSort}       = $config->{TWiki}->{Plugins}->{TablePlugin}->{doBody};
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableBorder}  = 1;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableFrame}   = "";
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableRules}   = "";
    $config->{TWiki}->{Plugins}->{TablePlugin}->{cellSpacing}  = 1;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{cellPadding}  = 0;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableWidth}   = "";
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{columnWidths}} = ( );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows}   = 1;
    $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows}   = 0;
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{headerAlign}}  = ( );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataAlign}}    = ( );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign}       = "";
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerBg}     = "#99CCCC";
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerColor}  = "";
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataBg}}       = ( "#FFFFCC", "#FFFFFF" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataColor}}    = ( );
    undef $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort};

    $config->{TWiki}->{Plugins}->{TablePlugin}->handleTableAttrs ( $config->{TWiki}->{Plugins}->{TablePlugin}->{pluginAttrs} );  # Plugin setting
    $config->{TWiki}->{Plugins}->{TablePlugin}->handleTableAttrs ( $config->{TWiki}->{Plugins}->{TablePlugin}->{prefsAttrs} );   # Preferences setting
}

# =========================
# Table attributes defined as a Plugin setting, a preferences setting
# e.g. in WebPreferences or as a %TABLE{...}% setting
sub handleTableAttrs
{ 
   my $self = shift;
	my $config = $self->{config} ;


    my( $args ) = @_;

    return "" if( $args =~/^\s*$/ );

    #Defines which column to initially sort : ShawnBradford 20020221
    my $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "initsort" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort} = $tmp if ( $tmp );

    #Defines which direction to sort the column set by initsort : ShawnBradford 20020221
    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "initdirection" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{initDirection} = 0 if( $tmp =~/^down$/i );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{initDirection} = 1 if( $tmp =~/^up$/i );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "sort" );
    $tmp = "0" if( $tmp =~ /^off$/oi );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{doSort} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "tableborder" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableBorder} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "tableframe" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableFrame} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "tablerules" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableRules} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "cellpadding" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{cellPadding} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "cellspacing" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{cellSpacing} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "headeralign" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{headerAlign}} = split( /,\s*/, $tmp ) if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "dataalign" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataAlign}} = split( /,\s*/, $tmp ) if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "tablewidth" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{tableWidth} = $tmp if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "columnwidths" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{columnWidths}} = split ( /, */, $tmp ) if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "headerrows" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} = $tmp if( $tmp ne "" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} = 1 if( $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} < 1 );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "footerrows" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} = $tmp if( $tmp ne "" );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "valign" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign} = $tmp if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "headerbg" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerBg} = $tmp if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "headercolor" );
    $config->{TWiki}->{Plugins}->{TablePlugin}->{headerColor} = $tmp if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "databg" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataBg}} = split( /,\s*/, $tmp ) if( $tmp );

    $tmp = $config->{TWiki}->{Func}->extractNameValuePair ( $args, "datacolor" );
    @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataColor}} = split( /,\s*/, $tmp ) if( $tmp );

    return "$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre}<nop>";
}

# =========================
# Convert text to number and date if possible
sub getTypes
{ 
   my $self = shift;
	my $config = $self->{config} ;


    my( $text ) = @_;

    $text =~ s/&nbsp;/ /go;

    my $num = undef;
    my $date = undef;
    if( $text =~ /^\s*$/ ) {
        $num = 0;
        $date = 0;
    }

    if( $text =~ m|^\s*([0-9]{1,2})[-\s/]*([A-Z][a-z][a-z])[-\s/]*([0-9]{4})\s*-\s*([0-9][0-9]):([0-9][0-9])| ) {
        # "31 Dec 2003 - 23:59", "31-Dec-2003 - 23:59", "31 Dec 2003 - 23:59 - any suffix"
        $date = timegm(0, $5, $4, $1, $config->{TWiki}->{Plugins}->{TablePlugin}->{mon2num}{$2}, $3 - 1900);
    } elsif( $text =~ m|^\s*([0-9]{1,2})[-\s/]([A-Z][a-z][a-z])[-\s/]([0-9]{2,4})\s*$| ) {
        # "31 Dec 2003", "31 Dec 03", "31-Dec-2003", "31/Dec/2003"
        my $year = $3;
        $year += 1900 if( length( $year ) == 2 && $year > 80 );
        $year += 2000 if( length( $year ) == 2 );
        $date = timegm( 0, 0, 0, $1, $config->{TWiki}->{Plugins}->{TablePlugin}->{mon2num}{$2}, $year - 1900 );
    } elsif ( $text =~ /^\s*[0-9]+(\.[0-9]+)?\s*$/ ) {
        $num = $text;
    }

    return( $num, $date );
}

# =========================
sub processTR { 
   my $self = shift;
	my $config = $self->{config} ;


    my ( $thePre, $theRow ) = @_;

    $config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre} = $thePre || "";
    my $attr = "";
    my $span = 0;
    my $l1 = 0;
    my $l2 = 0;
    if( ! $config->{TWiki}->{Plugins}->{TablePlugin}->{insideTABLE} ) {
        @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = ();
        @{$config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}} = ();
        $config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount}++;
    }
    $theRow =~ s/\t/   /go;  # change tabs to space
    $theRow =~ s/\s*$//o;    # remove trailing spaces
    $theRow =~ s/(\|\|+)/$config->{TWiki}->{Plugins}->{TablePlugin}->{translationToken} . length($1) . "\|"/geo;  # calc COLSPAN
    my $colCount = 0;
    my @row = ();
    $span = 0;
    my $value = "";
    foreach( split( /\|/, $theRow ) ) {
        $colCount++;
        $attr = "";
        $span = 1;
        #AS 25-5-01 Fix to avoid matching also single columns
        if ( s/$config->{TWiki}->{Plugins}->{TablePlugin}->{translationToken}([0-9]+)// ) {
            $span = $1;
            $attr = " colspan=\"$span\"" ;
        }
        s/^\s+$/ &nbsp; /o;
        /^(\s*).*?(\s*)$/;
        $l1 = length( $1 || "" );
        $l2 = length( $2 || "" );
        if( $l1 >= 2 ) {
            if( $l2 <= 1 ) {
                $attr .= ' align="right"';
            } else {
                $attr .= ' align="center"';
            }
        }
        if( defined $config->{TWiki}->{Plugins}->{TablePlugin}->{columnWidths}[$colCount-1] && $config->{TWiki}->{Plugins}->{TablePlugin}->{columnWidths}[$colCount-1] && $span <= 2 ) {
            $attr .= ' width="' . $config->{TWiki}->{Plugins}->{TablePlugin}->{columnWidths}[$colCount-1] . '"';
        }
        if( /^\s*\^\s*$/ ) { # row span above
            $config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$colCount-1]++;
            push @row, [ $value, "", "X" ];
        } else {
            for (my $col = $colCount-1; $col < ($colCount+$span-1); $col++) {
                if( defined($config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$col]) && $config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$col] ) {
                    my $nRows = scalar(@{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}});
                    my $rspan = $config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$col]+1;
                    $config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}[$nRows-$rspan][$col][1] .= " rowspan=\"$rspan\"";
                    undef($config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$col]);
                }
            }
            if( /^\s*\*(.*)\*\s*$/ ) {
                $value = $1;
                if( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{headerAlign}} ) {
                    my $align = @{$config->{TWiki}->{Plugins}->{TablePlugin}->{headerAlign}}[($colCount - 1) % ($#{$config->{TWiki}->{Plugins}->{TablePlugin}->{headerAlign}} + 1) ];
                    $attr .= " align=\"$align\""; # override $attr
                }

                $attr .= " valign=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign}\"" if $config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign};
                $attr .= " class=\"twikiFirstCol\"" if $colCount == 1;
                push @row, [ $value, "$attr", "th" ];
            } else {
                if( /^\s*(.*?)\s*$/ ) {   # strip white spaces
                    $_ = $1;
                }
                $value = $_;
                if( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataAlign}} ) {
                    my $align = @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataAlign}}[($colCount - 1) % ($#{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataAlign}} + 1) ];
                    $attr .= " align=\"$align\""; # override $attr
                }
                $attr .= " valign=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign}\"" if $config->{TWiki}->{Plugins}->{TablePlugin}->{vAlign};
                $attr .= " class=\"twikiFirstCol\"" if $colCount == 1;
                push @row, [ $value, "$attr", "td" ];
            }
        }
        while( $span > 1 ) {
            push @row, [ $value, "", "X" ];
            $colCount++;
            $span--;
        }
    }
    push @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}}, \@row;
    return "$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre}<nop>"; # Avoid TWiki converting empty lines to new paras
}

# =========================
# Do sort?
sub doIt
{ 
   my $self = shift;
	my $config = $self->{config} ;


    my( $header ) = @_;

    # Attachments table?
    if( $header->[0]->[0] =~ /FileAttachment/ ) {
        return $config->{TWiki}->{Plugins}->{TablePlugin}->{doAttachments};
    }

    my $doIt = $config->{TWiki}->{Plugins}->{TablePlugin}->{doSort};
    if( $config->{TWiki}->{Plugins}->{TablePlugin}->{doSort} ) {
        # All cells in header are headings?
        foreach my $cell ( @$header ) {
            if( $cell->[2] ne "th" ) {
                $doIt = 0;
                last;
            }
        }
    }

    return $doIt;
}

# =========================
# Is a colum a date (4), number (3) or text (0)?
sub colType
{ 
   my $self = shift;
	my $config = $self->{config} ;


   my( $col ) = @_;
   my $isDate = 1;
   my $isNum  = 1;
   my $num = "";
   my $date = "";
   foreach my $row ( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} ) {
       ( $num, $date ) = $config->{TWiki}->{Plugins}->{TablePlugin}->getTypes ( $row->[$col]->[0] );
       $isDate = 0 if( ! defined( $date ) );
       $isNum  = 0 if( ! defined( $num ) );
       last if( !$isDate && !$isNum );
       $row->[$col]->[4] = $date;
       $row->[$col]->[3] = $num;
   }

   if( $isDate ) {
       return 4;
   } elsif( $isNum ) {
       return 3;
   } else {
       return 0;
   }
}


# =========================
sub stripHtml
{ 
   my $self = shift;
	my $config = $self->{config} ;


   my( $text ) = @_;
   $text =~ s/\&nbsp;/ /go;                     # convert space
   $text =~ s/\[\[[^\]]+\]\[([^\]]+)\]\]/$1/go; # extract label from [[...][...]] link
   $text =~ s/<[^>]+>//go;                      # strip HTML
   $text =~ s/^ *//go;                          # strip leading space space
   $text = lc( $text );                         # convert to lower case
   return $text;
}

# =========================
sub emitTable
{ 
   my $self = shift;
	my $config = $self->{config} ;


    #Validate headerrows/footerrows and modify if out of range
    if ( $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} > @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} ) {
        $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} = @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}}; # limit header to size of table!
    }
    if ( $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} + $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} > @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} ) {
        $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} = @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} - $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows}; # and footer to whatever is left
    }
    my $direction = $config->{TWiki}->{Plugins}->{TablePlugin}->{up} ? 0 : 1;
    my $doIt = $config->{TWiki}->{Plugins}->{TablePlugin}->doIt ( $config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}[$config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows}-1] );
    my $text = "$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre}<table border=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{tableBorder}\"";
    $text .= " frame=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{tableFrame}\"" if( $config->{TWiki}->{Plugins}->{TablePlugin}->{tableFrame} );
    $text .= " cellspacing=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{cellSpacing}\" cellpadding=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{cellPadding}\"";
    $text .= " rules=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{tableRules}\"" if( $config->{TWiki}->{Plugins}->{TablePlugin}->{tableRules} );
    $text .= " width=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{tableWidth}\"" if( $config->{TWiki}->{Plugins}->{TablePlugin}->{tableWidth} );
    $text .= ">\n";
    my $type = "";
    my $attr = "";
    my $stype = "";

    #Flush out any remaining rowspans
    for (my $i = 0; $i < @{$config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}}; $i++) {
        if( defined($config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$i]) && $config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$i] ) {
            my $nRows = scalar(@{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}});
            my $rspan = $config->{TWiki}->{Plugins}->{TablePlugin}->{rowspan}[$i]+1;
            my $row = $nRows - $rspan;
            $config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}[$row][$i][1] .= " rowspan=\"$rspan\"";
        }
    }

    #Added to aid initial sorting direction and column : ShawnBradford 20020221
    if ( defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} ) ) {
        undef $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort};
    } elsif( defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort} ) ) {
        $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} = $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort} - 1;
        $config->{TWiki}->{Plugins}->{TablePlugin}->{up} = $config->{TWiki}->{Plugins}->{TablePlugin}->{initDirection};
        $direction = $config->{TWiki}->{Plugins}->{TablePlugin}->{up} ? 0 : 1;
        $config->{TWiki}->{Plugins}->{TablePlugin}->{requestedTable} = $config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount};
    }

    if(   ( (defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} ) && defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{requestedTable} ) && $config->{TWiki}->{Plugins}->{TablePlugin}->{requestedTable} eq $config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount} ) )
       || ( defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{initSort} ) ) ) {

        # DG 08 Aug 2002: Allow multi-line headers
        my @header = splice( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}}, 0, $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} );
        # DG 08 Aug 2002: Skip sorting any trailers as well
        my @trailer = ();
        if ( $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} && scalar( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} ) > $config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} ) {
            @trailer = splice( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}}, -$config->{TWiki}->{Plugins}->{TablePlugin}->{footerRows} );
        }

        $stype = $config->{TWiki}->{Plugins}->{TablePlugin}->colType ( $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} );
        $config->{TWiki}->{Func}->writeDebug ( "- TWiki::Plugins::TablePlugin sorting col $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} as $config->{TWiki}->{Plugins}->{TablePlugin}->{fields}[$stype]" ) if $config->{TWiki}->{Plugins}->{TablePlugin}->{debug};
        if( $stype ) {
            if( $config->{TWiki}->{Plugins}->{TablePlugin}->{up} ) {
                @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = sort { $b->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[$stype] <=> $a->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[$stype] } @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}};
            } else {
                @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = sort { $a->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[$stype] <=> $b->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[$stype] } @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}};
            }

        } else {
            if( $config->{TWiki}->{Plugins}->{TablePlugin}->{up} ) {
                # efficient way of sorting stripped HTML text
                @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = map { $_->[0] }
                            sort { $b->[1] cmp $a->[1] }
                            map { [ $_, $config->{TWiki}->{Plugins}->{TablePlugin}->stripHtml ( $_->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[0] ) ] } @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}};
            } else {
                @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = map { $_->[0] }
                            sort { $a->[1] cmp $b->[1] }
                            map { [ $_, $config->{TWiki}->{Plugins}->{TablePlugin}->stripHtml ( $_->[$config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol}]->[0] ) ] } @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}};
            }
        }
        # DG 08 Aug 2002: Cleanup after the header/trailer splicing
        # this is probably awfully inefficient - but how big is a table?
        @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} = ( @header, @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}}, @trailer );
    }
    my $rowCount = 0;
    my $dataColorCount = 0;
    my $resetCountNeeded = 0;
    my $arrow = "";
    my $color = "";
    foreach my $row ( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{curTable}} ) {
        $text .= "$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre}<tr>";
        my $colCount = 0;
        foreach my $fcell ( @$row ) {
            $arrow = "";
            next if( $fcell->[2] eq "X" ); # data was there so sort could work with col spanning
            $type = $fcell->[2];
            my $cell = $fcell->[0];
            my $attr = $fcell->[1];
            if( $type eq "th" ) {
               # reset data color count to start with first color after each table heading
               $dataColorCount = 0 if( $resetCountNeeded );
               $resetCountNeeded = 0;
               if( ! $config->{TWiki}->{Plugins}->{TablePlugin}->{upchar} ) {
                   # Added arrow images for up and down S. Bradford 20011018
                   # PTh 13 Nov 2001: Modfied and moved to TablePlugin attachment
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{upchar} = "<img src=\"%PUBURL%/$config->{TWiki}->{Plugins}->{TablePlugin}->{installWeb}/TablePlugin/up.gif\""
                           . " alt=\"up\" />";
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{upchar} = $config->{TWiki}->{Func}->expandCommonVariables ( $config->{TWiki}->{Plugins}->{TablePlugin}->{upchar}, $config->{TWiki}->{Plugins}->{TablePlugin}->{topic} );
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{downchar} = "<img src=\"%PUBURL%/$config->{TWiki}->{Plugins}->{TablePlugin}->{installWeb}/TablePlugin/down.gif\""
                             . " alt=\"down\" />";
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{downchar} = $config->{TWiki}->{Func}->expandCommonVariables ( $config->{TWiki}->{Plugins}->{TablePlugin}->{downchar}, $config->{TWiki}->{Plugins}->{TablePlugin}->{topic} );
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{diamondchar} = "<img src=\"%PUBURL%/$config->{TWiki}->{Plugins}->{TablePlugin}->{installWeb}/TablePlugin/diamond.gif\""
                                . " border=\"0\" alt=\"sort\" />";
                   $config->{TWiki}->{Plugins}->{TablePlugin}->{diamondchar} = $config->{TWiki}->{Func}->expandCommonVariables ( $config->{TWiki}->{Plugins}->{TablePlugin}->{diamondchar}, $config->{TWiki}->{Plugins}->{TablePlugin}->{topic} );
               }

               # DG: allow headers without b.g too (consistent and yes, I use this)
               $attr .= " bgcolor=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{headerBg}\"" unless( $config->{TWiki}->{Plugins}->{TablePlugin}->{headerBg} =~ /none/i );
               my $dir = 0;
               $dir = $direction if( defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} ) && $colCount == $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} );
               if( defined( $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} ) && $colCount == $config->{TWiki}->{Plugins}->{TablePlugin}->{sortCol} && $stype ne "" ) {
                   $arrow = "<a name=\"sorted_table\"><span title=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{fields}[$stype] ";
                   if( $dir == 0 ) {
                       $arrow .= "sorted ascending\">$config->{TWiki}->{Plugins}->{TablePlugin}->{upchar}</span></a>";
                       $attr .= " class=\"twikiSortedAscendingCol\"";
                   } else {
                       $arrow .= "sorted descending\">$config->{TWiki}->{Plugins}->{TablePlugin}->{downchar}</span></a>";
                       $attr .= " class=\"twikiSortedDescendingCol\"";
                   }
               }
               $color = "";
               $color = "<font tablepluginfixlinkcolor=\"on\" color=\"$config->{TWiki}->{Plugins}->{TablePlugin}->{headerColor}\">" if( $config->{TWiki}->{Plugins}->{TablePlugin}->{headerColor} );
               if( $doIt && $rowCount == $config->{TWiki}->{Plugins}->{TablePlugin}->{headerRows} - 1 ) {
                  if( $cell =~ /\[\[|href/o ) {
                     $cell = "$color $cell</font>" if( $color );
                     $cell .= " <a href=\"" . $config->{TWiki}->{Plugins}->{TablePlugin}->{url}
                           . "sortcol=$colCount&amp;table=$config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount}&amp;up=$dir#sorted_table\" "
                           . "title=\"Sort by this column\">$config->{TWiki}->{Plugins}->{TablePlugin}->{diamondchar}</a>$arrow";
                  } else {
                     $cell = "<a href=\"" . $config->{TWiki}->{Plugins}->{TablePlugin}->{url}
                           . "sortcol=$colCount&amp;table=$config->{TWiki}->{Plugins}->{TablePlugin}->{tableCount}&amp;up=$dir#sorted_table\" "
                           . "title=\"Sort by this column\">$color $cell";
                     $cell .= "</font>" if( $color );
                     $cell .= "</a> $arrow";
                  }
               } else {
                  $cell = " *$color$cell";
                  $cell .= "</font>" if( $color );
                  $cell .= "* ";
               }

            } else {
               $resetCountNeeded = 1 if( $colCount == 0 );
               if( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataBg}} ) {
                   $color = $config->{TWiki}->{Plugins}->{TablePlugin}->{dataBg}[$dataColorCount % ($#{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataBg}} + 1) ];
                   $attr .= " bgcolor=\"$color\"" unless( $color =~ /none/i );
               }
               $color = "";
               if( @{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataColor}} ) {
                   $color = $config->{TWiki}->{Plugins}->{TablePlugin}->{dataColor}[$dataColorCount % ($#{$config->{TWiki}->{Plugins}->{TablePlugin}->{dataColor}} + 1) ];
                   if( $color =~ /^(|none)$/i ) {
                       $color = "";
                   } else {
                       $color = "<font color=\"$color\">";
                   }
               }
               $cell = "$color $cell ";
               $cell .= "</font>" if( $color );
            }
            $text .= "<$type$attr>$cell";
            $text .= "</$type>";
            $colCount++;
        }
        $text .= "</tr>\n";
        $rowCount++;
        $dataColorCount++;
    }
    $text .= "$config->{TWiki}->{Plugins}->{TablePlugin}->{currTablePre}</table>\n";
    $config->{TWiki}->{Plugins}->{TablePlugin}->setDefaults () ;
    return $text;
}

# =========================
sub fixLinkColor
{ 
   my $self = shift;
	my $config = $self->{config} ;


   my( $text, $color ) = @_;
   # Hack to solve color problem of links produced after table rendering
   $color = "<font color=\"$color\">";
   $text =~ s|(<a href=\".*?\">)(.*?)(</a>)|</font>$1$color$2</font>$3$color|go;
   $text =~ s|$color\s*</font>||go;
   return $text;
}

# =========================
1;

1;
