package org.xbib.logging.filters;

import java.util.Iterator;
import java.util.logging.Filter;
import java.util.logging.LogRecord;

/**
 * A filter consisting of several filters in a chain. If any filter finds the log message to be unloggable,
 * the message will not be logged and subsequent filters will not be checked. If there are no nested filters,
 * this instance always returns {@code true}.
 */
public final class AllFilter implements Filter {

    private final Filter[] filters;

    /**
     * Construct a new instance.
     *
     * @param filters the constituent filters
     */
    public AllFilter(final Filter[] filters) {
        this.filters = filters.clone();
    }

    /**
     * Construct a new instance.
     *
     * @param filters the constituent filters
     */
    public AllFilter(final Iterable<Filter> filters) {
        this(filters.iterator());
    }

    /**
     * Construct a new instance.
     *
     * @param filters the constituent filters
     */
    public AllFilter(final Iterator<Filter> filters) {
        this.filters = unroll(filters, 0);
    }

    private static Filter[] unroll(Iterator<Filter> iter, int cnt) {
        if (iter.hasNext()) {
            final Filter filter = iter.next();
            if (filter == null) {
                throw new NullPointerException("filter at index " + cnt + " is null");
            }
            final Filter[] filters = unroll(iter, cnt + 1);
            filters[cnt] = filter;
            return filters;
        } else {
            return new Filter[cnt];
        }
    }

    /**
     * Determine whether the record is loggable.
     *
     * @param record the log record
     * @return {@code true} if all the constituent filters return {@code true}
     */
    @Override
    public boolean isLoggable(final LogRecord record) {
        for (Filter filter : filters) {
            if (!filter.isLoggable(record)) {
                return false;
            }
        }
        return true;
    }
}
