package CLI::TabBar;

use vars qw($VERSION);
$VERSION = '0.7';

use Carp;
use Text::Wrap;
use Text::Tabs qw(expand unexpand);
use strict;

sub new {
  my $proto = shift;
  my $self = { };

  bless($self, $proto);

  $self->{CurrentTab} = "";
  $self->{order} = [];
  $self->{rows} = [];

  $self->{screenHeight} = $main::GUI{maxY} - 2 - $self->Height();
  $main::GUI{window}->setscrreg($self->Height(),$main::GUI{maxY}-2);

  return $self;
}


sub Refresh {
  my $cw = shift;

  $cw->RecalculatePositions();
  $cw->DrawTabs();
  $cw->RaiseTab($cw->{vars}->{CurrentTab},1);
}


sub Height {
  my $self = shift;
  return $#{$self->{rows}} + 1;
}


sub RecalculatePositions {
  my $self = shift;

  my $row = 0;
  my $col = 0;
  my $x = 1;

  $self->{rows} = ();

  my $width = $main::GUI{maxX} - 1;

  my $order = 0;
  foreach my $index (0..$#{$self->{order}}) {
    my $tag = $self->{order}->[$index];
    next if ($self->{tags}->{$tag}->{hidden} == 1);
    $self->CharacterizeTab($tag,$order);
    $order++;

    if ((($x + $self->{tags}->{$tag}->{width}) > $width) &&
	($col != 0)) {
      $col = 0;
      $row++;
      $x = 1;
    }

    $self->{tags}->{$tag}->{row} = $row;
    $self->{tags}->{$tag}->{realRow} = $row;
    $self->{tags}->{$tag}->{col} = $col;
    $self->{tags}->{$tag}->{x} = $x;

    $x += $self->{tags}->{$tag}->{width};
    $col++;
    $self->{rows}->[$row]->{width} = $x;
    $self->{rows}->[$row]->{count} = $col;
  }

  $Text::Wrap::columns = $main::GUI{maxX} - 1;
  $self->{screenHeight} = $main::GUI{maxY} - 2 - $self->Height();
  $main::GUI{window}->setscrreg($self->Height(),$main::GUI{maxY}-3);
}



sub CharacterizeTab {
  my ($self,$tag,$order) = @_;

  $self->{tags}->{$tag}->{width} =
    1 + length($order) + 1 + length($self->{tags}->{$tag}->{text}) + 1;
  $self->{tags}->{$tag}->{order} = $order;
  $self->{tags}->{$tag}->{width} = 0 if ($self->{tags}->{$tag}->{hidden} == 1);
}


