/* UtilLib - Copyright (c) 2006-2023 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.conditions;

import java.util.AbstractList;
import java.util.List;
import java.util.RandomAccess;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.text.TextConstants;
import net.mapeadores.util.text.search.MultiSearchToken;
import net.mapeadores.util.text.search.SearchToken;
import net.mapeadores.util.text.search.SearchTokenParser;
import net.mapeadores.util.text.search.SimpleSearchToken;


/**
 *
 * @author Vincent Calame
 */
public final class ConditionsUtils {

    public final static TextTest EMPTY_TEXTTEST = new InternalTextTest(ConditionsConstants.EMPTY_TEST, "");
    public final static TextTest FILLED_TEXTTEST = new InternalTextTest(ConditionsConstants.NOT_EMPTY_TEST, "");

    private ConditionsUtils() {
    }

    /*public static short getModeInverse(short logicalOperator) {
        if (logicalOperator == ConditionsConstants.LOGICALOPERATOR_AND) {
            return ConditionsConstants.LOGICALOPERATOR_OR;
        }
        return ConditionsConstants.LOGICALOPERATOR_AND;
    }*/

    public static boolean accept(TextTest textTest, String contentString) {
        if (contentString == null) {
            contentString = "";
        }
        short testType = textTest.getTestType();
        if (testType == ConditionsConstants.EMPTY_TEST) {
            return (contentString.length() == 0);
        }
        if (testType == ConditionsConstants.NOT_EMPTY_TEST) {
            return (contentString.length() > 0);
        }
        String testString = textTest.getText().toLowerCase();
        contentString = contentString.toLowerCase();
        if (isExcludingPartTestType(testType)) {
            switch (testType) {
                case ConditionsConstants.NOT_MATCHES_TEST:
                    return !contentString.equals(testString);
                case ConditionsConstants.NOT_STARTSWITH_TEST:
                    return !contentString.startsWith(testString);
                case ConditionsConstants.NOT_ENDSWITH_TEST:
                    return !contentString.endsWith(testString);
                default:
                    return !contentString.contains(testString);
            }
        } else {
            switch (testType) {
                case ConditionsConstants.MATCHES_TEST:
                    return contentString.equals(testString);
                case ConditionsConstants.STARTSWITH_TEST:
                    return contentString.startsWith(testString);
                case ConditionsConstants.ENDSWITH_TEST:
                    return contentString.endsWith(testString);
                default:
                    return contentString.contains(testString);
            }
        }
    }

    /**
     * Si la chaine ne contient aucun des caractères suivants : *; alors les
     * espaces de la chaine sont traités comme des séparateurs
     */
    public static TextCondition parseSimpleCondition(String conditionString) {
        if (conditionString == null) {
            return null;
        }
        conditionString = conditionString.trim();
        int length = conditionString.length();
        if (length == 0) {
            return null;
        }
        String operator = ConditionsConstants.LOGICALOPERATOR_AND;
        if (conditionString.charAt(0) == '|') {
            if (length == 1) {
                return null;
            }
            operator = ConditionsConstants.LOGICALOPERATOR_OR;
            conditionString = conditionString.substring(1).trim();
        }
        return parseSimpleCondition(conditionString, operator);
    }

    /**
     * Si la chaine ne contient aucun des caractères suivants : *; alors les
     * espaces de la chaine sont traités comme des séparateurs
     */
    public static TextCondition parseSimpleCondition(String conditionString, String operator) {
        if (conditionString == null) {
            return null;
        }
        conditionString = conditionString.trim();
        int length = conditionString.length();
        if (length == 0) {
            return null;
        }
        if ((length == 1) && (conditionString.charAt(0) == '!')) {
            return null;
        }
        for (int i = 0; i < length; i++) {
            char carac = conditionString.charAt(i);
            switch (carac) {
                case '*':
                case ';':
                    return parseCondition(conditionString, operator);
            }
        }
        TextConditionBuilder conditionBuilder = new TextConditionBuilder(operator);
        String[] tokens = StringUtils.getTokens(conditionString, ' ', StringUtils.EMPTY_EXCLUDE);
        for (String token : tokens) {
            short testType = ConditionsConstants.CONTAINS_TEST;
            if (token.charAt(0) == '!') {
                if (token.length() == 1) {
                    continue;
                }
                testType = ConditionsConstants.NOT_CONTAINS_TEST;
                token = token.substring(1);
            }
            conditionBuilder.addTextTest(toTextTest(testType, token));
        }
        return conditionBuilder.toTextCondition();
    }

