The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Padre::Wx::Command;

# Class for the command window at the bottom of Padre.
# This currently has very little customisation code in it,
# but that will change in future.

use 5.008;
use strict;
use warnings;
use utf8;
use Encode                ();
use File::Spec            ();
use Params::Util          ();
use Padre::Wx::Role::View ();
use Padre::Wx::Role::Main ();
use Padre::Wx             ();
use Padre::Logger;

our $VERSION = '0.96';
our @ISA     = qw{
	Padre::Wx::Role::View
	Padre::Wx::Role::Main
	Wx::SplitterWindow
};


######################################################################
# Constructor

sub new {
	my $class = shift;
	my $main  = shift;
	my $panel = shift || $main->bottom;

	my $self = $class->SUPER::new(
		$panel, -1, Wx::DefaultPosition, Wx::DefaultSize,
		Wx::NO_FULL_REPAINT_ON_RESIZE | Wx::CLIP_CHILDREN
	);

	my $output = Wx::TextCtrl->new(
		$self, -1, "", Wx::DefaultPosition, Wx::DefaultSize,
		Wx::TE_READONLY | Wx::TE_MULTILINE | Wx::NO_FULL_REPAINT_ON_RESIZE
	);

	my $input = Wx::TextCtrl->new(
		$self, -1, "", Wx::DefaultPosition, Wx::DefaultSize,
		Wx::NO_FULL_REPAINT_ON_RESIZE | Wx::TE_PROCESS_ENTER
	);

	$self->{_output_} = $output;
	$self->{_input_}  = $input;

	# Do custom start-up stuff here
	#$self->clear;
	#$self->set_font;

	# Moves the focus the input window but does not allow selecting text in the output window
	#Wx::Event::EVT_SET_FOCUS( $output, sub { $input->SetFocus; } );

	Wx::Event::EVT_TEXT_ENTER(
		$main, $input,
		sub {
			$self->text_entered(@_);
		}
	);
	Wx::Event::EVT_KEY_UP( $input, sub { $self->key_up(@_) } );

	my $height = $main->{bottom}->GetSize->GetHeight;

	#print "Height: $height\n";
	#print $self->GetSize->GetHeight, "\n"; # gives 20 on startup?
	$self->SplitHorizontally( $output, $input, $height - 120 ); ## TODO ???
	$input->SetFocus;

	$self->{_history_} = Padre::DB::History->recent('commands') || [];

	#$self->{_history_pointer_} = @{ $self->{_history_} } - 1;

	$self->{_output_}->WriteText(
		Wx::gettext(
			"Experimental feature. Type '?' at the bottom of the page to get list of commands. If it does not work, blame szabgab.\n\n"
		)
	);

	return $self;
}


######################################################################
# Padre::Wx::Role::View Methods

sub view_panel {
	return 'bottom';
}

sub view_label {
	Wx::gettext('Command');
}

sub view_close {
	shift->main->show_command(0);
}



######################################################################
# Event Handlers

