#!/usr/bin/perl

use strict;
use warnings;
use lib './tools/lib';
use lib './lib';
use Syntax::Kamelon::XMLData;
use Syntax::Kamelon::Diagnostics;
use Wx;


my $help = <<__EOF;
This is a viewer/debugger for the Kamelon syntax highlight engine.

yashe_debug_wx takes the following arguments:

-d
-debug
	Sets debug mode.

-help
   Displays this text.

-i
-index
   Uses the index file in the xml folder if present.Otherwise it just 
   indexes the xml files everytime at startup. This takes a penalty.
-s
-sampledir
   Sets the samplefolder where the samplefiles for the viewer are stored
   They are recognized on the basis of their extension.

-e
-section
   Loads only the XML files specified in the menu section in the list.

-x
-xmldir
   Specifies the XML directory. By default it uses Kamelon's.
__EOF

my $noindex = 1;
my $sampledir = '.';
my $section = '';
my $xmldir;
my $mode = 'text';

my %shortargs = (
	'-d' => sub  {
		$mode = 'debug';
		print "mode: $mode\n";
	},
	'-e' => sub { 
		$section = shift @ARGV;
		print "section: $section\n";
	},
	'-i' => sub { 
		$noindex = 0;
		print "Using index\n";
	},
	'-s' => sub  {
		$sampledir = shift @ARGV;
		unless (-e $sampledir) { die "$sampledir does not exist" }
		unless (-d $sampledir) { die "$sampledir is not a directory" }
		print "sampledir: $sampledir\n"
	},
	'-x' => sub  {
		$xmldir = shift @ARGV;
		unless (-e $xmldir) { die "$xmldir does not exist" }
		unless (-d $xmldir) { die "$xmldir is not a directory" }
		print "xmldir: $xmldir\n"
	},
);

my %args = (%shortargs,
	'-debug' => $shortargs{'-d'},
	'-index' => $shortargs{'-i'},
	'-section' => $shortargs{'-e'},
	'-sampledir' => $shortargs{'-s'},
	'-xmldir' => $shortargs{'-x'},
	'-help' => sub { print "$help\n"; exit }
);

while (@ARGV) {
	my $t = shift @ARGV;
	if (exists $args{$t}) {
		my $call = $args{$t};
		&$call;
	} else {
		my @op = sort keys %args;
		my $opstr = "";
		for (@op) {
			$opstr = "$opstr $_"
		}
		die "Invalid option $t. Available options:$opstr\n";
	}
}

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

my $highlighter = Syntax::Kamelon::Diagnostics->new(
	noindex => $noindex,
	xmlfolder => $xmldir,
);


$xmldir = $highlighter->GetIndexer->XMLFolder;

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

package FilterBar;

use strict;
use warnings;

use Wx qw( :frame :textctrl :sizer :panel :window :id :combobox);
use Wx::Event qw( EVT_BUTTON EVT_CHECKBOX );
use base qw( Wx::Panel );

sub new {
	my $class = shift;
	my $keylist = shift;
	my $self = $class->SUPER::new(@_);
	
	my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->SetSizer($sizer);

	my $keylab = Wx::StaticText->new($self, -1, "Key:");
	$sizer->Add($keylab, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2);
	my $keybox = Wx::ComboBox->new($self, -1, "", [-1, -1], [-1, -1], [], wxCB_READONLY);
	$sizer->Add($keybox, 1, wxEXPAND|wxALL, 2);
	for (@$keylist) { $keybox->Append($_) }
	$self->{KEYD} = $keybox;


	my $oplab = Wx::StaticText->new($self, -1, "Operator:");
	$sizer->Add($oplab, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2);
	my $opbox =Wx::ComboBox->new($self, -1, "", [-1, -1], [-1, -1], [], wxCB_READONLY);
	$sizer->Add($opbox, 0, wxALL, 2);
	my $ops = $highlighter->AvailableOperators;
	for (@$ops) { $opbox->Append($_) }
	$self->{OPD} = $opbox;

	my $vallab = Wx::StaticText->new($self, -1, "Value:");
	$sizer->Add($vallab, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2);
	my $value = Wx::TextCtrl->new($self, -1, "");
	$sizer->Add($value, 1, wxEXPAND|wxALL, 2);
	$self->{VALD} = $value;

	my $clab = Wx::StaticText->new($self, -1, "More:");
	$sizer->Add($clab, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2);
	my $cbox =Wx::ComboBox->new($self, -1, "", [-1, -1], [60, -1], [], wxCB_READONLY);
	$sizer->Add($cbox, 0, wxALL, 2);
	my @cops = ('', 'and', 'or');
	for (@cops) { $cbox->Append($_) }
	$self->{COND} = $cbox;

	$sizer->Fit($self);
	$self->Layout();

	return $self;
}