    public static TextCondition parseSequenceCondition(String conditionString, String operator) {
        if (conditionString == null) {
            return null;
        }
        conditionString = conditionString.trim();
        int length = conditionString.length();
        if (length == 0) {
            return null;
        }
        List<SearchToken> searchTokenList = SearchTokenParser.parse(operator, TextConstants.STARTSWITH);
        if (searchTokenList.isEmpty()) {
            return null;
        }
        TextConditionBuilder conditionBuilder = new TextConditionBuilder(operator);
        for (SearchToken searchToken : searchTokenList) {
            if (searchToken instanceof SimpleSearchToken) {
                SimpleSearchToken simpleSearchToken = (SimpleSearchToken) searchToken;
                conditionBuilder.addTextTest(toTextTest(ConditionsConstants.convertSearchType(simpleSearchToken.getSearchType()), simpleSearchToken.getTokenString()));
            } else {
                MultiSearchToken multiSearchToken = (MultiSearchToken) searchToken;
                int count = multiSearchToken.getSubtokenCount();
                StringBuilder buf = new StringBuilder();
                for (int i = 0; i < count; i++) {
                    if (i > 0) {
                        buf.append(' ');
                    }
                    buf.append(multiSearchToken.getSubtoken(i).getTokenString());
                }
                conditionBuilder.addTextTest(toTextTest(ConditionsConstants.MATCHES_TEST, buf.toString()));
            }

        }
        return conditionBuilder.toTextCondition();
    }


