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


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

    private DateFilterFactory() {
    }

    public static DateFilter newMinimumFilter(FuzzyDate date) {
        if (date == null) {
            throw new IllegalArgumentException("date is null");
        }
        return new ExtremumDateFilter(date, false);
    }

    public static DateFilter newMaximumFilter(FuzzyDate date) {
        if (date == null) {
            throw new IllegalArgumentException("date is null");
        }
        return new ExtremumDateFilter(date, true);
    }

    public static RangeDateFilter newInstance(FuzzyDate date) {
        return new UniqueDateFilter(date);
    }

    public static RangeDateFilter newInstance(FuzzyDate date1, FuzzyDate date2) {
        if (date1 == null) {
            throw new IllegalArgumentException("date1 is null");
        }
        if (date2 == null) {
            throw new IllegalArgumentException("date2 is null");
        }
        int comp = date1.compareTo(date2);
        if (comp == 0) {
            return new UniqueDateFilter(date1);
        }
        if (comp > 0) {
            return newInstance(date2, date1);
        }
        return new DoubleDateFilter(date1, date2);

    }


    private static class UniqueDateFilter implements RangeDateFilter {

        private final FuzzyDate filterDate;
        private final short truncateType;

        private UniqueDateFilter(FuzzyDate filterDate) {
            this.filterDate = filterDate;
            this.truncateType = filterDate.getType();
        }

        @Override
        public boolean containsDate(FuzzyDate date) {
            if (date == null) {
                return false;
            }
            date = date.truncate(truncateType);
            return (date.equals(filterDate));
        }

        @Override
        public FuzzyDate getMinDate() {
            return filterDate;
        }

        @Override
        public FuzzyDate getMaxDate() {
            return filterDate;
        }

        @Override
        public int testInRange(FuzzyDate date) {
            date = date.truncate(truncateType);
            return date.compareTo(filterDate);
        }

    }


    private static class DoubleDateFilter implements RangeDateFilter {

        private final FuzzyDate filterDate1;
        private final FuzzyDate filterDate2;
        private final short truncateType1;
        private final short truncateType2;

        private DoubleDateFilter(FuzzyDate filterDate1, FuzzyDate filterDate2) {
            this.filterDate1 = filterDate1;
            this.filterDate2 = filterDate2;
            this.truncateType1 = filterDate1.getType();
            this.truncateType2 = filterDate2.getType();
        }

        @Override
        public boolean containsDate(FuzzyDate date) {
            if (date == null) {
                return false;
            }
            FuzzyDate date1 = date.truncate(truncateType1);
            if (date1.compareTo(filterDate1) < 0) {
                return false;
            }
            FuzzyDate date2 = date.truncate(truncateType2);
            return (date2.compareTo(filterDate2) <= 0);
        }

        @Override
        public FuzzyDate getMinDate() {
            return filterDate1;
        }

        @Override
        public FuzzyDate getMaxDate() {
            return filterDate2;
        }

        @Override
        public int testInRange(FuzzyDate date) {
            if (date == null) {
                return -1;
            }
            FuzzyDate date1 = date.truncate(truncateType1);
            if (date1.compareTo(filterDate1) < 0) {
                return -1;
            }
            FuzzyDate date2 = date.truncate(truncateType2);
            if (date2.compareTo(filterDate2) <= 0) {
                return 0;
            } else {
                return 1;
            }
        }

    }


    private static class ExtremumDateFilter implements DateFilter {

        private final FuzzyDate extremumDate;
        private final boolean isMaximum;

        private ExtremumDateFilter(FuzzyDate extremumDate, boolean isMaximum) {
            this.extremumDate = extremumDate;
            this.isMaximum = isMaximum;
        }

        @Override
        public boolean containsDate(FuzzyDate date) {
            if (date == null) {
                return false;
            }
            if (isMaximum) {
                return date.compareTo(extremumDate) <= 0;
            } else {
                return date.compareTo(extremumDate) >= 0;
            }
        }

    }

}