sub GetFilter {
	my $self = shift;
	my $key = $self->{KEYD}->GetValue;
	my $op = $self->{OPD}->GetValue;
	my $txt = $self->{VALD};
	my $val = $txt->GetRange(0, $txt->GetLastPosition);
	my $cont = $self->{COND}->GetValue;
	return [$key, $op, $val, $cont];
}


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

package FilterBox;

use strict;
use warnings;

use Wx qw( :frame :textctrl :sizer :panel :window :id);
use Wx::Event qw( EVT_BUTTON EVT_CHECKBOX );
use base qw( Wx::Panel );

sub new {
	my $class = shift;
	my $label = shift;
	my $keylist = shift;
	my $self = $class->SUPER::new(@_);
	
	my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->SetSizer($sizer);
	
	my $bar = Wx::Panel->new($self, -1);
	$sizer->Add($bar, 1, wxEXPAND|wxALL, 2);
	my $barsizer = Wx::BoxSizer->new(wxHORIZONTAL);
	$bar->SetSizer($barsizer);

	my $fp = Wx::ScrolledWindow->new($bar, -1, [-1, -1], [-1, -1], 
		wxHSCROLL|wxVSCROLL
	);
	$fp->EnableScrolling(1,1);
	$fp->FitInside();
   $fp->SetScrollRate(5, 5);
	$barsizer->Add($fp, 1, wxEXPAND|wxALL, 2);
	my $fsiz = Wx::BoxSizer->new(wxVERTICAL);
	$fp->SetSizer($fsiz);
	$self->{PANEL} = $fp;
	
	my $bp = Wx::Panel->new($bar, -1);
	$barsizer->Add($bp, 0, wxALL, 2);
	my $bsiz = Wx::BoxSizer->new(wxVERTICAL);
	$bp->SetSizer($bsiz);
	my $lab = Wx::StaticText->new($bp, -1, $label);
	$bsiz->Add($lab, 0, wxALL, 2);
	my @but = qw( Add Remove );
	foreach my $b (@but) {
		my $button = Wx::Button->new($bp, -1, $b);
		$bsiz->Add($button, 0);
		EVT_BUTTON($self, $button, $self->can("On$b"));
	}
	
	$self->{KEYLIST} = $keylist;
	$self->{FILTERS} = [];
	$sizer->Fit($self);
	$self->Layout();

	return $self;
}

sub Filters {
	my $self = shift;
	return $self->{FILTERS}
}


sub GetFilters {
	my $self = shift;
	my $f = $self->{FILTERS};
	my @o = ();
	for (@$f) {
		push @o, $_->GetFilter;
	}
	return \@o
}

sub OnAdd {
	my $self = shift;
	my $par = $self->{PANEL};
	my $filt = FilterBar->new($self->{KEYLIST}, $par);
	my $siz = $par->GetSizer;
	$siz->Add($filt, 0, wxEXPAND|wxALL, 2);
# 	$filt->FitInside;
	$par->FitInside();
	$par->Layout;
	$par->GetParent->GetSizer->Fit($par);
	$self->Layout;
	my $filters = $self->{FILTERS};
	push @$filters, $filt;
}

sub OnRemove {
	my $self = shift;
	my $filters = $self->{FILTERS};
	if (@$filters) {
		my $filt = pop @$filters;
		my $par = $filt->GetParent;
		$filt->Destroy;
		$par->FitInside;
	}
}

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

package DataPanel;

use strict;
use warnings;
use Carp;
use Syntax::Kamelon::Wx::LogTextCtrl;;

use Wx qw( :frame :textctrl :sizer :panel :window :id);
use Wx::Event qw( EVT_BUTTON EVT_CHECKBOX );
use base qw( Wx::Panel );

