/* UtilLib - Copyright (c) 2012-2017 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.date;

import java.text.ParseException;
import java.util.AbstractList;
import java.util.List;
import java.util.RandomAccess;
import net.mapeadores.util.text.StringUtils;


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

    public final static DateFilter NULL_FILTER = new NullDateFilter(true);
    public final static DateFilter NOTNULL_FILTER = new NullDateFilter(false);

    private DateFilterUtils() {
    }

    public static RangeDateFilter parseDateFilter(String s) throws ParseException {
        String[] tokens = StringUtils.getTechnicalTokens(s, false);
        int length = tokens.length;
        if (length == 0) {
            return null;
        }
        if (length > 2) {
            throw new ParseException("Too many tokens", s.length() - 1);
        }
        if (length == 1) {
            FuzzyDate date = FuzzyDate.parse(tokens[0]);
            return DateFilterFactory.newInstance(date);
        } else {
            FuzzyDate date1;
            FuzzyDate date2;
            date1 = FuzzyDate.parse(tokens[0]);
            date2 = FuzzyDate.parse(tokens[1]);
            return DateFilterFactory.newInstance(date1, date2);
        }
    }

    public static String toString(DateFilter dateFilter) {
        if (dateFilter instanceof RangeDateFilter) {
            RangeDateFilter rangeDateFilter = (RangeDateFilter) dateFilter;
            FuzzyDate min = rangeDateFilter.getMinDate();
            FuzzyDate max = rangeDateFilter.getMaxDate();
            if (min.equals(max)) {
                return min.toString();
            } else {
                return min.toString() + " ; " + max.toString();
            }
        }
        return "";
    }

    public static boolean intersects(FuzzyDate date, DateFilter dateFilter) {
        if (dateFilter.containsDate(date)) {
            return true;
        }
        if (!(dateFilter instanceof RangeDateFilter)) {
            return false;
        }
        if (date == null) {
            return false;
        }
        return intersects((RangeDateFilter) dateFilter, DateFilterFactory.newInstance(date));
    }

    public static boolean intersects(FuzzyDate date1, FuzzyDate date2, DateFilter dateFilter) {
        if (dateFilter.containsDate(date1)) {
            return true;
        }
        if (dateFilter.containsDate(date2)) {
            return true;
        }
        if (!(dateFilter instanceof RangeDateFilter)) {
            return false;
        }
        if (date1 == null) {
            return false;
        }
        if (date2 == null) {
            return false;
        }
        return intersects((RangeDateFilter) dateFilter, DateFilterFactory.newInstance(date1, date2));
    }

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

    private static boolean intersects(RangeDateFilter rangeDateFilter, DateFilter otherFilter) {
        FuzzyDate min = rangeDateFilter.getMinDate();
        FuzzyDate max = rangeDateFilter.getMaxDate();
        if (min.equals(max)) {
            return otherFilter.containsDate(min);
        } else {
            return (otherFilter.containsDate(min) || otherFilter.containsDate(max));
        }
    }


    private static class NullDateFilter implements DateFilter {

        private final boolean isNull;

        private NullDateFilter(boolean isNull) {
            this.isNull = isNull;
        }

        @Override
        public boolean containsDate(FuzzyDate date) {
            if (date == null) {
                return isNull;
            } else {
                return !isNull;
            }
        }

    }


    private static class DateFilterList extends AbstractList<DateFilter> implements RandomAccess {

        private final DateFilter[] array;

        private DateFilterList(DateFilter[] array) {
            this.array = array;
        }

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

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

    }

}
