package de.duehl.swing.ui.highlightingeditor.search;

/*
 * Copyright 2017 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import de.duehl.basics.debug.DebugHelper;
import de.duehl.basics.text.Text;
import de.duehl.swing.ui.elements.search.SearchReaktor;
import de.duehl.swing.ui.highlightingeditor.HighlightingEditor;

/**
 * Diese Klasse kümmert sich um die Suche im Editor.
 *
 * @version 1.01     2017-12-15
 * @author Christian Dühl
 */

public class EditorSearcher {

    private static final String NO_SEARCH_TEXT = "###_NO_SEARCH_WORD_ENTERED_###";
    private static final boolean DEBUG = true;

    /** Letzte Fundstelle. */
    private int lastSearchIndex = 0;

    /** Letzter gesuchter Text. */
    private String searchText = NO_SEARCH_TEXT;

    /** Der Editor in dem gesucht wird. */
    private HighlightingEditor editor;

    /**
     * Konstruktor.
     *
     * Achtung, wird dieser Konstruktor verwendet, muss vor der Benutzung durch eine Suche der
     * Editor mit switchEditor() gesetzt werden!
     */
    public EditorSearcher() {
    }

    /**
     * Konstruktor
     *
     * @param editor
     *            Der Editor in dem gesucht wird.
     */
    public EditorSearcher(HighlightingEditor editor) {
        this.editor = editor;
    }

    /** Wechselt den Editor. */
    public void switchEditor(HighlightingEditor editor) {
        if (!editor.equals(this.editor)) {
            this.editor = editor;
            lastSearchIndex = 0;
            //searchText = NO_SEARCH_TEXT;
        }
    }

    public SearchReaktor createSearchReaktor() {
        return new SearchReaktor() {
            @Override
            public void search(String searchText) {
                searchInternal(searchText);
            }

            @Override
            public void searchAgain() {
                searchAgainInternal();
            }
        };
    }

    private void searchInternal(String searchText) {
        this.searchText = searchText;
        lastSearchIndex = editor.getCaretPosition();
        searchAgainInternal();
    }

    private void searchAgainInternal() {
        if (searchTextIsValid()) {
            searchAgainWithValidSearchText();
        }
    }

    private boolean searchTextIsValid() {
        return searchText != NO_SEARCH_TEXT && !searchText.isEmpty();
    }

    private void searchAgainWithValidSearchText() {
        String text = getTextWithInternalLineBreaks();
        adjustLastSearchIndexInCaseOfShortenedText(text);

        int index = text.indexOf(searchText, lastSearchIndex);
        if (index < 0) {
            say("Suche von vorn...");
            index = text.indexOf(searchText, 0);
        }

        if (index < 0) {
            searchWasNotSuccessfull();
        }
        else {
            searchAgainWithValidIndex(index);
        }
    }

    private String getTextWithInternalLineBreaks() {
        String text = editor.getText();
        text = Text.lineBreaksToBackslashN(text);
        return text;
    }

    private void adjustLastSearchIndexInCaseOfShortenedText(String text) {
        if (lastSearchIndex >= text.length()) {
            lastSearchIndex = 0;
        }
    }

    private void searchWasNotSuccessfull() {
        say("Suchbegriff '" + searchText + "' nicht im Text gefunden.");
    }

    private void searchAgainWithValidIndex(int index) {
        lastSearchIndex = index + searchText.length();
        say("Suchbegriff '" + searchText + "' an Position " + index + " bis " + lastSearchIndex
                + " im Text gefunden.");

        //editor.setCaretPosition(index);
        editor.select(index, lastSearchIndex); // setzt die CaretPosition auch.
    }

    private void say(String message) {
        if (DEBUG) {
            String filename = editor.getFilename();
            String title = "(" + (null == filename  ? "unknown" : filename) + ") - ";
            DebugHelper.sayWithClassAndMethodAndTime(title + message);
        }
    }

}
