package App::InteractivePerlTutorial;

use 5.014000;
use strict;
use warnings;
use parent qw/Wx::App/;
our $VERSION = '0.000_001';

use constant CHAPTERS => [qw/Introduction Scalar Arrays Hashes Sub IO FileTests Control Smartmatch/];

use File::HomeDir;
use Pod::Simple::XHTML;
use YAML::Any qw/DumpFile LoadFile/;

use Wx qw/:everything/;
use Wx::Event qw/:everything/;
use Wx::Html;
use Wx::Scintilla;

##################################################

my ($tree, $frame, $sizer, $html_window, $exe_panel, $exe_nb, $scintilla, $lesson, @exercises);
my ($datafile, %exdata);
my $purple = Wx::Colour->new(65, 67,109);

sub add_subtree{
	my ($tree, $node, $parent) = @_;
	eval "require $node" or die $@;
	my $item = $tree->AppendItem($parent, $node->TEXT);
	$tree->SetItemBackgroundColour($item, $purple);
	$tree->SetItemTextColour($item, $node->can('COLOUR') ? Wx::Colour->new($node->COLOUR) : Wx::Colour->new('white'));
	if ($node->can('EXERCISES')) {
		my @exercises = @{$node->EXERCISES};
		$tree->SetItemImage($item, 0) if @exercises == grep { $exdata{$node}[$_] } 0 .. $#exercises;
	} elsif ($node->can('CHILDREN')) {
		$tree->SetItemImage($item, 2);
		$tree->SetItemTextColour($item, Wx::Colour->new('lightgreen'));
		$tree->SetItemBold($item);
	}
	$tree->SetPlData($item, $node);
	eval { add_subtree ($tree, "${node}::$_", $item) for @{$node->CHILDREN()} };
}

sub run_exercise{
	my $code = $scintilla->GetText;
	my $exercise = $exercises[$exe_nb->GetSelection];
	undef $@;
	my ($in, $out) = $exercise->{input};
	close STDIN;
	close STDOUT;
	open STDIN, '<', \$in or die "Cannot reopen STDIN: $!";
	open STDOUT, '>', \$out or die "Cannot reopen STDOUT: $!";
	my @ret = eval $code;
	my $dialog;
	if ($@) {
		$dialog = Wx::MessageDialog->new($frame, "An error has ocurred while executing the code\n\n$@", 'Error', wxOK | wxCENTRE | wxICON_ERROR);
	} elsif ($exercise->{check}->($out, @ret)){
		$dialog = Wx::MessageDialog->new($frame, 'You solved this exercise successfully', 'Success', wxOK | wxCENTRE);
		$exdata{$lesson}[$exe_nb->GetSelection] = 1;
		#$exdata{$lesson}{alldone} = 1 if ;
		DumpFile $datafile, \%exdata;
		$tree->DeleteAllItems;
		my $root = $tree->AddRoot('root');
		add_subtree $tree, "App::InteractivePerlTutorial::Chapter::$_", $root for @{CHAPTERS()};
		$tree->ExpandAll;
	} else {
		$dialog = Wx::MessageDialog->new($frame, 'Wrong answer', 'Wrong answer', wxOK | wxCENTRE);
	}
	$dialog->ShowModal;
}

