The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Kephra::App::StatusBar;
our $VERSION = '0.09';
use strict;
use warnings;

my (@fields, @abs_border_x, %index, %width);
my $bar;
sub _ref    { $bar = ref $_[0] eq 'Wx::StatusBar' ? $_[0] : $bar }
sub _config { Kephra::API::settings()->{app}{statusbar} }
sub _item   { $fields[$_[0]] }
sub _l18n   { Kephra::Config::Localisation::strings()->{app}{status} }
sub _none_string {
	Kephra::Config::Localisation::strings()->{dialog}{general}{none};
}
sub _set_text {
	my ($msg, $nr) = @_;
	my $win = Kephra::App::Window::_ref();
	return if not defined $nr or $nr < 0 or $nr > @fields or not $win or not defined $msg;
	$win->SetStatusText($msg, $nr);
}
sub _index_from_mouse_pos {
	my $x_pos = shift;
	for (0 .. $#abs_border_x) {
		return $_ if $width{ $fields[$_] } == -1;
		return $_ if $x_pos <= $abs_border_x[$_];
	}
}
#
# external API
#
sub create {
	my $win = Kephra::App::Window::_ref();
	$win->CreateStatusBar(1);
	my $bar = $win->GetStatusBar;

	my $statusbar_def = Kephra::Config::File::load_from_node_data( _config() );
	unless ($statusbar_def) {
		$statusbar_def = Kephra::Config::Default::toolbars()->{statusbar};
	}

	for my $nr (0 .. $#$statusbar_def) {
		my @item = split / /, $statusbar_def->[$nr];
		if ($item[0] eq 'textpanel' and defined $item[1]) {
			$index{$item[1]} = $nr;
			$width{$item[1]} = defined $item[2] ? $item[2] : 50;
		}
	}
	$fields[ $index{$_} ] = $_ for keys %index;
	$abs_border_x[0] = $width{ $fields[0] };
	$abs_border_x[$_] = $abs_border_x[$_-1] + $width{ $fields[$_] } + 2
		for 1 .. $#fields;

	my $length = scalar keys %index;
	$bar->SetFieldsCount( $length );
	my @field_width;
	$field_width[$_] = $width{ $fields[$_] } for 0 .. $length - 1;
	$bar->SetStatusWidths( @field_width );
	$win->SetStatusBarPane( $index{message} );

	Wx::Event::EVT_LEFT_DOWN  ( $bar, sub {
		return unless get_interactive();
		my ( $bar,    $event )  = @_;
		my $field = _item( _index_from_mouse_pos( $event->GetX ) );
		if    ($field eq 'syntaxmode') {Kephra::Document::SyntaxMode::switch_auto()}
		#elsif ($field eq 'codepage')   {Kephra::Document::Property::switch_codepage()}
		elsif ($field eq 'tab')        {Kephra::Document::Property::switch_tab_mode()}
		elsif ($field eq 'EOL')        {Kephra::App::EditPanel::Indicator::switch_EOL_visibility()}
		elsif ($field eq 'message')    {next_file_info(); }
	} );
	Wx::Event::EVT_RIGHT_DOWN ( $bar, sub {
		return unless get_contextmenu_visibility();
		my ( $bar, $event ) = @_;
		my $x = $event->GetX;
		my $index = _index_from_mouse_pos( $x );
		my $cell_start = $bar->GetFieldRect($index)->GetTopLeft;
		$x = $cell_start->x unless $width{ _item($index) } == -1;
		my $y = $cell_start->y;
		my $field = _item( $index );
		my $menu = \&Kephra::App::ContextMenu::get;
		if    ($field eq 'syntaxmode'){$bar->PopupMenu( &$menu('status_syntaxmode'),$x,$y)}
		elsif ($field eq 'codepage')  {$bar->PopupMenu( &$menu('status_encoding'),  $x,$y)}
		elsif ($field eq 'tab')       {$bar->PopupMenu( &$menu('status_tab'),       $x,$y)}
		elsif ($field eq 'EOL')       {$bar->PopupMenu( &$menu('status_eol'),       $x,$y)}
		elsif ($field eq 'message')   {$bar->PopupMenu( &$menu('status_info'),      $x,$y)}
	});
	my $help_index = -1;
	Wx::Event::EVT_MOTION      ( $bar, sub {
		my $index = _index_from_mouse_pos( $_[1]->GetX );
		return if $index == $help_index;
		$help_index = $index;
		info_msg( _l18n()->{help}{ _item( $index ) } );
	});
	Wx::Event::EVT_LEAVE_WINDOW( $bar, sub { info_msg(''); $help_index = -1 });


	Kephra::EventTable::add_call
		('caret.move',       'caret_status', \&caret_pos_info,   __PACKAGE__);
	Kephra::EventTable::add_call
		('document.text.change', 'info_msg', \&refresh_info_msg, __PACKAGE__);
	Kephra::EventTable::add_call
		('editpanel.focus',      'info_msg', \&refresh_info_msg, __PACKAGE__);

	show();
}
sub get_visibility { _config()->{'visible'} }
sub switch_visibility {
	_config()->{'visible'} ^= 1;
	show();
	Kephra::App::Window::_ref()->Layout();
}
sub show { Kephra::App::Window::_ref()->GetStatusBar->Show( get_visibility() ) }
sub get_interactive { _config()->{interactive} }
sub get_contextmenu_visibility    { _config()->{contextmenu_visible} }
sub switch_contextmenu_visibility { _config()->{contextmenu_visible} ^= 1 }
#
# update cell content
#
sub refresh_cursor {
	caret_pos_info();
	refresh_info_msg();
}

