package Hexed::Term;

use strict;
use warnings;
use include;

use Hexed::Util;
use Curses;

# Initialize the window and pad.
sub init {
  my ($class, $dat) = @_;
  # Ten thousand lines is QUITE a bit. We probably won't run out.
  $dat->{Pad} = newpad(CONFIG->termlines, $dat->{Width} + 1);
  $dat->{OffY} = 0;   # for the pad
  $dat->{Prompt} = $dat->{Opts}{Prompt};
  $dat->{Total} = 0;
  delete $dat->{Opts};
  return bless $dat, $class;
}

# Add a message to the window.
sub msg {
  my ($self, $msg) = @_;
  my @lines = wrap($self->{Width}, $msg);

  my $were = $#{ $self->{Msgs} };
  push @{ $self->{Msgs} }, @lines;

  # Split by formatting tags.
  $self->{Pad}->standend;
  foreach my $line (@lines) {
    my $x = 0;
    foreach my $string (split(/(<[^>]+>)/, $line)) {
      next unless $string;  # that split is weird
      if ($string =~ m/<([^>]+)>/) {
        $self->{Pad}->attron( paint $1 );
      } else {
        # A normal part of the string.
        $self->{Pad}->addstr($self->{Total}, $x, $string);
        $x += length($string);
      }
    }
    $self->{Total}++;
  }

  # We must always reserve one line for the prompt. Thus, we can have a max of
  # height - 1 lines. If there's a prompt, that is.
  if ($#{ $self->{Msgs} } > $self->{Height} - $self->{Prompt}) {
    # Remove as many lines as we need.
    $self->{OffY} += $#{ $self->{Msgs} } - $self->{Height} + $self->{Prompt};
    splice @{ $self->{Msgs} }, 0, $#{ $self->{Msgs} } - $self->{Height} + $self->{Prompt};
  }

  return @lines;
}

# Display the messages in the scrolling region.
sub draw {
  my $self = shift;
  $self->{Win}->refresh if shift;   # fullscreen HexedUI stuff kills border

  $self->{Pad}->prefresh(
    $self->{OffY}, 0,   # in the pad/grid
    $self->{Y1}, $self->{X1}, $self->{Y2}, $self->{X2}
  );

  return 1;
}

# Perform a readline-esque input.
sub prompt {
  my ($self, $prompt, $limit) = @_;
  die "Can't prompt on a promptless terminal!\n" unless $self->{Prompt};
  my $y =  $self->{Total};
  my $x = 0;  # relative in the grid, that is
  $limit = $self->{Width} - length($prompt) if $limit eq "line";
  # We don't operate on the "window" like we once did. Instead, we directly
  # mess with the pad -- this prevents some window/pad conflicts. No big
  # chance, just $y is huge and we call draw, not refresh.
  my $win = $self->{Pad};
  my @orig = ($y, $x);
  curs_set(1);
  my @in = ();
  my $pntr = 0;
  # Draw the prompt.
  $win->addstr($y, $x, $prompt);
  $x += length($prompt);
  # Our cursor wandered off, McGonagoll, I swear! Wait, this joke is old...
  $self->draw;
  my ($start, $end) = ($x, $x); # Our cursor can't go past these points

  until ((my $key = getch) eq "\n") {
    if ($key eq 260) {
      # Left
      next if $x == $start; # Boundary?
      $x--;
      $pntr--;
      $win->move($y, $x);
      $self->draw;
    } elsif ($key eq 261) {
      # Right
      next if $x == $end; # Boundary?
      $x++;
      $pntr++;
      $win->move($y, $x);
      $self->draw;
    } elsif ($key eq 263) {
      # Backspace
      next if $pntr == 0; # Anything there to erase?
      splice(@in, --$pntr, 1);
      $win->delch($y, --$x);
      $self->draw;
      $end--;
    } elsif ($key eq 330) {
      # Delete
      next if $start == $end; # Anything there to erase?
      splice(@in, $pntr, 1);
      $win->delch($y, $x);
      $self->draw;
      $end--;
    } elsif ($key eq 262) {
      # Home
      next if $x == $start; # Already there
      $x = $start;
      $pntr = 0;
      $win->move($y, $x);
      $self->draw;
    } elsif ($key eq 360) {
      # End
      next if $x == $end; # Already there
      $x = $end;
      $pntr = $#in + 1;
      $win->move($y, $x);
      $self->draw;
    } else {
      next if scalar @in == $limit;
      if ($x == $end) {
        # Are we at the end?
        $win->addch($y, $x++, $key);
        $self->draw;
        $end++;
        $in[$pntr] = $key;
        $pntr++;
      } else {
        # Or are we inserting?
        splice(@in, $pntr, 0, $key);
        # @in is correct. Make the display and cursor and such reflect that.
        foreach my $X ($start .. $end) {
          $win->addch($y, $X, $in[$X - $start]);
        }
        $end++;
        $x++;
        $pntr++;
        $win->move($y, $x);
        $self->draw;
      }
    }
  }
  # If we're a temporary prompt...
  curs_set(0);
  my $in = join "", @in;
  $self->msg($prompt . $in);
  return $in;
}

42;