sub show_hint{
	Wx::MessageDialog->new($frame, $exercises[$exe_nb->GetSelection]->{hint} // 'No hint available', 'Success', wxOK | wxCENTRE)->ShowModal;
}

sub show_solution{
	Wx::MessageDialog->new($frame, $exercises[$exe_nb->GetSelection]->{solution} // 'No solution available', 'Success', wxOK | wxCENTRE)->ShowModal;
}

sub show_questions {
	Wx::TextEntryDialog->new($frame, "Do you have any questions about Interactive Perl Tutorial?\nWrite your question in the box below and press OK.", 'Questions?', wxOK | wxCANCEL)->ShowModal;
}

use Data::Dumper;

sub mangle_lesson {
	my $lesson = '<body bgcolor="rgb(65, 67, 109)" text="white">' . shift;
	$lesson =~ s!(<h1.*h1>)!\U<font color="rgb(109,179,109)">$1</font>\E!;
	$lesson =~ s,<code>,<font color="yellow"><code>,g;
	$lesson =~ s,</code>,</code></font>,g;
	$lesson
}

sub change_lesson {
	my $module = shift;
	$lesson = $module;

	my $parser = Pod::Simple::XHTML->new;
	my $out;
	$parser->output_string (\$out);
	my $fh;
	{ no strict 'refs'; $fh = *{"${module}::DATA"} }
	my $pos = tell $fh;
	$parser->parse_file($fh);
	seek $fh, $pos, 0;
	$html_window->SetPage(mangle_lesson $out);

	if ($module->can('EXERCISES')) {
		$exe_panel->Show(1);
		$exe_nb->DeleteAllPages;
		@exercises = @{$module->EXERCISES};
		for (0 .. $#exercises) {
			$exe_nb->AddPage(Wx::StaticText->new($exe_nb, -1, $exercises[$_]{statement}), 'Exercise ' . ($_ + 1));
		}
	} else {
		$exe_panel->Show(0);
	}

	$sizer->Layout;
}

sub init_scintilla{
	my $font = Wx::Font->new(12, wxTELETYPE, wxNORMAL, wxNORMAL);
	$scintilla->SetFont($font);
	$scintilla->StyleSetFont(Wx::Scintilla::STYLE_DEFAULT, $font);
	$scintilla->StyleClearAll();
	$scintilla->StyleSetBackground(Wx::Scintilla::STYLE_DEFAULT,  $purple);
	$scintilla->StyleSetBackground($_,  $purple) for 0 .. 18;
	$scintilla->StyleSetForeground(0,  Wx::Colour->new(255, 255, 127));
	$scintilla->StyleSetForeground(1,  Wx::Colour->new(0, 255, 255));
	$scintilla->StyleSetForeground(2,  Wx::Colour->new(255, 127, 255));
	$scintilla->StyleSetForeground(3,  Wx::Colour->new(127, 127, 127));
	$scintilla->StyleSetForeground(4,  Wx::Colour->new(255, 127, 127));
	$scintilla->StyleSetForeground(5,  Wx::Colour->new(255, 255, 127));
	$scintilla->StyleSetForeground(6,  Wx::Colour->new(0, 127, 255));
	$scintilla->StyleSetForeground(7,  Wx::Colour->new(127, 255, 127));
	$scintilla->StyleSetForeground(8,  Wx::Colour->new(255, 255, 255));
	$scintilla->StyleSetForeground(9,  Wx::Colour->new(127, 127, 127));
	$scintilla->StyleSetForeground(10, Wx::Colour->new(255, 255, 127));
	$scintilla->StyleSetForeground(11, Wx::Colour->new(255, 255, 0));
	$scintilla->StyleSetForeground(12, Wx::Colour->new(127, 255, 127));
	$scintilla->StyleSetForeground(13, Wx::Colour->new(191, 128, 0));
	$scintilla->StyleSetForeground(17, Wx::Colour->new(0, 255, 127));
	$scintilla->StyleSetForeground(18, Wx::Colour->new(127, 127, 255));

	$scintilla->StyleSetBold(12, 1);
	$scintilla->StyleSetSpec(Wx::Scintilla::SCE_H_TAG, 'fore:#0000ff');
	$scintilla->SetLexer(Wx::Scintilla::SCLEX_PERL);
}

my ($onion, $tick_cross);

sub load_png {
	my $handler = Wx::PNGHandler->new;
	my $image = Wx::Image->new;
	open my $file, shift;
	$handler->LoadFile($image, $file);
	Wx::Bitmap->new($image);
}

sub load_images {
	$onion = load_png 'onion.png';
	$tick_cross = Wx::ImageList->new(20, 20);
	$tick_cross->Add(load_png 'tick.png');
	$tick_cross->Add(load_png 'cross.png');
	$tick_cross->Add(load_png 'minionion.png');
}

sub OnInit {
	load_images;
	$frame = Wx::Frame->new(undef, -1, 'Interactive Perl Tutorial', [-1, -1], [500, 700]);
	my $panel = Wx::Panel->new($frame);
	$panel->SetBackgroundColour(Wx::Colour->new(59, 12, 89));
	$sizer = Wx::BoxSizer->new(wxHORIZONTAL);

	$tree = Wx::TreeCtrl->new($panel, -1, [-1, -1], [-1, -1], wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT);
	$tree->SetBackgroundColour($purple);
	$tree->SetImageList($tick_cross);
	my $root = $tree->AddRoot('root');
	add_subtree $tree, "App::InteractivePerlTutorial::Chapter::$_", $root for @{CHAPTERS()};
	EVT_TREE_SEL_CHANGED($tree, $tree, sub { change_lesson $_[0]->GetPlData($_[0]->GetSelection) });
	$tree->ExpandAll;

	$html_window = Wx::HtmlWindow->new($panel);

	$exe_panel = Wx::Panel->new($panel);
	$exe_panel->SetBackgroundColour(Wx::Colour->new(59, 12, 89));
	my $exe_sizer = Wx::BoxSizer->new(wxVERTICAL);
	$exe_nb = Wx::Notebook->new($exe_panel);
	$exe_nb->SetBackgroundColour($purple);
	$exe_nb->SetForegroundColour(Wx::Colour->new('white'));
	$scintilla = Wx::Scintilla::TextCtrl->new($exe_panel);
	init_scintilla $scintilla;
	$scintilla->SetWhitespaceBackground(1, $purple);
	my $button_panel = Wx::Panel->new($exe_panel);
	$button_panel->SetBackgroundColour(Wx::Colour->new(59, 12, 89));
	my $button_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
	my $run = Wx::BitmapButton->new($button_panel, -1,  $onion);
	my $hint = Wx::Button->new($button_panel, -1, 'Hint');
	my $sol = Wx::Button->new($button_panel, -1, 'Solution');
	my $questions = Wx::Button->new($button_panel, -1, 'Questions?');
	EVT_BUTTON($run, $run, \&run_exercise);
	EVT_BUTTON($hint, $hint, \&show_hint);
	EVT_BUTTON($sol, $sol, \&show_solution);
	EVT_BUTTON($questions, $questions, \&show_questions);

	$button_sizer->Add($run, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 5);
	$button_sizer->Add($hint, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 5);
	$button_sizer->Add($sol, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 5);
	$button_sizer->Add($questions, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 5);
	$button_panel->SetSizer($button_sizer);

	$exe_sizer->Add($exe_nb, 1, wxEXPAND | wxBOTTOM, 10);
	$exe_sizer->Add($scintilla, 3, wxEXPAND | wxTOP | wxBOTTOM, 10);
	$exe_sizer->Add($button_panel, 0, wxCENTER | wxTOP, 10);
	$exe_panel->SetSizer($exe_sizer);

	change_lesson "App::InteractivePerlTutorial::Chapter::Introduction";
	$sizer->Add($tree, 1, wxEXPAND | wxALL, 10);
	$sizer->Add($html_window, 3, wxEXPAND | wxALL, 10);
	$sizer->Add($exe_panel, 2, wxEXPAND | wxALL, 10);
	$panel->SetSizer($sizer);
	$frame->Show(1)
}

sub run{
	$datafile = File::HomeDir->my_dist_data(__PACKAGE__, {create => 1}) . '/exercises.yml';
	%exdata = %{LoadFile $datafile} if -f $datafile;
	App::InteractivePerlTutorial->new->MainLoop;
}

1;
__END__

=head1 NAME

App::InteractivePerlTutorial - Interactive Perl tutorial

=head1 SYNOPSIS

  use App::InteractivePerlTutorial;
  App::InteractivePerlTutorial->run;

=head1 DESCRIPTION

This is a developer release of App::InteractivePerlTutorial. There is no documentation yet.

It is also severely broken. So don't use it yet.

=head1 AUTHOR

Marius Gavrilescu, E<lt>marius@ieval.roE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2013 by Marius Gavrilescu

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.18.1 or,
at your option, any later version of Perl 5 you may have available.


=cut