    /**
     * Reconstruit une instance de Condition à partir d'une chaîne. Le
     * point-virgule est le séparateur des différentes conditions.
     */
    public static TextCondition parseCondition(String conditionString, String operator) {
        TextConditionBuilder conditionBuilder = new TextConditionBuilder(operator);
        int length = conditionString.length();
        boolean previousEscaped = false;
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < length; i++) {
            char carac = conditionString.charAt(i);
            if (previousEscaped) {
                if (carac != ';') {
                    buf.append('\\');
                }
                buf.append(carac);
                previousEscaped = false;
            } else {
                if (carac == ';') {
                    if (buf.length() > 0) {
                        conditionBuilder.addTextTest(buf.toString());
                        buf = new StringBuilder();
                    }

                } else if (carac == '\\') {
                    previousEscaped = true;
                } else {
                    buf.append(carac);
                }
            }
        }
        if (previousEscaped) {
            buf.append('\\');
        }
        conditionBuilder.addTextTest(buf.toString());
        return conditionBuilder.toTextCondition();
    }

    /**
     * Reconstruit une instance de TextTest à partir d'une chaîne.
     */
    public static TextTest parseTextTest(String testString) {
        if (testString == null) {
            return null;
        }
        testString = testString.trim();
        if (testString.length() == 0) {
            return null;
        }
        boolean non = (testString.charAt(0) == '!');
        if ((non) && (testString.length() == 1)) {
            return EMPTY_TEXTTEST;
        }
        if (non) {
            testString = testString.substring(1);
        }
        String text;
        short testType;
        boolean commence = false;
        if ((testString.charAt(0) == '*') || (testString.charAt(0) == '%')) {
            commence = true;
            text = testString.substring(1);
        } else if (testString.startsWith("..")) {
            commence = true;
            text = testString.substring(2);
        } else {
            text = testString;
        }
        text = StringUtils.cleanString(text);
        int taille = text.length();
        if (text.length() == 0) {
            if (non) {
                return EMPTY_TEXTTEST;
            } else {
                return FILLED_TEXTTEST;
            }
        } else {
            boolean finit = false;
            if ((text.charAt(taille - 1) == '*') || (text.charAt(taille - 1) == '%')) {
                text = text.substring(0, taille - 1);
                finit = true;
            } else if (text.endsWith("..")) {
                text = text.substring(0, taille - 2);
                finit = true;
            }
            if (commence) {
                if (finit) {
                    if (non) {
                        testType = ConditionsConstants.NOT_CONTAINS_TEST;
                    } else {
                        testType = ConditionsConstants.CONTAINS_TEST;
                    }
                } else {
                    if (non) {
                        testType = ConditionsConstants.NOT_ENDSWITH_TEST;
                    } else {
                        testType = ConditionsConstants.ENDSWITH_TEST;
                    }
                }
            } else {
                if (finit) {
                    if (non) {
                        testType = ConditionsConstants.NOT_STARTSWITH_TEST;
                    } else {
                        testType = ConditionsConstants.STARTSWITH_TEST;
                    }
                } else {
                    if (non) {
                        testType = ConditionsConstants.NOT_MATCHES_TEST;
                    } else {
                        testType = ConditionsConstants.MATCHES_TEST;
                    }
                }
            }
        }
        return toTextTest(testType, text);
    }

    public static TextTest toOpposite(TextTest textTest) {
        short oppositeType = getOppositeTestType(textTest.getTestType());
        return toTextTest(oppositeType, textTest.getText());
    }

    public static short getOppositeTestType(short testType) {
        switch (testType) {
            case ConditionsConstants.STARTSWITH_TEST:
                return ConditionsConstants.NOT_STARTSWITH_TEST;
            case ConditionsConstants.ENDSWITH_TEST:
                return ConditionsConstants.NOT_ENDSWITH_TEST;
            case ConditionsConstants.CONTAINS_TEST:
                return ConditionsConstants.NOT_CONTAINS_TEST;
            case ConditionsConstants.MATCHES_TEST:
                return ConditionsConstants.NOT_MATCHES_TEST;
            case ConditionsConstants.EMPTY_TEST:
                return ConditionsConstants.NOT_EMPTY_TEST;
            case ConditionsConstants.NOT_STARTSWITH_TEST:
                return ConditionsConstants.STARTSWITH_TEST;
            case ConditionsConstants.NOT_ENDSWITH_TEST:
                return ConditionsConstants.ENDSWITH_TEST;
            case ConditionsConstants.NOT_CONTAINS_TEST:
                return ConditionsConstants.CONTAINS_TEST;
            case ConditionsConstants.NOT_MATCHES_TEST:
                return ConditionsConstants.MATCHES_TEST;
            case ConditionsConstants.NOT_EMPTY_TEST:
                return ConditionsConstants.EMPTY_TEST;
            default:
                return -1;
        }
    }

    public static String toSQL(TextTest textTest) {
        StringBuilder buf = new StringBuilder();
        switch (textTest.getTestType()) {
            case ConditionsConstants.EMPTY_TEST:
                buf.append(" IS NULL");
                break;
            case ConditionsConstants.NOT_EMPTY_TEST:
                buf.append(" IS NOT NULL");
                break;
            case ConditionsConstants.STARTSWITH_TEST:
                buf.append(" LIKE '");
                preparation(buf, textTest);
                buf.append("%'");
                break;
            case ConditionsConstants.ENDSWITH_TEST:
                buf.append(" LIKE '%");
                preparation(buf, textTest);
                buf.append("'");
                break;
            case ConditionsConstants.CONTAINS_TEST:
                buf.append(" LIKE '%");
                preparation(buf, textTest);
                buf.append("%'");
                break;
            case ConditionsConstants.MATCHES_TEST:
                buf.append(" LIKE '");
                preparation(buf, textTest);
                buf.append("'");
                break;
            case ConditionsConstants.NOT_STARTSWITH_TEST:
                buf.append(" NOT LIKE '%");
                preparation(buf, textTest);
                buf.append("%'");
                break;
            case ConditionsConstants.NOT_ENDSWITH_TEST:
                buf.append(" NOT LIKE '%");
                preparation(buf, textTest);
                buf.append("'");
                break;
            case ConditionsConstants.NOT_CONTAINS_TEST:
                buf.append(" NOT LIKE '%");
                preparation(buf, textTest);
                buf.append("%'");
                break;
            case ConditionsConstants.NOT_MATCHES_TEST:
                buf.append(" NOT LIKE '");
                preparation(buf, textTest);
                buf.append("'");
                break;
        }
        return buf.toString();
    }

    private static void preparation(StringBuilder buf, TextTest textTest) {
        String text = textTest.getText();
        for (int i = 0; i < text.length(); i++) {
            char carac = text.charAt(i);
            if (carac == '\'') {
                buf.append("''");
            } else {
                buf.append(carac);
            }
        }
    }

    public static boolean isExcludingPartTestType(short testType) {
        switch (testType) {
            case ConditionsConstants.NOT_STARTSWITH_TEST:
            case ConditionsConstants.NOT_ENDSWITH_TEST:
            case ConditionsConstants.NOT_CONTAINS_TEST:
            case ConditionsConstants.NOT_MATCHES_TEST:
            case ConditionsConstants.EMPTY_TEST:
                return true;
            default:
                return false;
        }
    }

    public static boolean isIncludingPartTestType(short testType) {
        switch (testType) {
            case ConditionsConstants.STARTSWITH_TEST:
            case ConditionsConstants.ENDSWITH_TEST:
            case ConditionsConstants.CONTAINS_TEST:
            case ConditionsConstants.MATCHES_TEST:
            case ConditionsConstants.NOT_EMPTY_TEST:
                return true;
            default:
                return false;
        }
    }

    public static String conditionToSimpleString(TextCondition condition, boolean withOperator) {
        if (!isSimpleCondition(condition)) {
            String conditionString = conditionToString(condition);
            if (conditionString.length() > 0) {
                String operatorPrefix = ((withOperator) && (condition.isOrOperator())) ? "|" : "";
                conditionString = operatorPrefix + conditionString + ";";
            }
            return conditionString;
        } else {
            StringBuilder buf = new StringBuilder();
            if ((withOperator) && (condition.isOrOperator())) {
                buf.append('|');
            }
            for (TextTest textTest : condition.getIncludingTextTestList()) {
                buf.append(textTest.getText());
                buf.append(' ');
            }
            for (TextTest textTest : condition.getExcludingTextTestList()) {
                buf.append('!');
                buf.append(textTest.getText());
                buf.append(' ');
            }
            return buf.toString();
        }
    }

    public static String conditionToString(TextCondition condition) {
        StringBuilder buf = new StringBuilder();
        boolean next = false;
        for (TextTest textTest : condition.getIncludingTextTestList()) {
            if (next) {
                buf.append(';');
            } else {
                next = true;
            }
            buf.append(textTest.getCompleteText());
        }
        for (TextTest textTest : condition.getExcludingTextTestList()) {
            if (next) {
                buf.append(';');
            } else {
                next = true;
            }
            buf.append(textTest.getCompleteText());
        }
        return buf.toString();
    }

    public static String testTypeToString(short testType) {
        switch (testType) {
            case ConditionsConstants.STARTSWITH_TEST:
                return ".*";
            case ConditionsConstants.ENDSWITH_TEST:
                return "*.";
            case ConditionsConstants.CONTAINS_TEST:
                return "*.*";
            case ConditionsConstants.MATCHES_TEST:
                return ".";
            case ConditionsConstants.EMPTY_TEST:
                return "!*";
            case ConditionsConstants.NOT_STARTSWITH_TEST:
                return "!.*";
            case ConditionsConstants.NOT_ENDSWITH_TEST:
                return "!*.";
            case ConditionsConstants.NOT_CONTAINS_TEST:
                return "!*.*";
            case ConditionsConstants.NOT_MATCHES_TEST:
                return "!.";
            case ConditionsConstants.NOT_EMPTY_TEST:
                return "*";
            default:
                throw new IllegalArgumentException("wrong testType value = " + testType);
        }
    }

    public static short testTypeToShort(String type) {
        if (type.equals(".*")) {
            return ConditionsConstants.STARTSWITH_TEST;
        } else if (type.equals("*.")) {
            return ConditionsConstants.ENDSWITH_TEST;
        } else if (type.equals("*.*")) {
            return ConditionsConstants.CONTAINS_TEST;
        } else if (type.equals(".")) {
            return ConditionsConstants.MATCHES_TEST;
        } else if (type.equals("!*")) {
            return ConditionsConstants.EMPTY_TEST;
        } else if (type.equals("!.*")) {
            return ConditionsConstants.NOT_STARTSWITH_TEST;
        } else if (type.equals("!*.")) {
            return ConditionsConstants.NOT_ENDSWITH_TEST;
        } else if (type.equals("!*.*")) {
            return ConditionsConstants.NOT_CONTAINS_TEST;
        } else if (type.equals("!.")) {
            return ConditionsConstants.NOT_MATCHES_TEST;
        } else if (type.equals("*")) {
            return ConditionsConstants.NOT_EMPTY_TEST;
        } else {
            throw new IllegalArgumentException("wrong type value = " + type);
        }
    }

    /**
     *
     * @throws IllegalArgumentException si testType est inconnu.
     */
    public static short getState(TextTest textTest) {
        switch (textTest.getTestType()) {
            case ConditionsConstants.STARTSWITH_TEST:
            case ConditionsConstants.ENDSWITH_TEST:
            case ConditionsConstants.CONTAINS_TEST:
            case ConditionsConstants.MATCHES_TEST:
                return ConditionsConstants.PARTIAL_CONDITION;
            case ConditionsConstants.EMPTY_TEST:
                return ConditionsConstants.EMPTY_CONDITION;
            case ConditionsConstants.NOT_STARTSWITH_TEST:
            case ConditionsConstants.NOT_ENDSWITH_TEST:
            case ConditionsConstants.NOT_CONTAINS_TEST:
            case ConditionsConstants.NOT_MATCHES_TEST:
                return ConditionsConstants.PARTIALOREMPTY_CONDITION;
            case ConditionsConstants.NOT_EMPTY_TEST:
                return ConditionsConstants.NOTEMPTY_CONDITION;
            default:
                throw new IllegalArgumentException("unknown conditionType");
        }
    }

    public static short merge(String logicalOperator, short currentState, short addingState) {
        if (currentState == ConditionsConstants.UNKNOWN_CONDITION) {
            return addingState;
        }
        if (currentState == addingState) {
            return currentState;
        }
        if (logicalOperator.equals(ConditionsConstants.LOGICALOPERATOR_AND)) {
            return mergeAndMode(currentState, addingState);
        } else {
            return mergeOrMode(currentState, addingState);
        }
    }

    public static short mergeAndMode(short currentState, short addingState) {
        if (currentState == ConditionsConstants.IMPOSSIBLE_CONDITION) {
            return ConditionsConstants.IMPOSSIBLE_CONDITION;
        }
        if (currentState == ConditionsConstants.NEUTRAL_CONDITION) {
            return addingState;
        }
        if (currentState == ConditionsConstants.EMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.NOTEMPTY_CONDITION:
                case ConditionsConstants.PARTIAL_CONDITION:
                    return ConditionsConstants.IMPOSSIBLE_CONDITION;
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.EMPTY_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.NOTEMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.IMPOSSIBLE_CONDITION;
                case ConditionsConstants.PARTIAL_CONDITION:
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.PARTIAL_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.PARTIAL_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.IMPOSSIBLE_CONDITION;
                case ConditionsConstants.NOTEMPTY_CONDITION:
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.PARTIAL_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.PARTIALOREMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.EMPTY_CONDITION;
                case ConditionsConstants.NOTEMPTY_CONDITION:
                case ConditionsConstants.PARTIAL_CONDITION:
                    return ConditionsConstants.PARTIAL_CONDITION;
                default:
                    return currentState;
            }
        }
        throw new IllegalArgumentException();
    }

    public static short mergeOrMode(short currentState, short addingState) {
        if (currentState == ConditionsConstants.IMPOSSIBLE_CONDITION) {
            return addingState;
        }
        if (currentState == ConditionsConstants.NEUTRAL_CONDITION) {
            return ConditionsConstants.NEUTRAL_CONDITION;
        }
        if (currentState == ConditionsConstants.EMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.NOTEMPTY_CONDITION:
                    return ConditionsConstants.NEUTRAL_CONDITION;
                case ConditionsConstants.PARTIAL_CONDITION:
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.PARTIALOREMPTY_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.NOTEMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.NEUTRAL_CONDITION;
                case ConditionsConstants.PARTIAL_CONDITION:
                    return ConditionsConstants.NOTEMPTY_CONDITION;
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.NEUTRAL_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.PARTIAL_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.PARTIALOREMPTY_CONDITION;
                case ConditionsConstants.NOTEMPTY_CONDITION:
                    return ConditionsConstants.NOTEMPTY_CONDITION;
                case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                    return ConditionsConstants.PARTIALOREMPTY_CONDITION;
                default:
                    return currentState;
            }
        }
        if (currentState == ConditionsConstants.PARTIALOREMPTY_CONDITION) {
            switch (addingState) {
                case ConditionsConstants.EMPTY_CONDITION:
                    return ConditionsConstants.PARTIALOREMPTY_CONDITION;
                case ConditionsConstants.NOTEMPTY_CONDITION:
                    return ConditionsConstants.NEUTRAL_CONDITION;
                case ConditionsConstants.PARTIAL_CONDITION:
                    return ConditionsConstants.PARTIALOREMPTY_CONDITION;
                default:
                    return currentState;
            }
        }
        throw new IllegalArgumentException();
    }

    public static boolean isPartialState(short state) {
        return ((state == ConditionsConstants.PARTIAL_CONDITION) || (state == ConditionsConstants.PARTIALOREMPTY_CONDITION));
    }

    public static TextTest toTextTest(short testType, String text) {
        return new InternalTextTest(testType, text);
    }

    public static TextTest cloneTextTest(TextTest textTest) {
        short testType = textTest.getTestType();
        switch (testType) {
            case ConditionsConstants.EMPTY_TEST:
                return EMPTY_TEXTTEST;
            case ConditionsConstants.NOT_EMPTY_TEST:
                return FILLED_TEXTTEST;
            default:
                return new InternalTextTest(testType, textTest.getText());
        }
    }

    public static boolean isNeutral(TextCondition condition) {
        short state = getConditionType(condition);
        return ((state == ConditionsConstants.UNKNOWN_CONDITION) || (state == ConditionsConstants.NEUTRAL_CONDITION));
    }

    public static short getConditionType(TextCondition condition) {
        String logicalOperator = condition.getLogicalOperator();
        short state = ConditionsConstants.UNKNOWN_CONDITION;
        for (TextTest textTest : condition.getExcludingTextTestList()) {
            state = ConditionsUtils.merge(logicalOperator, state, ConditionsUtils.getState(textTest));
        }
        for (TextTest textTest : condition.getIncludingTextTestList()) {
            state = ConditionsUtils.merge(logicalOperator, state, ConditionsUtils.getState(textTest));
        }
        return state;
    }

    public static List<TextTest> wrap(TextTest[] array) {
        return new TextTestList(array);
    }

    private static boolean isSimpleCondition(TextCondition condition) {
        short conditionType = getConditionType(condition);
        List<TextTest> excludingTextTestList = condition.getExcludingTextTestList();
        if (conditionType == ConditionsConstants.PARTIALOREMPTY_CONDITION) {
            if (excludingTextTestList.isEmpty()) {
                return false;
            }
        } else if (conditionType != ConditionsConstants.PARTIAL_CONDITION) {
            return false;
        }
        for (TextTest textTest : condition.getIncludingTextTestList()) {
            if (textTest.getTestType() != ConditionsConstants.CONTAINS_TEST) {
                return false;
            }
            String text = textTest.getText();
            if (text.indexOf(' ') != -1) {
                return false;
            }
            if (text.equals("!")) {
                return false;
            }
            if (text.equals("|")) {
                return false;
            }
        }
        for (TextTest textTest : excludingTextTestList) {
            if (textTest.getTestType() != ConditionsConstants.NOT_CONTAINS_TEST) {
                return false;
            }
            String text = textTest.getText();
            if (text.indexOf(' ') != -1) {
                return false;
            }
        }
        return true;
    }


    private static class TextTestList extends AbstractList<TextTest> implements RandomAccess {

        private final TextTest[] array;

        private TextTestList(TextTest[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public TextTest get(int index) {
            return array[index];
        }

    }


    private static class InternalTextTest implements TextTest {

        private final short testType;
        private final String text;

        public InternalTextTest(short testType, String text) {
            this.testType = testType;
            this.text = text;
        }

        @Override
        public short getTestType() {
            return testType;
        }

        @Override
        public String getText() {
            return text;
        }


    }

}
