/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *
 *   (C) 2005-2006, Geotools Project Managment Committee (PMC)
 *   (C) 2003, Gerald I. Evenden
 *   (C) 2000, Frank Warmerdam
 *
 *    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; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    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 formulas from the PROJ package of USGS.
 *    USGS's work is fully acknowledged here. This derived work has
 *    been relicensed under LGPL with Frank Warmerdam's permission.
 */
package org.geotools.referencing.operation.projection;

// J2SE dependencies
import java.util.Collection;

// OpenGIS dependencies
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.referencing.operation.MathTransform;

// Geotools dependencies
import org.geotools.referencing.NamedIdentifier;
import org.geotools.metadata.iso.citation.Citations;


/**
 * Hotine Oblique Mercator projection. It is similar to the {@link ObliqueMercator oblique mercator}
 * projection, except that coordinates start at the intersection of the central line and the equator
 * of the aposphere.
 *
 * @since 2.4
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/projection/HotineObliqueMercator.java $
 * @version $Id: HotineObliqueMercator.java 24563 2007-02-23 00:20:43Z desruisseaux $
 * @author Rueben Schulz
 */
public class HotineObliqueMercator extends ObliqueMercator {
    /**
     * Constructs a new map projection from the supplied parameters.
     *
     * @param  parameters The parameter values in standard units.
     * @throws ParameterNotFoundException if a mandatory parameter is missing.
     *
     * @todo Current implementation assumes a "azimuth" case. We may try to detect
     *       automatically the "two points" case in a future version if needed. Note
     *       that this limitation doesn't apply to projection created from the
     *       {@link Provider_TwoPoint}. 
     */
    protected HotineObliqueMercator(final ParameterValueGroup parameters)
            throws ParameterNotFoundException 
    {
        this(parameters, Provider.PARAMETERS.descriptors(), false);
    }

    /**
     * Constructs a new map projection from the supplied parameters.
     * 
     * @param parameters The parameter values in standard units.
     * @param expected The expected parameter descriptors.
     * @param twoPoint {@code true} for the "two points" case, or {@code false} for the
     *         "azimuth" case. The former is used by ESRI but not EPSG.
     * @throws ParameterNotFoundException if a mandatory parameter is missing.
     */
    HotineObliqueMercator(final ParameterValueGroup parameters, final Collection expected,
                          final boolean twoPoint)
            throws ParameterNotFoundException 
    {
        // Fetch parameters 
        super(parameters, expected, twoPoint, true);
    }

    /**
     * {@inheritDoc}
     */
    public ParameterDescriptorGroup getParameterDescriptors() {
        return (twoPoint) ? Provider_TwoPoint.PARAMETERS : Provider.PARAMETERS;
    }




    //////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////
    ////////                                                                          ////////
    ////////                                 PROVIDERS                                ////////
    ////////                                                                          ////////
    //////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////

    /**
     * The {@linkplain org.geotools.referencing.operation.MathTransformProvider math transform
     * provider} for a {@linkplain HotineObliqueMercator Hotine Oblique Mercator} projection
     * (EPSG code 9812).
     *
     * @since 2.4
     * @version $Id: HotineObliqueMercator.java 24563 2007-02-23 00:20:43Z desruisseaux $
     * @author Rueben Schulz
     *
     * @see org.geotools.referencing.operation.DefaultMathTransformFactory
     */
    public static final class Provider extends ObliqueMercator.Provider {
        /**
         * The parameters group.
         */
        static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] {
                new NamedIdentifier(Citations.OGC,      "Hotine_Oblique_Mercator"),
                new NamedIdentifier(Citations.EPSG,     "Hotine Oblique Mercator"),
                new NamedIdentifier(Citations.EPSG,     "9812"),
                new NamedIdentifier(Citations.GEOTIFF,  "CT_ObliqueMercator_Hotine"),
                new NamedIdentifier(Citations.ESRI,     "Hotine_Oblique_Mercator_Azimuth_Natural_Origin"),
                new NamedIdentifier(Citations.ESRI,     "Rectified_Skew_Orthomorphic_Natural_Origin"),
                new NamedIdentifier(Citations.GEOTOOLS, NAME)
            }, new ParameterDescriptor[] {
                SEMI_MAJOR,          SEMI_MINOR,
                LONGITUDE_OF_CENTRE, LATITUDE_OF_CENTRE,
                AZIMUTH,             RECTIFIED_GRID_ANGLE,
                SCALE_FACTOR,
                FALSE_EASTING,       FALSE_NORTHING
            });

        /**
         * Constructs a new provider. 
         */
        public Provider() {
            super(PARAMETERS);
        }

        /**
         * Creates a transform from the specified group of parameter values.
         *
         * @param  parameters The group of parameter values.
         * @return The created math transform.
         * @throws ParameterNotFoundException if a required parameter was not found.
         */
        protected MathTransform createMathTransform(final ParameterValueGroup parameters)
                throws ParameterNotFoundException
        {
            final Collection descriptors = PARAMETERS.descriptors();
            return new HotineObliqueMercator(parameters, descriptors, false);
        }
    }


    /**
     * The {@linkplain org.geotools.referencing.operation.MathTransformProvider math transform
     * provider} for a {@linkplain HotineObliqueMercator Hotine Oblique Mercator} projection,
     * specified with two points on the central line (instead of a central point and azimuth).
     *
     * @since 2.4
     * @version $Id: HotineObliqueMercator.java 24563 2007-02-23 00:20:43Z desruisseaux $
     * @author Rueben Schulz
     *
     * @see org.geotools.referencing.operation.DefaultMathTransformFactory
     */
    public static final class Provider_TwoPoint extends ObliqueMercator.Provider_TwoPoint {
        /**
         * The parameters group.
         */
        static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] {
                new NamedIdentifier(Citations.ESRI,     "Hotine_Oblique_Mercator_Two_Point_Natural_Origin"),
                new NamedIdentifier(Citations.GEOTOOLS, NAME)
            }, new ParameterDescriptor[] {
                SEMI_MAJOR,          SEMI_MINOR,
                LAT_OF_1ST_POINT,    LONG_OF_1ST_POINT,
                LAT_OF_2ND_POINT,    LONG_OF_2ND_POINT,
                LATITUDE_OF_CENTRE,  SCALE_FACTOR,
                FALSE_EASTING,       FALSE_NORTHING
            });

        /**
         * Constructs a new provider. 
         */
        public Provider_TwoPoint() {
            super(PARAMETERS);
        }

        /**
         * Creates a transform from the specified group of parameter values.
         *
         * @param  parameters The group of parameter values.
         * @return The created math transform.
         * @throws ParameterNotFoundException if a required parameter was not found.
         */
        protected MathTransform createMathTransform(final ParameterValueGroup parameters)
                throws ParameterNotFoundException
        {
            final Collection descriptors = PARAMETERS.descriptors();
            return new HotineObliqueMercator(parameters, descriptors, true);
        }
    }
}