###########################################################################
#
#
#
###########################################################################
sub DrawTabs {
  my ($self) = @_;

  my $y = 0;
  my @string;
  my $type;
  my $string;
  my $length;
  foreach my $row (reverse(0..$#{$self->{rows}})) {
    @string = ();
    $length = 0;
    foreach my $index (0..$#{$self->{order}}) {
      my $tag = $self->{order}->[$index];
      next if ($self->{tags}->{$tag}->{hidden} == 1);
      next if ($self->{tags}->{$tag}->{row} != $row);
      my $type = 4;
      $type = 5 if ($self->Raised($tag));
      push(@string,$type," ".$self->{tags}->{$tag}->{order}.")");
      my $subtype = $type;
      $subtype = $self->{tags}->{$tag}->{highlight}
	if exists($self->{tags}->{$tag}->{highlight});
      push(@string,$subtype,$self->{tags}->{$tag}->{text});
      push(@string,$type," ");
      $length += $self->{tags}->{$tag}->{width};
    }
    push(@string,4," "x($main::GUI{maxX} - $length));

    $main::GUI{window}->move($y,0);
    $main::GUI{window}->clrtoeol();
    $length = 0;
    while($#string > -1) {
      $type = shift(@string);
      $string = shift(@string);
      $main::GUI{window}->attron(main::COLOR_PAIR($type));
      $main::GUI{window}->addstr($y,$length,$string);
      $main::GUI{window}->attrset(0);
      $length += length($string);
    }
    $y++;
  }
  $main::GUI{window}->move($y,0);
  $main::GUI{window}->attrset(0);
  $main::GUI{window}->refresh();

  $self->RaiseTab($self->CurrentTab(),1);
}


###########################################################################
#
#
#
###########################################################################
sub AddTab {
  my $self = shift;
  my (%args) = @_;

  if (!exists($args{text}) || !exists($args{tag})) {
    croak("ERROR: AddTab: must set text and tag arguments");
  }

  push(@{$self->{order}},$args{tag});

  $self->{tags}->{$args{tag}}->{text} = $args{text};
  $self->{tags}->{$args{tag}}->{raisecb} = $args{raisecb}
    if exists($args{raisecb});

  $self->RecalculatePositions();
  $self->DrawTabs();
}


###########################################################################
#
#
#
###########################################################################
sub DeleteTab {
  my($self,$tag,$type) = @_;

  return if !exists($self->{tags}->{$tag});

  if ($self->Raised($tag)) {
    if ($self->{order}->[0] eq $tag) {
      if ($#{$self->{order}} == 0) {
	$self->UnpackTab($tag);
      }	else {
	$self->RaiseTab($self->{order}->[1]);
      }
    } else {
      $self->RaiseTab($self->{order}->[0]);
    }
  }

  #---------------------------------------------------------------------------
  # Remove this tag from the order
  #---------------------------------------------------------------------------
  my $order = -1;
  foreach my $index (0..$#{$self->{order}}) {
    $order = $index if ($self->{order}->[$index] eq $tag);
  }
  splice(@{$self->{order}},$order,1);
  delete($self->{tags}->{$tag});

  $self->RecalculatePositions();
  $self->DrawTabs();
}


###########################################################################
#
# RaiseTab - Code to handle switching over to this tab
#
###########################################################################
sub RaiseTab {
  my ($self,$tag,$raiseitanyway) = @_;

  return if ($tag eq "");

  $raiseitanyway = 0 if (!defined($raiseitanyway) || ($raiseitanyway eq ""));

  return if ($self->Raised($tag) && ($raiseitanyway != 1));

  $self->RemoveTransients($self->{CurrentTab});

  $self->{CurrentTab} = $tag;

  $self->UnhighlightTab($tag);

  if ($self->{tags}->{$tag}->{row} != 0) {
    foreach my $tempTag (keys(%{$self->{tags}})) {
      $self->{tags}->{$tempTag}->{row} =
	$self->{tags}->{$tempTag}->{realRow};
    }
    my $row = $self->{tags}->{$tag}->{row};
    foreach my $tempTag (keys(%{$self->{tags}})) {
      if ($self->{tags}->{$tempTag}->{row} < $row) {
	$self->{tags}->{$tempTag}->{row} += 1;
      } else {
	if ($self->{tags}->{$tempTag}->{row} == $row) {
	  $self->{tags}->{$tempTag}->{row} = 0;
	}
      }	
    }
  }

  $self->DrawTabs() unless ($raiseitanyway == 1);

  $self->DrawTabContents($tag);

  &{$self->{tags}->{$tag}->{raisecb}}()
    if exists($self->{tags}->{$tag}->{raisecb});
}


sub DrawTabContents {
  my $self = shift;
  my $tag = shift;

  my $bottom = $#{$self->{screen}->{$tag}};
  my $top = $#{$self->{screen}->{$tag}} - $self->{screenHeight} + 1;
  $top = 0 if ($top < 0);

  foreach my $y ($self->Height()..($main::GUI{maxY}-3)) {
    $main::GUI{window}->move($y,0);
    $main::GUI{window}->clrtoeol();
  }

  my $y = $main::GUI{maxY}-3;
  my $type;
  my $text;
  my $colorIndex;
  my $bound;
  my $piece;
  my $next;

  foreach my $line ($top..$bottom) {
    $main::GUI{window}->scroll();
    $main::GUI{window}->move($y,0);
    $main::GUI{window}->clrtoeol();
    my $x = 0;
    my $text = $self->{screen}->{$tag}->[$line];
    while ($text !~ /^\s*$/) {
      $text =~ s/^\#t\#//;
      if ($text =~ /^\#c\#\d+\#/) {
	$text =~ s/^\#c\#(\d+)\#//;
	$type = $1;
	if (defined($type)) {
	  $main::GUI{window}->attron(main::COLOR_PAIR($type));
	  next;
	}
      }
      $colorIndex = index($text,"#c#",1);
      $bound = (($colorIndex > ($Text::Wrap::columns - $x) || ($colorIndex == -1)) ?
		($Text::Wrap::columns - $x) :
		$colorIndex
	       );
      if ($text =~ s/^([^\n]{0,$bound})(\#|\s|\Z(?!\n))//xm) {
	$piece = $1;
	$next = $2;
	$main::GUI{window}->addstr($y,$x,$piece);
	$x += length($piece);
	if (($next ne "#") || ($x == $Text::Wrap::columns)) {
	  $x = 0;
	  if (($next eq " ") || (($next eq "\n") && ($text =~ /\S+/))) {
	    $main::GUI{window}->scroll();
	    $main::GUI{window}->addstr($y,$x," "x12);
	    $x += 12;
	  }
	}
	$text = "#".$text if ($next eq "#");
      } else {
	if ($text =~ s/^([^\n]{0,$bound})//) {
	  $piece = $1;
	  $main::GUI{window}->addstr($y,$x,$piece);
	  $x += length($piece);
	  if ($x == $Text::Wrap::columns) {
	    $x = 0;
	    $main::GUI{window}->scroll();
	    $main::GUI{window}->addstr($y,$x," "x12);
	    $x += 12;
	  }
	}
      }
    }

    $main::GUI{window}->attrset(0);
  }
  $main::GUI{window}->move($main::GUI{maxY}-1,0);
  $main::GUI{window}->refresh();
}


sub Print {
  my $self = shift;
  my $tag = $self->CurrentTab();
  my $type = "normal";
  my $control = "";
  if ($_[0] eq "__jarl__:tabbar") {
    $control = shift;
    $tag = shift;
    $type = shift;
  }
  if ($_[0] eq "__jarl__:tabbar:transient") {
    $control = shift;
  }

  foreach my $piece (@_) {
    if (($#{$self->{screen}->{$tag}} == -1) ||
	($self->{screen}->{$tag}->[$#{$self->{screen}->{$tag}}] =~ /\n$/)) {
      if ($control eq "__jarl__:tabbar:transient") {
	push(@{$self->{screen}->{$tag}},"#t#");
      } else {
	push(@{$self->{screen}->{$tag}},"");
      }
    }
    $self->{screen}->{$tag}->[$#{$self->{screen}->{$tag}}] .= "#c#$main::types{$type}#$piece";
  }
  shift(@{$self->{screen}->{$tag}}) if ($#{$self->{screen}->{$tag}} == 99);

  $self->DrawTabContents($tag) if ($self->Raised($tag));
}


sub RemoveTransients {
  my $self = shift;
  my $tag = shift;

  foreach my $line (reverse(0..$#{$self->{screen}->{$tag}})) {
    splice(@{$self->{screen}->{$tag}},$line,1)
      if ($self->{screen}->{$tag}->[$line] =~ /^\#t\#/);
  }
}


sub CurrentTab {
  my ($self) = @_;
  return $self->{CurrentTab};
}


sub CurrentText {
  my ($self) = @_;
  return $self->{tags}->{$self->{CurrentTab}}->{text};
}


sub Raised {
  my ($self,$tag) = @_;
  return ($self->{CurrentTab} eq $tag);
}


sub ExistsTab {
  my ($self,$tag) = @_;
  return exists($self->{tags}->{$tag});
}


sub HighlightTab {
  my ($self,$tag,$priority) = @_;

  return if $self->Raised($tag);

  $priority = "low" if (!defined($priority) ||
			(($priority ne "low") &&
			 ($priority ne "medium") &&
			 ($priority ne "high"))
		       );

  my $priorityValue = $priority eq "low" ? 1 : ($priority eq "medium" ? 2 : 3);

  my $highlight = (exists($self->{tags}->{$tag}->{highlight}) ?
		   $self->{tags}->{$tag}->{highlight} :
		   0
		  );

  if ($priorityValue > $highlight) {
    $self->{tags}->{$tag}->{highlight} = $priorityValue;
  }

  $self->DrawTabs();
}


sub UnhighlightTab {
  my ($self,$tag) = @_;
  delete($self->{tags}->{$tag}->{highlight});
}


sub FindOrder {
  my $self = shift;
  my ($tag) = @_;
  return (exists($self->{tags}->{$tag}->{order}) ? $self->{tags}->{$tag}->{order} : -1);
}


sub GetOrder {
  my $self = shift;
  my $index = shift;

  foreach my $tag (keys(%{$self->{tags}})) {
    next unless exists($self->{tags}->{$tag}->{order});
    return $tag if ($self->{tags}->{$tag}->{order} == $index);
  }
}


sub HideTab {
  my ($self,$tag) = @_;

  return if ($self->{tabs}->{order}->[0] eq $tag);

  $self->{tags}->{$tag}->{hidden} = 1;
  if ($self->Raised($tag)) {
    $self->RaiseTab($self->{order}->[0]);
  }
  $self->Refresh();
}


sub ShowTab {
  my ($self,$tag) = @_;

  my $hidden = $self->{tags}->{$tag}->{hidden};
  $self->{tags}->{$tag}->{hidden} = 0;
  $self->Refresh();
  $self->RaiseTab($tag) if ($hidden == 1);
}




1;
