package ru.yandex.webmaster3.storage.util.clickhouse2.condition;

import org.apache.commons.lang3.ArrayUtils;
import ru.yandex.webmaster3.core.util.json.polymorphic.Polymorphic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author aherman
 */
public abstract class Condition implements Polymorphic<ConditionType> {
    private final ConditionType type;

    protected Condition(ConditionType type) {this.type = type;}

    public abstract String toQuery();

    public abstract <T> Predicate<T> toPredicate(ConditionFieldExtractor<T> fieldExtractor);

    @Override
    public ConditionType getType() {
        return type;
    }

    public Condition andThen(Condition condition) {
        return Condition.and(this, condition);
    }

    public static Condition trueCondition() {
        return ConstCondition.TRUE_CONDITION;
    }

    public static Condition falseCondition() {
        return ConstCondition.FALSE_CONDITION;
    }

    public static Condition and(List<? extends Condition> operands) {
        if (operands.isEmpty()) {
            return trueCondition();
        }
        if (operands.size() == 1) {
            return operands.get(0);
        }
        return new BoolOpCondition(BoolOpCondition.Operator.AND, new ArrayList<>(operands));
    }

    public static Condition and(Condition... operands) {
        if (ArrayUtils.isEmpty(operands)) {
            return trueCondition();
        }
        if (operands.length == 1) {
            return operands[0];
        }
        return new BoolOpCondition(BoolOpCondition.Operator.AND, Arrays.asList(operands));
    }

    public static Condition or(List<Condition> operands) {
        if (operands.isEmpty()) {
            return trueCondition();
        }
        if (operands.size() == 1) {
            return operands.get(0);
        }
        return new BoolOpCondition(BoolOpCondition.Operator.OR, operands);
    }

    public static Condition or(Condition... operands) {
        if (ArrayUtils.isEmpty(operands)) {
            return trueCondition();
        }
        if (operands.length == 1) {
            return operands[0];
        }
        return new BoolOpCondition(BoolOpCondition.Operator.OR, Arrays.asList(operands));
    }
}
