package Cursed::Frame;

use strict;
use warnings;
use include;

use Curses;
use Clone ("clone");

use Hexed::Prompt;
use Hexed::Menu;
use Hexed::Fixed;

# Form a set of windows from a layout description.
sub summon {
  my ($class, $ui, $name, %layout) = @_;
  my $self = bless {
    _HexedUI => $ui,
    _Name    => $name
  }, $class;
  while (my ($win, $dat) = each %layout) {
    $self->_make_win($win => $dat);
  }
  return $self;
}

# Construct a window.
sub _make_win {
  my ($self, $name, $dat) = @_;

  my $orig = clone($dat);

  # Size *does* matter!
  getmaxyx(my $rows, my $cols);
  
  # Any time a size or position says a percent, change that to whatever
  # percent of either the actual rows or columns of our terminal is.
  # Likewise, handle centering
  $dat->{Size}[0] =~ s#(\d+)%#$1 * $rows / 100#;
  $dat->{Size}[1] =~ s#(\d+)%#$1 * $cols / 100#;
  $dat->{At}[0] =~ s#(\d+)%#$1 * $rows / 100#;
  $dat->{At}[1] =~ s#(\d+)%#$1 * $cols / 100#;
  $dat->{At}[0] =~ s#center#center($dat->{Size}[0], $rows)#;
  $dat->{At}[1] =~ s#center#center($dat->{Size}[1], $cols)#;
  
  # And evaluate that value.
  my $sizeY = int eval($dat->{Size}[0]);
  my $sizeX = int eval($dat->{Size}[1]);
  my $posY = int eval($dat->{At}[0]);
  my $posX = int eval($dat->{At}[1]);
  delete $dat->{At};
  delete $dat->{Size};
  
  my $win = newwin($sizeY, $sizeX, $posY, $posX);                 
  $win->box(0, 0) if $dat->{Border};
  # TODO: do we wanna do this yet? :|
  $win->refresh;

  # If there's a border, then there's automatically an X and Y offset of 1
  # each side. So we lose 2 rows and 2 columns. Reflect that visually.
  # Additionally, the window itself may have more padding.
  my $off = 0;
  $off = 2 if $dat->{Border};
  $off += 2 if $dat->{Pad};

  my $handler = "Hexed::$dat->{Type}";
  my %dat = (
    # These are the coordinates of what we're actually allowed to draw in.
    Y1     => ($off / 2),
    X1     => ($off / 2),
    Height => $sizeY - $off,
    Width  => $sizeX - $off,
    Win     => $win,
    Border  => $dat->{Border},
    Off     => $off,
    AbsPosY => $posY,
    AbsPosX => $posX,
    Frame   => $self,
    Orig    => $orig,
    Name    => $name,
    Opts    => $dat
  );
  $dat{Y2} = $dat{Y1} + $dat{Height};
  $dat{X2} = $dat{X1} + $dat{Width};
  delete $dat->{Border};
  delete $dat->{Pad};
  delete $dat->{Type};

	my $childof = $dat->{ChildOf};
  $self->{$name} = $handler->init(%dat);
	# Register self if we're a subwindow.
	push @{ $self->{$childof}{Subwindows} }, $self->{$name} if $childof;
}

# Return a list of windows in this frame.
sub windows {
  my $self = shift;
  return map { $self->{$_} } grep(!/^_/, keys %$self);
}

# TODO
sub frame_resize {
}

# Redraw a window completely, clearing residue.
sub redraw {
  my ($self, $win) = @_;
  $win = $self->{$win};
	$win->{Win}->clear;
	$win->{Win}->standend;
	$win->{Win}->box(0, 0) if $win->{Border};
	$win->draw;
}

# Create a temporary popup to select an option from a menu.
sub choose {
  my ($self, $query, @choices) = @_;
  my $choose = new Queue;
  my $width = 2 + longest($query, @choices);;
  $width += 2;
	# TODO: bad assumption to make, childof...
  $self->_make_win(TmpChoosePopup => {
		ChildOf   => "Main",
    Type      => "Menu",
    At        => ["center + 3", "center"],
    Size      => [@choices + 2, $width],
    Border    => 1,
    Queue     => $choose,
    ShiftKeys => 0,
    DeleteKey => 0,
    KeyHandler   => sub {
      my ($win, $key) = @_;
      $win->ui->{_GotInput} = $win->{Queue}->active if $key eq "<^M>";
    }
  });
  $choose->add($_, Menu => $choices[$_]) foreach 0 .. $#choices;
  $self->_make_win(TmpChooseTitle => {
		ChildOf => "Main",
    Type    => "Fixed",
    At      => [$self->{TmpChoosePopup}{AbsPosY} - 3, "center"],
    Size    => [3, $width],
    Border  => 1
  });
  $self->{TmpChooseTitle}->title(0, $query);
  $self->{TmpChooseTitle}->draw;

  my $choice = $self->ui->wait_input;

  # Cleanup
	$self->nuke_win("TmpChooseTitle");
	$self->nuke_win("TmpChoosePopup");
  return $choice;
}

# Create a temporary popup window to prompt for input.
sub askfor {
  my ($self, $query, undef, $limit) = @_;
  my $size = length($query) > $limit ? length($query) : $limit;
  $self->_make_win(TmpPrompt => {
		ChildOf => "Main",
    Type    => "Prompt",
    At      => ["center", "center"],
    Size    => [4, $size + 2],
    Border  => 1
  });
  my $input = $self->{TmpPrompt}->prompt($query, $limit);

  # Cleanup
	$self->nuke_win("TmpPrompt");
  return $input;
}

# Give a reference to the HexedUI singleton
sub ui {
  my $self = shift;
  return $self->{_HexedUI};
}                                                                         

# Destroy a window from the frame.
sub nuke_win {
  my ($self, $name) = @_;
  my $win = $self->{$name};
  $win->{Win}->delwin;

  # And remove any keymaps they might have
  $self->ui->remove_keymap($name);

	# Unregister them if they're a subwindow somewhere
	$self->{ $win->{ChildOf} }->remove_subwins($name) if $win->{ChildOf};

  # Clean up the screens
  delete $self->{$name};
	$self->redraw($_->{Name}) foreach $self->windows;
}

42;
