package Lire::UI::CompoundWidget;

use strict;

use base qw/ Curses::UI::Container Lire::UI::Widget /;

use Carp;
use Curses;
use Curses::UI::Common;
use Locale::TextDomain 'lire';

use Lire::Utils qw/ check_object_param max/;

use vars qw/ @CARP_NOT %bindings %routines /;

@CARP_NOT = qw/ Curses::UI::Container /;

%bindings = ( KEY_PPAGE() => 'pageup',
              KEY_NPAGE() => 'pagedown' );
%routines = ( 'pageup' => \&help_pageup,
              'pagedown' => \&help_pagedown );

sub new {
    my $class = shift;
    my %userargs = @_;
    keys_to_lowercase(\%userargs);

    check_object_param( $userargs{'value'}, 'value',
                        'Lire::Config::Dictionary' );

    my $self = $class->Curses::UI::Container::new( %userargs,
                                                   '-bindings' => \%bindings,
                                                   '-routines' => \%routines );
    if ( $self->shown_components() ) {
        $self->_setup_value_widgets();
        $self->_setup_help_viewer();
    } else {
        $self->_setup_empty_label();
    }
    $self->layout();

    return $self;
}

sub _setup_empty_label {
    my $self = $_[0];

    $self->add('empty_label', 'Label',
               '-text'=>__('-- This option does not have any attributes --'));

    return;
}

sub _setup_value_widgets {
    my $self = $_[0];

    foreach my $comp ( $self->shown_components() ) {
        my $name = $comp->name();
        $self->add( "${name}_label", 'Label',
                    '-text' => $name, '-bold' => 1,
                    '-textalignment' => 'right'  );
        $self->add( "${name}_widget", 'Lire::UI::Widget',
                    'value' => $self->{'value'}->get( $name ),
                    '-onfocus' => \&_child_focus_cb,
                    'onvaluechanged' => sub { $self->run_event( 'onvaluechanged' ) },
                  );
    }

    return;
}

sub shown_components {
    my $self = $_[0];

    grep { ! $_->obsolete() } $self->{'value'}->spec()->components();
}

# FIXME: this is hackish
sub _help_onfocus_cb {
    my $help = $_[0];

    my $self = $help->parent();
    if ( $help->{'_tag'} ) {
        $self->focus_next();
        $help->{'_tag'} = 0;
    } else {
        $self->parent()->focus_next();
        $help->{'_tag'} = 1;
    }

    return;
}

sub _setup_help_viewer {
    my $self = $_[0];

    return unless $self->shown_components();

    $self->add( 'help_summary', 'Label', '-bold' => 1 );
    my $viewer = $self->add( 'help_viewer', 'TextViewer',
                             '-wrapping' => 1, '-vscrollbar' => 1,
                             '_tag' => 0 );
    $viewer->onFocus( \&_help_onfocus_cb );

    return;
}

sub help_viewer_width {
    return int( ($_[0]->canvaswidth() - 2) * 0.4 );
}

sub layout_value_widgets {
    my $self = $_[0];

    $self->{'_label_width'} = $self->_max_label_size();
    $self->{'_widget_width'} = ( $self->canvaswidth() - $self->{'_label_width'}
                                 - $self->help_viewer_width() - 2 );
    my $y = 0;
    my $left = $self->shown_components();
    if ( $left * 2 - 1> $self->canvasheight() ) {
        $Curses::UI::screen_too_small++;
        return;
    }

    foreach my $comp ( $self->shown_components() ) {
        my $label = $self->getobj( $comp->name() . '_label' );
        $label->{'-x'} = 0;
        $label->{'-y'} = $y;
        $label->{'-width'} = $self->{'_label_width'};

        my $widget = $self->getobj( $comp->name() . "_widget" );
        $widget->{'-x'} = $self->{'_label_width'} + 1;
        $widget->{'-y'} = $y;
        $widget->{'-width'} = $self->{'_widget_width'};
        $widget->{'-height'} =
          int( ($self->canvasheight() - $y - ($left - 1)) / $left );
        $widget->layout();
        $y += $widget->{'-height'} + 1;
        $left--;
    }
    return;
}

sub layout_help_viewer {
    my $self = $_[0];

    my $help_width = $self->help_viewer_width();
    my $x = $self->{'_label_width'} + $self->{'_widget_width'} + 2;

    my $summary = $self->getobj( 'help_summary' );
    $summary->{'-x'} = $x;
    $summary->{'-y'} = 0;
    $summary->{'-width'} = $help_width;

    my $viewer = $self->getobj( 'help_viewer' );
    $viewer->{'-x'} = $x;
    $viewer->{'-y'} = 2;
    $viewer->{'-width'} = $help_width;

    return;
}

sub layout_contained_objects {
    my $self = $_[0];

    return $self unless $self->getobj( 'help_viewer' );

    $self->layout_value_widgets();
    $self->layout_help_viewer();

    return $self->SUPER::layout_contained_objects();
}

sub refresh_view {
    my $self = $_[0];

    foreach my $comp ( $self->shown_components() ) {
        my $name = $comp->name();
        die "$name: $self" unless $self->isa( 'Lire::UI::CompoundWidget' );
        $self->getobj( "${name}_widget" )->refresh_view();
    }

    return;
}

sub _max_label_size {
    my $self = $_[0];

    my $avail = int( ( $self->canvaswidth()-2 ) * 0.25 );

    my @labels = map { $_->name() } $self->shown_components();
    my $max = max( map { length $_ } @labels );
    return ( $max < $avail ? $max : $avail );
}

# Routines
sub help_pageup {
    my $self = $_[0];

    my $help_viewer = $self->getobj( 'help_viewer' );
    $help_viewer->cursor_pageup();
    $help_viewer->draw();

    return;
}

sub help_pagedown {
    my $self = $_[0];

    my $help_viewer = $self->getobj( 'help_viewer' );
    $help_viewer->cursor_pagedown();
    $help_viewer->draw();

    return;
}

# callbacks
sub _child_focus_cb {
    my $widget = $_[0];

    my $self = $widget->parent();

    my $value = $widget->{'value'};

    $self->getobj( 'help_summary' )->text( $value->summary() );

    my $help_viewer = $self->getobj( 'help_viewer' );
    $help_viewer->cursor_up( undef, $help_viewer->{'-yscrpos'} )
      if ( $help_viewer->{'-yscrpos'} > 1 );
    $help_viewer->text( $value->text_description()
                        || __( 'No help available.' ) );

    return;
}

1;
