package com.knecon.fforesight.service.layoutparser.processor.model.graph.textblock;

import static java.lang.String.format;

import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.knecon.fforesight.service.layoutparser.processor.model.graph.TextRange;
import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Page;

public interface TextBlock extends CharSequence {

    String getSearchText();


    List<AtomicTextBlock> getAtomicTextBlocks();


    List<TextRange> getBoldTextBoundaries();


    List<TextRange> getItalicTextBoundaries();


    String getOrientation();


    int getTextDirection();


    TextRange getTextRange();


    int getNextLinebreak(int fromIndex);


    int getPreviousLinebreak(int fromIndex);


    List<Integer> getLineBreaks();


    Rectangle2D getPosition(int stringIdx);


    List<Rectangle2D> getPositions(TextRange stringTextRange);


    Map<Page, List<Rectangle2D>> getPositionsPerPage(TextRange stringTextRange);


    int numberOfLines();


    String subSequenceWithLineBreaks(TextRange stringTextRange);


    default String searchTextWithLineBreaks() {

        return subSequenceWithLineBreaks(getTextRange());
    }

    default int indexOf(String searchTerm) {

        return indexOf(searchTerm, getTextRange().start());
    }


    default Set<Page> getPages() {

        return getAtomicTextBlocks().stream()
                .map(AtomicTextBlock::getPage)
                .collect(Collectors.toUnmodifiableSet());
    }


    default Set<Page> getPages(TextRange textRange) {

        return getAtomicTextBlocks().stream()
                .filter(atomicTextBlock -> atomicTextBlock.getTextRange().intersects(textRange))
                .map(AtomicTextBlock::getPage)
                .collect(Collectors.toUnmodifiableSet());
    }


    default int indexOf(String searchTerm, int startOffset) {

        int start = getSearchText().indexOf(searchTerm, startOffset - getTextRange().start());
        if (start == -1) {
            return -1;
        }
        return start + getTextRange().start();
    }


    default CharSequence getFirstLine() {

        return subSequence(getTextRange().start(), getNextLinebreak(getTextRange().start()));
    }


    default boolean containsBoundary(TextRange textRange) {

        if (textRange.end() < textRange.start()) {
            throw new IllegalArgumentException(format("Invalid %s, StartIndex must be smaller than EndIndex", textRange));
        }
        return getTextRange().contains(textRange);
    }


    default boolean containsIndex(int stringIndex) {

        return getTextRange().containsExclusive(stringIndex);
    }


    default CharSequence subSequence(TextRange textRange) {

        return subSequence(textRange.start(), textRange.end());
    }


    default String buildSummary() {

        String[] words = getSearchText().split(" ");
        int bound = Math.min(words.length, 4);
        List<String> list = new ArrayList<>(Arrays.asList(words).subList(0, bound));

        return String.join(" ", list);
    }


    @Override
    default CharSequence subSequence(int start, int end) {

        return getSearchText().substring(start - getTextRange().start(), end - getTextRange().start());
    }


    @Override
    default int length() {

        return getTextRange().length();
    }


    @Override
    default char charAt(int index) {

        return getSearchText().charAt(index - getTextRange().start());
    }

}