sub new {
	my $class = shift;
	my $self = $class->SUPER::new(@_);
	
	my $sizer = Wx::BoxSizer->new(wxVERTICAL);
	$self->SetSizer($sizer);
	
	my $splitter = Wx::SplitterWindow->new($self, wxID_ANY);

	my $toppane = Wx::Panel->new($splitter, wxID_ANY);
	my $tsiz = Wx::BoxSizer->new(wxVERTICAL);
	$toppane->SetSizer($tsiz);
	
	my @fopt = ($toppane, -1, [-1, -1], [-1, -1], wxBORDER_SUNKEN);
	
	my $synfilter = FilterBox->new("Syntax filter", $highlighter->AvailableLanguageKeys, @fopt);
	$tsiz->Add($synfilter, 1, wxBOTTOM|wxEXPAND, 2);
	$self->{SYN} = $synfilter;
	
	my $confilter = FilterBox->new("Context filter", $highlighter->AvailableContextKeys, @fopt);
	$tsiz->Add($confilter, 1, wxBOTTOM|wxEXPAND, 2);
	$self->{CON} = $confilter;
	
	my $rulefilter = FilterBox->new("Rule filter", $highlighter->AvailableRuleKeys, @fopt);
	$tsiz->Add($rulefilter, 1, wxBOTTOM|wxEXPAND, 2);
	$self->{RUL} = $rulefilter;
	
	my $shchk = Wx::Panel->new($toppane, -1);
	$tsiz->Add($shchk, 0, wxEXPAND|wxALL, 2);
	my $ssiz = Wx::BoxSizer->new(wxHORIZONTAL);
	$shchk->SetSizer($ssiz);
	my $slab = Wx::StaticText->new($shchk, -1, "Show:");
	$ssiz->Add($slab, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2);
	
	my @ca = qw(Details Context Rules Attributes Lists);
	foreach my $chk (@ca) {
		my $id = Wx::NewId;
		my $box = Wx::CheckBox->new($shchk, $id, $chk);
		$ssiz->Add($box, 0, wxALL, 2);
		my $method = $highlighter->can("Show$chk");
		$box->SetValue(&$method($highlighter));
		EVT_CHECKBOX($self, $id, sub { &$method($highlighter, $box->GetValue) });
	}
	
	my $filler = Wx::Panel->new($shchk, -1);
	$ssiz->Add($filler, 1, wxEXPAND);
	my $runb = Wx::Button->new($shchk, -1, "Run");
	$ssiz->Add($runb, 0, wxALL|wxALIGN_RIGHT, 2);
	EVT_BUTTON($self, $runb, \&Run);

	
	my $ctxt = Syntax::Kamelon::Wx::LogTextCtrl->new($splitter, -1, "", [-1, -1], [400,100]);
	$splitter->SplitHorizontally($toppane, $ctxt);
# 	$splitter->SetSashPosition(100);
	$splitter->SetSashGravity(0.5);
	$sizer->Add($splitter, 1, wxEXPAND|wxALL, 2);
	$self->{TXT} = $ctxt;
	$highlighter->OutCall( sub {
		$ctxt->WriteStyle(@_);
	});
	
	
	$sizer->Fit($self);
	$self->Layout();

	return $self;
}

sub entryOpen {
	my ($self, $entry) = @_;
	$self->entryClose;
	$highlighter->Diagnoze($entry);
	$self->{TXT}->ShowPosition(1);
}

sub entryClose {
	my $self = shift;
	$self->{TXT}->Clear;
	$highlighter->Clear;
	return 1
}

sub Run {
	my $self = shift;
	$self->entryClose;
	use Data::Dumper;
	my $syn = $self->{SYN};
	my $sf = $syn->GetFilters;
	print Dumper $sf;
	$highlighter->SyntaxFilter($sf);

	my $con = $self->{CON};
	my $cf = $con->GetFilters;
	print Dumper $cf;
	$highlighter->ContextFilter($cf);

	my $rul = $self->{RUL};
	my $rf = $rul->GetFilters;
	print Dumper $rf;
	$highlighter->RuleFilter($rf);
	
	my @list = $highlighter->AvailableSyntaxes;
	foreach my $item (@list) {
		$highlighter->Diagnoze($item);
	}
	$self->{TXT}->ShowPosition(1);
}

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

package ConsoleFrame;

use strict;
use warnings;
use Carp;

use Wx qw( :frame :textctrl :sizer :panel :window :id);
use base qw( Wx::Frame );
use Syntax::Kamelon::Wx::KamelonList;

sub new {
	my $class = shift;
	my $self = $class->SUPER::new(@_);
	my $indexer = $highlighter->GetIndexer;
	#Create widgets and controls
	my $splitter = Wx::SplitterWindow->new($self, wxID_ANY);
	my $listpane = Syntax::Kamelon::Wx::KamelonList->new($indexer, sub { return 0 }, $splitter, wxID_ANY);
	my $contentpane = DataPanel->new($splitter, wxID_ANY);
	$splitter->SplitVertically($listpane, $contentpane);
	$splitter->SetSashPosition(200);
	
	$self->{CONTENT} = $contentpane;
	
	$listpane->listCallback(sub {
		my $item = shift;
		if ($contentpane->entryOpen($item)) {
			return 1
		}
		return 0;
	});
	
	#Do layout
	my $topsizer = Wx::BoxSizer->new(wxHORIZONTAL);
	$topsizer->Add($splitter, 1, wxEXPAND);
	$self->SetSizer($topsizer);
	$topsizer->Fit($self);
	$self->Layout();

	return $self;
}

sub entryClose {
	my $self = shift;
	return $self->{CONTENT}->entryClose;
}

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

package ConsoleApp;

use base qw(Wx::App);   # Inherit from Wx::App

sub OnInit {
	my $self = shift;
	my $frame = ConsoleFrame->new( 
		undef,         # Parent window
		-1,            # Window id
		'Kamelon XML Viewer',  # Title
		[1200, 800],
	);
	$self->SetTopWindow($frame);    
	$frame->Show(1);                
}

sub OnExit {
 	my $self = shift;
}

package main;

my $wxobj = ConsoleApp->new(); 
$wxobj->MainLoop;
