package com.scrivenvar.editors;
import com.scrivenvar.FileEditorTab;
import com.scrivenvar.decorators.VariableDecorator;
import com.scrivenvar.definition.DefinitionPane;
import com.scrivenvar.definition.FindMode;
import com.scrivenvar.definition.VariableTreeItem;
import javafx.scene.control.TreeItem;
import javafx.scene.input.KeyEvent;
import org.fxmisc.richtext.StyledTextArea;
import java.nio.file.Path;
import java.text.BreakIterator;
import static com.scrivenvar.definition.FindMode.*;
import static javafx.scene.input.KeyCode.SPACE;
import static javafx.scene.input.KeyCombination.CONTROL_DOWN;
import static org.fxmisc.wellbehaved.event.EventPattern.keyPressed;
public final class VariableNameInjector {
private FileEditorTab mTab;
private final DefinitionPane mDefinitionPane;
public VariableNameInjector( final DefinitionPane pane ) {
mDefinitionPane = pane;
}
public void addListener( final FileEditorTab tab ) {
assert tab != null;
mTab = tab;
tab.getEditorPane().addKeyboardListener(
keyPressed( SPACE, CONTROL_DOWN ),
this::autoinsert
);
}
public void injectSelectedItem() {
final var pane = getDefinitionPane();
final TreeItem<String> item = pane.getSelectedItem();
if( item.isLeaf() ) {
final var leaf = pane.findLeaf( item.getValue(), FindMode.EXACT );
final var editor = getEditor();
editor.insertText( editor.getCaretPosition(), decorate( leaf ) );
}
}
private void autoinsert( final KeyEvent e ) {
final String paragraph = getCaretParagraph();
final int[] boundaries = getWordBoundariesAtCaret();
final String word = paragraph.substring( boundaries[ 0 ], boundaries[ 1 ] );
final VariableTreeItem<String> leaf = findLeaf( word );
if( leaf != null ) {
replaceText( boundaries[ 0 ], boundaries[ 1 ], decorate( leaf ) );
expand( leaf );
}
}
private int[] getWordBoundariesAtCaret() {
final String paragraph = getCaretParagraph();
int offset = getCurrentCaretColumn();
final BreakIterator wordBreaks = BreakIterator.getWordInstance();
wordBreaks.setText( paragraph );
while( offset > 0 && wordBreaks.isBoundary( offset ) ) {
offset--;
}
final int[] boundaries = new int[ 2 ];
boundaries[ 1 ] = wordBreaks.following( offset );
boundaries[ 0 ] = wordBreaks.previous();
return boundaries;
}
private String decorate( final VariableTreeItem<String> leaf ) {
return decorate( leaf.toPath() );
}
private String decorate( final String variable ) {
return getVariableDecorator().decorate( variable );
}
private void replaceText(
final int posBegan, final int posEnded, final String text ) {
final int p = getCurrentParagraph();
getEditor().replaceText( p, posBegan, p, posEnded, text );
}
private int getCurrentParagraph() {
return getEditor().getCurrentParagraph();
}
private String getCaretParagraph() {
return getEditor().getText( getCurrentParagraph() );
}
private int getCurrentCaretColumn() {
return getEditor().getCaretColumn();
}
private VariableTreeItem<String> findLeaf( final String word ) {
assert word != null;
VariableTreeItem<String> leaf = findLeafExact( word );
leaf = leaf == null ? findLeafStartsWith( word ) : leaf;
leaf = leaf == null ? findLeafContains( word ) : leaf;
leaf = leaf == null ? findLeafLevenshtein( word ) : leaf;
return leaf;
}
private VariableTreeItem<String> findLeafExact( final String text ) {
return findLeaf( text, EXACT );
}
private VariableTreeItem<String> findLeafContains( final String text ) {
return findLeaf( text, CONTAINS );
}
private VariableTreeItem<String> findLeafStartsWith( final String text ) {
return findLeaf( text, STARTS_WITH );
}
private VariableTreeItem<String> findLeafLevenshtein( final String text ) {
return findLeaf( text, LEVENSHTEIN );
}
private VariableTreeItem<String> findLeaf(
final String text, final FindMode findMode ) {
return getDefinitionPane().findLeaf( text, findMode );
}
private void expand( final TreeItem<String> node ) {
final DefinitionPane pane = getDefinitionPane();
pane.collapse();
pane.expand( node );
pane.select( node );
}
private VariableDecorator getVariableDecorator() {
return VariableNameDecoratorFactory.newInstance( getFilename() );
}
private Path getFilename() {
return getFileEditorTab().getPath();
}
private EditorPane getEditorPane() {
return getFileEditorTab().getEditorPane();
}
private StyledTextArea<?, ?> getEditor() {
return getEditorPane().getEditor();
}
public FileEditorTab getFileEditorTab() {
return mTab;
}
private DefinitionPane getDefinitionPane() {
return mDefinitionPane;
}
}