sub text_entered {
	my ( $self, $main, $event ) = @_;

	my $text = $self->{_input_}->GetRange( 0, $self->{_input_}->GetLastPosition );
	$self->{_input_}->Clear;
	$self->out(">> $text\n");
	my %commands = (
		':e filename'        => 'Open file',
		':! cmd'             => 'Run command in shell',
		'?'                  => 'This help',
		':history'           => 'History of all the command',
		':padre cmd'         => 'Execute cmd withing the current Padre process',
		':keycatcher Number' => 'Turn on catching keyboard for a single event (defaults to 2)',
	);

	push @{ $self->{_history_} }, $text;
	Padre::DB::History->create(
		type => 'commands',
		name => $text,
	);

	#$self->{_history_pointer_} = @{ $self->{_history_} } - 1;
	if ( $text eq '?' ) {
		foreach my $cmd ( sort keys %commands ) {
			$self->outn("$cmd    - $commands{$cmd}");
		}
	} elsif ( $text eq ':history' ) {
		foreach my $cmd ( @{ $self->{_history_} } ) {
			$self->outn($cmd);
		}
	} elsif ( $text =~ m/^:keycatcher(\s+(\d+))?\s*$/ ) {
		$self->{_keycatcher_} = $2 || 2;
	} elsif ( $text =~ /^:e\s+(.*?)\s*$/ ) {
		my $path = $1;
		if ( not -e $path ) {
			$self->outn("File ($path) does not exist");
		} elsif ( not -f $path ) {
			$self->outn("($path) is not a file");
		} else {
			$main->setup_editors($path);
		}
	} elsif ( $text =~ /^:!\s*(.*?)\s*$/ ) {

		# TODO: what about long running commands?
		my $cmd = $1;

		# TODO: when reqire and import is used it blows up with
		# Can't call method "capture_merged" without a package or object reference at
		# so we "use" it now
		#require Capture::Tiny;
		#import Capture::Tiny qw(capture_merged);
		use Capture::Tiny qw(capture_merged);
		my $out = capture_merged {
			system($cmd);
		};
		if ( defined $out ) {
			$self->out($out);
		}
	} elsif ( $text =~ m/^:padre\s+(.*?)\s*$/ ) {
		my $ret;
		my $out = capture_merged {
			$ret = eval $1;
		};
		my $err = $@;
		if ( defined $out and $out ne '' ) {
			$self->outn($out);
		}
		if ( defined $ret and $ret ne '' ) {
			$self->outn($ret);
		}
		if ($err) {
			$self->outn($err);
		}
	} else {
		$self->outn("Invalid command");
	}

	return;
}

sub key_up {
	my ( $self, $input, $event ) = @_;

	#print $self;
	#print $event;
	my $mod = $event->GetModifiers || 0;
	my $code = $event->GetKeyCode;

	if ( $self->{_keycatcher_} ) {
		$self->{_keycatcher_}--;
		$self->outn("Mode: $mod  Code: $code");
	}

	my $text = $self->{_input_}->GetRange( 0, $self->{_input_}->GetLastPosition );
	if ( not defined $text or $text eq '' ) {
		delete $self->{_history_pointer_};
	}
	my $new_text;
	if ( $mod == 0 and $code == 9 ) { # TAB
		                              #print "Text: $text\n";
		require Padre::Util::CommandLine;
		$new_text = Padre::Util::CommandLine::tab($text);
	} elsif ( $mod == 0 and $code == 317 ) { # Down
		return if not @{ $self->{_history_} };
		if ( not defined $self->{_history_pointer_} ) {
			$self->{_history_pointer_} = 0;
		} else {
			$self->{_history_pointer_}++;
			if ( $self->{_history_pointer_} >= @{ $self->{_history_} } ) {
				$self->{_history_pointer_} = 0;
			}
		}
		$new_text = $self->{_history_}[ $self->{_history_pointer_} ];
	} elsif ( $mod == 0 and $code == 315 ) { # Up
		return if not @{ $self->{_history_} };
		if ( not defined $self->{_history_pointer_} ) {
			$self->{_history_pointer_} = @{ $self->{_history_} } - 1;
		} else {
			$self->{_history_pointer_}--;
		}
		if ( $self->{_history_pointer_} < 0 ) {
			$self->{_history_pointer_} = @{ $self->{_history_} } - 1;
		}
		$new_text = $self->{_history_}[ $self->{_history_pointer_} ];
	} elsif ( $mod == 2 and $code == 85 ) {  # Ctrl-u
		$new_text = '';
	} else {
		return;
	}

	#print "New text: $new_text\n";
	if ( defined $new_text ) {
		$self->{_input_}->Clear;
		$self->{_input_}->WriteText($new_text);
	}

}

sub out {
	my ( $self, $text ) = @_;
	$self->{_output_}->WriteText($text);
}

sub outn {
	my ( $self, $text ) = @_;
	$self->{_output_}->WriteText("$text\n");
}


#####################################################################
# General Methods

sub select {
	my $self   = shift;
	my $parent = $self->GetParent;
	$parent->SetSelection( $parent->GetPageIndex($self) );
	return;
}

sub clear {
	my $self = shift;

	#$self->SetBackgroundColour('#FFFFFF');
	#$self->Remove( 0, $self->GetLastPosition );
	#$self->Refresh;
	return 1;
}


sub relocale {

	# do nothing
}

1;

# Copyright 2008-2012 The Padre development team as listed in Padre.pm.
# LICENSE
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl 5 itself.