package net.sf.jabref.logic.search;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.regex.Pattern;

import com.google.common.eventbus.EventBus;

public class SearchQueryHighlightObservable {

    private final EventBus eventBus = new EventBus();

    private Optional<Pattern> pattern = Optional.empty();

    /**
     * Adds a SearchQueryHighlightListener to the search bar. The added listener is immediately informed about the current search.
     * Subscribers will be notified about searches.
     *
     * @param newListener SearchQueryHighlightListener to be added
     */
    public void addSearchListener(SearchQueryHighlightListener newListener) {
        Objects.requireNonNull(newListener);

        eventBus.register(newListener);
        newListener.highlightPattern(pattern);

    }

    public void removeSearchListener(SearchQueryHighlightListener listener) {
        Objects.requireNonNull(listener);

        try {
            eventBus.unregister(listener);
        } catch (IllegalArgumentException e) {
            // occurs if the event source has not been registered, should not prevent shutdown
        }
    }
    /**
     * Fires an event if a search was started (or cleared)
     *
     * @param searchQuery the search query
     */
    public void fireSearchlistenerEvent(SearchQuery searchQuery) {
        Objects.requireNonNull(searchQuery);

        // Parse the search string to words
        pattern = getPatternForWords(searchQuery.getSearchWords(), searchQuery.isRegularExpression(),
                searchQuery.isCaseSensitive());

        update();
    }

    public void reset() {
        pattern = Optional.empty();
        update();
    }

    private void update() {
        // Fire an event for every listener
        eventBus.post(pattern);
    }

    // Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled
    public static Optional<Pattern> getPatternForWords(List<String> words, boolean useRegex, boolean isCaseSensitive) {
        if ((words == null) || words.isEmpty() || words.get(0).isEmpty()) {
            return Optional.empty();
        }

        // compile the words to a regular expression in the form (w1)|(w2)|(w3)
        StringJoiner joiner = new StringJoiner(")|(", "(", ")");
        for (String word : words) {
            joiner.add(useRegex ? word : Pattern.quote(word));
        }
        String searchPattern = joiner.toString();

        if (isCaseSensitive) {
            return Optional.of(Pattern.compile(searchPattern));
        } else {
            return Optional.of(Pattern.compile(searchPattern, Pattern.CASE_INSENSITIVE));
        }
    }

}
