/*
 *  @author Ranides Atterwim <ranides@gmail.com>
 *  @copyright Ranides Atterwim
 *  @license WTFPL
 *  @url http://ranides.net/projects/assira
 */

package net.ranides.assira.generic;

import java.util.Comparator;

/**
 *
 * @author ranides
 */
@SuppressWarnings({"PMD.ShortVar", "PMD.ShortMethodName"})
public final class ValueUtils {

    private ValueUtils() { }

    /**
     * Zwraca pierwszą nie-nullową wartość, lub {@code null}, jeśli żaden argument
     * nie spełnia warunków.
     * @param <T>
     * @param values
     * @return
     */
    public static <T> T or(T... values) {
        for(T value : values) { if(null != value) { return value; } }
        return null;
    }

    /**
     * Zwraca pierwszą nie-nullową wartość, lub {@code null}, jeśli żaden argument
     * nie spełnia warunków.
     * @param <T>
     * @param a
     * @return
     */
    public static <T> T or(T a) {
        return a;
    }

    /**
     * Zwraca pierwszą nie-nullową wartość, lub {@code null}, jeśli żaden argument
     * nie spełnia warunków.
     * @param <T>
     * @param a
     * @param b
     * @return
     */
    public static <T> T or(T a, T b) {
        if(null!=a) { return a; }
        if(null!=b) { return b; }
        return null;
    }

    /**
     * Porównuje przekazane argumenty za pomocą funkcji equals.
     * <div class="message-note">{@code null} safe method</div>
     * @param <T>
     * @param a
     * @param b
     * @return
     */
    public static <T> boolean equals(T a, T b) {
        if(null==a) {
            return (null==b);
        }
        return a.equals(b);
    }

    /**
     * Jeśli oba argumenty są liczbami ({@code instanceof Number}) to porównuje z określoną precyzją.
     * Dla wszystkich innych argumentów dokonuje zwykłego porównania za pomocą
     * metody {@code equals}
     * @param <T>
     * @param a
     * @param b
     * @param precision
     * @return
     */
    public static <T> boolean equals(T a, T b, double precision) {
        if(a instanceof Number && b instanceof Number) {
            double fa = ((Number)a).doubleValue();
            double fb = ((Number)b).doubleValue();
            return Math.abs(fa - fb) <= precision;
        } else {
            return ValueUtils.equals(a, b);
        }
    }

    public static boolean isTrue(Object value) {
        return (value instanceof Boolean) && (Boolean)value;
    }

    public static boolean isFalse(Object value) {
        return (value instanceof Boolean) && !(Boolean)value;
    }
    
    public static int compare(Object value1, Object value2) {
        return NATURAL_COMPARATOR.compare(value1, value2);
    }

    public static final Comparator NATURAL_COMPARATOR = new Comparator() {
        @Override
        public int compare(Object a, Object b) {
            return ((Comparable)a).compareTo(b);
        }
    };

    public static <T extends Comparable<T>> Comparator<T> naturalComparator() {
        return NATURAL_COMPARATOR;
    }
}
