/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.sis.referencing.operation.provider;

import jakarta.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.referencing.operation.projection.NormalizedProjection;
import org.apache.sis.util.internal.shared.Constants;
import org.apache.sis.measure.Units;


/**
 * The provider for <q>Satellite-Tracking</q> projections.
 * We are not aware of authoritative source for parameter definitions, except the Snyder book.
 * See {@link org.apache.sis.referencing.operation.projection.SatelliteTracking here for more
 * details}.
 *
 * @author  Matthieu Bastianelli (Geomatys)
 * @author  Martin Desruisseaux (Geomatys)
 */
@XmlTransient
public class SatelliteTracking extends MapProjection {
    /**
     * For cross-version compatibility.
     */
    private static final long serialVersionUID = -2406880538621713953L;

    /**
     * The operation parameter descriptor for the <cite>central meridian</cite> (λ₀) parameter value.
     * Valid values range is [-180 … 180]° and default value is 0°.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> ESRI:    </td><td> Central_Meridian </td></tr>
     *   <tr><td> OGC:     </td><td> central_meridian </td></tr>
     *   <tr><td> GeoTIFF: </td><td> CenterLong </td></tr>
     *   <tr><td> Proj4:   </td><td> lon_0 </td></tr>
     * </table>
     */
    public static final ParameterDescriptor<Double> CENTRAL_MERIDIAN = ESRI.CENTRAL_MERIDIAN;

    /**
     * Latitude crossing the central meridian at the desired origin of rectangular coordinates.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> ESRI:    </td><td> Latitude_Of_Origin </td></tr>
     *   <tr><td> OGC:     </td><td> latitude_of_origin </td></tr>
     *   <tr><td> GeoTIFF: </td><td> CenterLat </td></tr>
     *   <tr><td> Proj4:   </td><td> lat_0 </td></tr>
     * </table>
     */
    public static final ParameterDescriptor<Double> LATITUDE_OF_ORIGIN = ESRI.LATITUDE_OF_ORIGIN;;

    /**
     * The operation parameter descriptor for the <cite>Latitude of 1st standard parallel</cite>.
     * For conical satellite-tracking projection, this is the first parallel of conformality with true scale.
     * Valid values range is [-90 … 90]° and default value is 0°.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> ESRI:    </td><td> Standard_Parallel_1 </td></tr>
     *   <tr><td> OGC:     </td><td> standard_parallel_1 </td></tr>
     *   <tr><td> GeoTIFF: </td><td> StdParallel1 </td></tr>
     *   <tr><td> Proj4:   </td><td> lat_1 </td></tr>
     * </table>
     */
    public static final ParameterDescriptor<Double> STANDARD_PARALLEL_1 = ESRI.STANDARD_PARALLEL_1;

    /**
     * The operation parameter descriptor for the <cite>second parallel of conformality but without true scale</cite>
     * parameter value for conic projection. Valid values range is [-90 … 90]° and default value is the opposite value
     * given to the {@link #STANDARD_PARALLEL_1} parameter.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> ESRI:    </td><td> Standard_Parallel_2 </td></tr>
     *   <tr><td> OGC:     </td><td> standard_parallel_2 </td></tr>
     *   <tr><td> GeoTIFF: </td><td> StdParallel2 </td></tr>
     *   <tr><td> Proj4:   </td><td> lat_2 </td></tr>
     * </table>
     */
    public static final ParameterDescriptor<Double> STANDARD_PARALLEL_2 = ESRI.STANDARD_PARALLEL_2;

    /**
     * The operation parameter descriptor for the angle of inclination between the plane of the Earth's
     * Equator and the plane of the satellite orbit. It is measured counterclockwise from the Equator to
     * the orbit plane at the ascending node. Examples: 99.092° for Landsat 1, 2 and 3.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> SIS:     </td><td> satellite_orbit_inclination </td></tr>
     * </table>
     */
    public static final ParameterDescriptor<Double> SATELLITE_ORBIT_INCLINATION;

    /**
     * The operation parameter descriptor for the time required for revolution of the satellite.
     * Examples: 103.267 minutes for Landsat 1, 2 and 3; 98.884 minutes for Landsat 4 and 5.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> SIS:     </td><td> satellite_orbital_period </td></tr>
     * </table>
     * <b>Notes:</b>
     * <ul>
     *   <li>Value domain: (0.0 … ∞) d</li>
     *   <li>No default value</li>
     * </ul>
     */
    public static final ParameterDescriptor<Double> SATELLITE_ORBITAL_PERIOD;

    /**
     * The operation parameter descriptor for the length of Earth's rotation with respect to the
     * precessed ascending node. The ascending node is the point on the satellite orbit at which
     * the satellite crosses the Earth's equatorial plane in a northerly direction.
     * For Landsat (Sun-synchronous satellite orbit), this is 1440 minutes.
     *
     * <!-- Generated by ParameterNameTableGenerator -->
     * <table class="sis">
     *   <caption>Parameter names</caption>
     *   <tr><td> SIS:     </td><td> ascending_node_period </td></tr>
     * </table>
     * <b>Notes:</b>
     * <ul>
     *   <li>Value domain: (0.0 … ∞) d</li>
     *   <li>No default value</li>
     * </ul>
     */
    public static final ParameterDescriptor<Double> ASCENDING_NODE_PERIOD;

    /**
     * The group of all parameters expected by this coordinate operation.
     */
    private static final ParameterDescriptorGroup PARAMETERS;
    static {
        final ParameterBuilder builder = builder().setCodeSpace(Citations.SIS, Constants.SIS);
        SATELLITE_ORBIT_INCLINATION = setNameAndDescription(builder, "satellite_orbit_inclination").create(0, Units.DEGREE);
        SATELLITE_ORBITAL_PERIOD    = setNameAndDescription(builder, "satellite_orbital_period").createStrictlyPositive(Double.NaN, Units.DAY);
        ASCENDING_NODE_PERIOD       = setNameAndDescription(builder, "ascending_node_period")   .createStrictlyPositive(Double.NaN, Units.DAY);
        PARAMETERS = builder.addName("Satellite-Tracking").createGroupForMapProjection(
                LATITUDE_OF_ORIGIN,
                CENTRAL_MERIDIAN,
                STANDARD_PARALLEL_1,
                STANDARD_PARALLEL_2,
                SATELLITE_ORBIT_INCLINATION,
                SATELLITE_ORBITAL_PERIOD,
                ASCENDING_NODE_PERIOD);
    }

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

    /**
     * Sets the parameter name in the given builder, together with a description created from
     * the resource bundle in this package. The resource key is the same as the parameter name.
     *
     * @param  builder  the builder where to set the parameter name and description.
     * @param  name     the parameter name, also used as resource key.
     * @return the builder, for method calls chaining.
     */
    private static ParameterBuilder setNameAndDescription(final ParameterBuilder builder, final String name) {
        return builder.addName(name).setDescription(new Description(name));
    }

    /**
     * {@inheritDoc}
     *
     * @return the map projection created from the given parameter values.
     */
    @Override
    protected NormalizedProjection createProjection(final Parameters parameters) {
        return new org.apache.sis.referencing.operation.projection.SatelliteTracking(this, parameters);
    }
}
