package Kephra::Edit::Goto;
our $VERSION = '0.11';

use strict;
use warnings;
#
# internal calls
#
sub _ep_ref       { Kephra::App::EditPanel::_ref() }
sub _center_caret { Kephra::Edit::_center_caret() }
sub _pos {
	my $ep  = _ep_ref();
	my $pos = shift;
	$pos += $ep->GetLength if $pos < 0;
	$ep->GotoPos($pos);
	$ep->EnsureCaretVisible();
}
#
# simple jump calls
#
sub pos { position(@_) }
sub position { # jump caret to character based text position
	my $pos = shift;
	return unless $pos;
	my $ep  = _ep_ref();
	my $max = $ep->GetLength;
	my $fvl = $ep->GetFirstVisibleLine;
	my $visible = $ep->GetLineVisible( $ep->LineFromPosition($pos) );

	$pos += $max if $pos < 0;
	$pos = 0 if $pos < 0;
	$pos = $max if $pos > $max;
	$ep->SetCurrentPos($pos);
	$ep->SetSelection ($pos, $pos);
	$ep->SearchAnchor;
	#$visible ? $ep->ScrollToLine($fvl) : _center_caret();
	$ep->EnsureCaretVisible;
	$ep->EnsureVisible( $ep->LineFromPosition($pos) );
	#_center_caret();
}
sub next_visible_pos {
	my $ep  = _ep_ref();
	my $line = $ep->GetCurrentLine();
	return if $ep->GetLineVisible($line);
	$line = $ep->GetFoldParent($line) until $ep->GetLineVisible($line);
	$ep->GotoLine($line);
	_center_caret();
}

sub line    {
	my $ep = _ep_ref();
	my $l18n = Kephra::API::localisation()->{dialog}{edit};
	my $line = Kephra::Dialog::get_number( 
		$l18n->{goto_line_input},
		$l18n->{goto_line_headline},
		$ep->GetCurrentLine + 1
	);
	line_nr( $line - 1) unless $line == &Wx::wxCANCEL;
}
sub line_nr { position( _ep_ref()->PositionFromLine( shift ) ) }

sub last_edit {
	my $pos = Kephra::Document::Data::get_attribute('edit_pos');
	position( $pos ) if defined $pos;
}

#
# block navigation
#
sub prev_block{ _ep_ref()->CmdKeyExecute(&Wx::wxSTC_CMD_PARAUP)   }
sub next_block{ _ep_ref()->CmdKeyExecute(&Wx::wxSTC_CMD_PARADOWN) }
#
# brace navigation
#
sub prev_brace {
	my $ep  = _ep_ref();
	my $oldpos = my $pos = $ep->GetCurrentPos;
	my $braceleft = 1; # is brace left to caret

	$braceleft--, $pos-- if $ep->BraceMatch($pos-1) > -1;
	$ep->GotoPos($pos - 1);
	$ep->SearchAnchor();
	my $newpos = $ep->SearchPrev(&Wx::wxSTC_FIND_REGEXP, '[{}()\[\]]');
	$newpos++ if $ep->BraceMatch($newpos) > $newpos;
	$newpos-- if not $braceleft and $newpos == $ep->BraceMatch($pos)+1;
	$newpos > -1 ? position($newpos) : position($oldpos);
}

sub next_brace {
	my $ep  = _ep_ref(   );
	my $oldpos = my $pos = $ep->GetCurrentPos;
	my $braceleft = 0; # is brace left to caret

	$braceleft++, $pos--
		if $ep->BraceMatch($pos-1) > -1 and $ep->BraceMatch($pos) == -1;
	$ep->GotoPos($oldpos + 1);
	$ep->SearchAnchor();
	my $newpos = $ep->SearchNext(&Wx::wxSTC_FIND_REGEXP, '[{}()\[\]]');
	$newpos++ if $ep->BraceMatch($newpos) > $newpos;
	$newpos++ if not $braceleft and $newpos == $ep->BraceMatch($pos);
	$newpos > -1 ? position($newpos) : position($oldpos);
}

sub prev_related_brace {
	my $ep  = _ep_ref();
	my $pos = $ep->GetCurrentPos;
	my $braceright = 1; # is brace right to caret
	my $matchpos = $ep->BraceMatch(--$pos);
	$braceright--, $matchpos = $ep->BraceMatch(++$pos) if $matchpos == -1;
	if ($matchpos == -1) { prev_brace() }
	else {
		if ($matchpos < $pos) { 
			$braceright ? position($matchpos) : position($matchpos+1); 
		}
		else { # when there is no matching brace
			my $open_char = chr $ep->GetCharAt($pos);
			my $close_char = chr $ep->GetCharAt($matchpos);
			$ep->GotoPos($pos);
			$ep->SearchAnchor();
			my $next_open = $ep->SearchPrev(0, $open_char);
			$ep->GotoPos($pos);
			$ep->SearchAnchor();
			my $next_close = $ep->SearchPrev(0, $close_char);
			if ($next_open ==-1 and $next_close == -1) {
				$ep->GotoPos($ep->GetLength);
				$ep->SearchAnchor();
				position( $ep->SearchPrev(0, $close_char) );
			} else {
				$next_open > $next_close
					? position( $next_open + 1 ) 
					: position( $next_close );
			}
		}
	}
}

sub next_related_brace {
	my $ep  = _ep_ref();
	my $pos = $ep->GetCurrentPos;
	my $braceleft = 1; # is brace left to caret
	my $matchpos = $ep->BraceMatch($pos);
	$braceleft--, $matchpos = $ep->BraceMatch(--$pos) if $matchpos == -1;
	if ($matchpos == -1) { next_brace() }
	else {
		if ($matchpos > $pos) {
			$braceleft ? position($matchpos+1) : position($matchpos); 
		}
		else { # when there is no matching brace
			my $open_char = chr $ep->GetCharAt($matchpos);
			my $close_char = chr $ep->GetCharAt($pos);
			$ep->GotoPos($pos + 1);
			$ep->SearchAnchor();
			my $next_open = $ep->SearchNext(0, $open_char);
			$ep->GotoPos($pos + 1);
			$ep->SearchAnchor();
			my $next_close = $ep->SearchNext(0, $close_char);
			if ($next_open ==-1 and $next_close == -1) {
				$ep->GotoPos(0);
				$ep->SearchAnchor();
				position( $ep->SearchNext(0, $open_char) );
			} else {
				$next_open < $next_close
					? position( $next_open + 1 ) 
					: position( $next_close );
			}
		}
	}
}

1;
__END__
=head1 NAME

Kephra::App::Goto - caret jump functions

=head1 DESCRIPTION



=cut