sub refresh_all_cells {
	refresh_cursor();
	style_info();
	codepage_info();
	tab_info();
	EOL_info();
	info_msg();
}

sub caret_pos_info {
	my $ep     = Kephra::App::EditPanel::_ref();
	my $pos    = $ep->GetCurrentPos;
	my $line   = $ep->LineFromPosition($pos) + 1;
	my $lpos   = $ep->GetColumn($pos) + 1;
	my $value;

	# caret pos display
	if ( $line > 9999  or $lpos > 9999 )
	     { _set_text(" $line : $lpos", $index{cursor} ) }
	else { _set_text("  $line : $lpos", $index{cursor} ) }

	# selection or  pos % display
	my ( $sel_beg, $sel_end ) = $ep->GetSelection;
	unless ( Kephra::Document::Data::attr('text_selected') ) {
		my $chars = $ep->GetLength;
		if ($chars) {
			my $value = int 100 * $pos / $chars + .5;
			$value = ' ' . $value if $value < 10;
			$value = ' ' . $value . ' ' if $value < 100;
			_set_text( "    $value%", $index{selection} );
		} else { _set_text( "    100%", $index{selection} ) }
	} else {
		if ( $ep->SelectionIsRectangle ) {
			my $x = abs int $ep->GetColumn($sel_beg) - $ep->GetColumn($sel_end);
			my $lines = 1 + abs int $ep->LineFromPosition($sel_beg)
				- $ep->LineFromPosition($sel_end);
			my $chars = $x * $lines;
			$lines = ' ' . $lines if $lines < 100;
			if ($lines < 10000) { $value = "$lines : $chars" }
			else                { $value = "$lines:$chars" }
			_set_text( $value, $index{selection} );
		} else {
			my $lines = 1 + $ep->LineFromPosition($sel_end)
						  - $ep->LineFromPosition($sel_beg);
			my $chars = $sel_end - $sel_beg -
				($lines - 1) * Kephra::Document::Data::get_attribute('EOL_length');
			$lines = ' ' . $lines if $lines < 100;
			if ($lines < 10000) { $value = "$lines : $chars" }
			else                { $value = "$lines:$chars" }
			_set_text( $value, $index{selection});
		}
	}
}

sub style_info {
	my $style = shift
		|| Kephra::Document::Data::attr('syntaxmode')
		|| _none_string();
	_set_text( '' . $style, $index{syntaxmode} );
}
sub codepage_info {
	my $codepage = shift || Kephra::Document::Data::attr('codepage');
	my $msg = defined $codepage 
		? Kephra::CommandList::get_cmd_property
			( 'document-encoding-'.$codepage, 'label' )
		: _none_string();
	_set_text( '' . $codepage, $index{codepage} );
}
sub tab_info {
	my $mode  = Kephra::App::EditPanel::_ref()->GetUseTabs || 0;
	my $msg   = $mode ? ' HT' : ' ST';
	_set_text( $msg, $index{'tab'} );
}

sub EOL_info {
	my $mode = shift || Kephra::Document::Data::get_attribute('EOL') || _none_string() || 'no';
	my $msg;
	if    ( $mode eq 'none'  or $mode eq 'no' )  { $msg = _none_string() || 'no' }
	elsif ( $mode eq 'cr'    or $mode eq 'mac' ) { $msg = " Mac"  }
	elsif ( $mode eq 'lf'    or $mode eq 'lin' ) { $msg = "Linux" }
	elsif ( $mode eq 'cr+lf' or $mode eq 'win' ) { $msg = " Win"  }
	_set_text( $msg, $index{EOL} );
}
#
# info messages, last cell
#
sub status_msg { info_msg(@_) }
sub info_msg   {
	my $msg;
	$msg .= $_ for @_;
	_set_text( $msg, $index{message} );
}
sub refresh_info_msg  { refresh_file_info() }

sub info_msg_nr {
	my $nr = shift;
	if (defined $nr) { _config()->{msg_nr} = $nr}
	else             { _config()->{msg_nr} }
}

sub next_file_info {
	my $info_nr = _config()->{msg_nr};
	$info_nr = $info_nr >= 2 ? 0 : $info_nr + 1;
	set_info_msg_nr($info_nr);
}

sub set_info_msg_nr {
	my $info_nr = shift || 0;
	info_msg_nr($info_nr);
	refresh_file_info();
}

sub refresh_file_info {
	my $msg = info_msg_nr() ? _get_file_info( _config()->{msg_nr} ) : '';
	_set_text( $msg, $index{message} );
}

sub _get_file_info {
	my $selector = shift;
	return '' unless $selector;
	my $l18n = _l18n()->{label};

	# show how big file is
	if ( $selector == 1 ) {
		my $ep = Kephra::App::EditPanel::_ref();

		return sprintf ' %s: %s   %s: %s',
			$l18n->{chars}, _dotted_number( $ep->GetLength ),
			$l18n->{lines}, _dotted_number( $ep->GetLineCount );

	# show how old file is
	} elsif ( $selector == 2 ) {
		my $file = Kephra::Document::Data::get_file_path();
		if ($file) {
			my @time = localtime( $^T - ( -M $file ) * 86300 );
			return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{last_change},
				$time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
		} else {
			my @time = localtime;
			return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{now_is},
				$time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
		}
	}
}

sub _dotted_number {
	local $_ = shift;
	1 while s/^(\d+)(\d{3})/$1.$2/;
	return $_;
}

1;