package eu.dnetlib.lbs.subscriptions;

import java.util.Arrays;
import java.util.Date;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import eu.dnetlib.lbs.utils.DateParser;

public class ConditionParams {

	private String value;
	private String otherValue;

	public ConditionParams() {}

	public ConditionParams(final String value, final String otherValue) {
		this.value = value;
		this.otherValue = otherValue;
	}

	public String getValue() {
		return this.value;
	}

	public void setValue(final String value) {
		this.value = value;
	}

	public String getOtherValue() {
		return this.otherValue;
	}

	public void setOtherValue(final String otherValue) {
		this.otherValue = otherValue;
	}

	public boolean verify(final String s, final ConditionOperator operator) {
		final Set<String> set = tokenize(s);

		switch (operator) {
		case EXACT:
			return StringUtils.equalsIgnoreCase(s, this.value);
		case MATCH_ANY:
			return tokenize(this.value).stream().anyMatch(set::contains);
		case MATCH_ALL:
			return tokenize(this.value).stream().allMatch(set::contains);
		case RANGE:
			return (this.value == null || s.compareTo(this.value) >= 0) && (this.otherValue == null || s.compareTo(this.otherValue) <= 0);
		default:
		}
		return true;
	}

	public boolean verify(final boolean b, final ConditionOperator operator) {
		switch (operator) {
		case EXACT:
		case MATCH_ANY:
		case MATCH_ALL:
			return b == (this.value.equalsIgnoreCase("true"));
		default:
			return false;
		}
	}

	public boolean verify(final double n, final ConditionOperator operator) {
		switch (operator) {
		case EXACT:
		case MATCH_ANY:
		case MATCH_ALL:
			return n == NumberUtils.toDouble(this.value, 0);
		case RANGE:
			return (n >= NumberUtils.toDouble(this.value, Double.MIN_VALUE)
					&& (n <= NumberUtils.toDouble(this.otherValue, Double.MAX_VALUE)));
		default:
			return false;
		}
	}

	public boolean verify(final Date date, final ConditionOperator operator) {
		if (date == null) { return false; }

		switch (operator) {
		case EXACT:
		case MATCH_ANY:
		case MATCH_ALL:
			return date.getTime() == DateParser.parse(this.value).getTime();
		case RANGE:
			final Date min = DateParser.parse(this.value);
			final Date max = DateParser.parse(this.otherValue);
			final long t = date.getTime();
			return (min == null || t >= min.getTime()) && (max == null || t <= max.getTime());
		default:
			return false;
		}
	}

	private Set<String> tokenize(final String s) {
		return Arrays.stream(s.replaceAll("[^a-zA-Z0-9]", " ").toLowerCase().split(" "))
				.map(String::trim)
				.filter(StringUtils::isNotBlank)
				.collect(Collectors.toSet());
	}
}
