/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 * 
 *    (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    This package contains documentation from OpenGIS specifications.
 *    OpenGIS consortium's work is fully acknowledged here.
 */
package org.geotools.referencing.factory;

import java.util.Map;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.Collection;
import java.awt.RenderingHints;

import org.opengis.referencing.*;
import org.geotools.factory.Hints;


/**
 * The base class for authority factories that create referencing object directly. This is
 * in contrast with other factories like the {@linkplain AuthorityFactoryAdapter adapter}
 * or {@linkplain BufferedAuthorityFactory buffered} ones, which delegates their work to
 * an other factory.
 *
 * @since 2.3
 *
 * @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/DirectAuthorityFactory.java $
 * @version $Id: DirectAuthorityFactory.java 37299 2011-05-25 05:21:24Z mbedward $
 * @author Martin Desruisseaux (IRD)
 */
public abstract class DirectAuthorityFactory extends AbstractAuthorityFactory {

    // IMPLEMENTATION NOTE:  The reason why this class exist is that we don't want "indirect"
    // factories like BufferedAuthorityFactory to inherit the factories field.  If this field
    // existed in their super-class, then the super-class constructor could try to initialize
    // it while in fact BufferedAuthorityFactory don't need it.  Experience with Geotools 2.2
    // suggest that it can lead to tricky recursivity problems in FactoryFinder, because most
    // factories registered in META-INF/services are some kind of BufferedAuthorityFactory.

    /**
     * The underlying factories used for objects creation.
     */
    protected final ReferencingFactoryContainer factories;

    /**
     * Tells if {@link ReferencingFactoryContainer#hints} has been invoked. It must be
     * invoked exactly once, but can't be invoked in the constructor because it causes
     * a {@link StackOverflowError} in some situations.
     */
    private boolean hintsInitialized;

    /**
     * Constructs an instance using the specified set of factories.
     *
     * @param factories The low-level factories to use.
     * @param priority The priority for this factory, as a number between
     *        {@link #MINIMUM_PRIORITY MINIMUM_PRIORITY} and
     *        {@link #MAXIMUM_PRIORITY MAXIMUM_PRIORITY} inclusive.
     */
    protected DirectAuthorityFactory(final ReferencingFactoryContainer factories, final int priority) {
        super(priority);
        this.factories = factories;
        ensureNonNull("factories", factories);
    }

    /**
     * Returns the implementation hints for this factory. The returned map contains values for
     * {@link Hints#CRS_FACTORY CRS}, {@link Hints#CS_FACTORY CS}, {@link Hints#DATUM_FACTORY DATUM}
     * and {@link Hints#MATH_TRANSFORM_FACTORY MATH_TRANSFORM} {@code FACTORY} hints. Other values
     * may be provided as well, at implementation choice.
     */
    @Override
    public Map<RenderingHints.Key,?> getImplementationHints() {
        synchronized (hints) { // Note: avoid lock on public object.
            if (!hintsInitialized) {
                hintsInitialized = true;
                hints.putAll(factories.getImplementationHints());
            }
        }
        return super.getImplementationHints();
    }

    /**
     * Returns the direct {@linkplain Factory factory} dependencies.
     */
    @Override
    Collection<? super AuthorityFactory> dependencies() {
        if (factories != null) {
            final Set<Object> dependencies = new LinkedHashSet<Object>(8);
            dependencies.add(factories.getCRSFactory());
            dependencies.add(factories.getCSFactory());
            dependencies.add(factories.getDatumFactory());
            return dependencies;
        }
        return super.dependencies();
    }
}
