package de.renew.unify;

import java.util.Collections;
import java.util.Set;

import org.apache.log4j.Logger;

class EstimateVisitor implements TupleIndexVisitor {
    public static final Logger LOGGER = Logger.getLogger(EstimateVisitor.class);

    private Set<Object> _bestSet = null;

    /**
     * Returns the best set of elements found so far.
     *
     * @return the best set of elements
     */
    public Set<Object> getBestSet() {
        return _bestSet;
    }

    void possibleCollection(Set<Object> set) {
        int size = set.size();
        if (_bestSet == null || size < _bestSet.size()) {
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace(" ---> found good enumeration: size " + size);
            }
            _bestSet = set;
        }
    }

    @Override
    public void visitBranch(ComponentBranch branch) {
        // The remainder cannot match any other elements besides those in
        // the element set of the branch.
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("EstVis: visiting comp. branch " + branch.getAllElements());
        }
        possibleCollection(branch.getAllElements());
    }

    @Override
    public boolean visitIndex(ArityBranch branch, Object remainder) {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("EstVis: visiting arity branch " + branch.getHashCodeRelation());
            LOGGER.trace("        with remainder " + remainder);
        }
        if (Unify.isBound(remainder)) {
            // The remainder is well known. We can look up the
            // matching elements. There is no need to proceed
            // down the search tree.
            possibleCollection(
                branch.getHashCodeRelation().elementsAt(TupleIndex.theHashCode(remainder)));
            return false;
        } else if (remainder instanceof Aggregate) {
            // The remainder is a non-empty aggregate that is at least partially
            // unbound. It will be processed later.
            return true;
        } else if (remainder instanceof Calculator) {
            // The remainder will be calculated later. Hence, the entire
            // object cannot be bound now.
            possibleCollection(Collections.emptySet());
            return false;
        } else {
            // The remainder is an unknown or a variable.
            // All possible elements were already considered
            // in the node above the branch.
            return false;
        }
    }
}