/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2003-2005, Open Geospatial Consortium Inc.
 *    
 *    All Rights Reserved. http://www.opengis.org/legal/
 */
package org.opengis.util;

import java.util.List;
import org.opengis.annotation.UML;
import org.opengis.annotation.Extension;

import static org.opengis.annotation.Obligation.*;
import static org.opengis.annotation.Specification.*;


/**
 * A sequence of identifiers rooted within the context of a {@linkplain NameSpace namespace}.
 * This interface is similar in purpose to {@link javax.naming.Name} from the <cite>Java Naming
 * and Directory Interface</cite>. All generic names:
 * <p>
 * <ul>
 *   <li>carry an association with their {@linkplain #scope scope} in which they are
 *       considered local;</li>
 *   <li>have the ability to provide a {@linkplain #getParsedNames parsed} version of
 *       themselves.</li>
 * </ul>
 * <p>
 * Names are <em>immutables</em>. They may be {@linkplain #toFullyQualifiedName fully qualified}
 * like {@code "org.opengis.util.Record"}, or they may be relative to a {@linkplain #scope scope}
 * like {@code "util.Record"} in the {@code "org.opengis"} scope. The illustration below shows all
 * possible constructions for {@code "org.opengis.util.Record"}.
 *
 * <blockquote><table border="1" cellpadding="15"><tr><td><table border="0" cellspacing="0">
 *   <tr>
 *     <th align="right">org</th>
 *     <th>.</th><th>opengis</th>
 *     <th>.</th><th>util</th>
 *     <th>.</th><th>Record</th>
 *     <th width="50"></th>
 *     <th>{@link #scope}</th>
 *     <th>{@link #getParsedNames}</th>
 *   </tr>
 *
 *   <tr align="center">
 *     <td bgcolor="palegoldenrod" colspan="1"><font size="-1">{@linkplain #head head}</font></td><td></td>
 *     <td bgcolor="palegoldenrod" colspan="5"><font size="-1">{@linkplain ScopedName#tail tail}</font></td>
 *     <td rowspan="3"></td>
 *     <td rowspan="3" bgcolor="beige" align="left">{@linkplain NameSpace#isGlobal global}</td>
 *     <td rowspan="3" bgcolor="beige" align="right">{@literal {"org", "opengis", "util", "Record"}}</td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="wheat" colspan="5"><font size="-1">{@linkplain ScopedName#path path}</font></td><td></td>
 *     <td bgcolor="wheat" colspan="1"><font size="-1">{@linkplain #tip tip}</font></td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="burlywood" colspan="7">{@linkplain ScopedName}</td>
 *   </tr>
 *
 *   <tr><td colspan="7" height="3"></td></tr>
 *   <tr align="center">
 *     <td bgcolor="palegoldenrod" colspan="1" rowspan="3"><font size="-1">{@linkplain #scope scope}</font></td><td rowspan="3"></td>
 *     <td bgcolor="palegoldenrod" colspan="1"><font size="-1">head</font></td><td></td>
 *     <td bgcolor="palegoldenrod" colspan="3"><font size="-1">tail</font></td>
 *     <td rowspan="3"></td>
 *     <td rowspan="3" bgcolor="beige" align="left">{@literal "org"}</td>
 *     <td rowspan="3" bgcolor="beige" align="right">{@literal {"opengis", "util", "Record"}}</td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="wheat" colspan="3"><font size="-1">path</font></td><td></td>
 *     <td bgcolor="wheat" colspan="1"><font size="-1">tip</font></td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="burlywood" colspan="5">ScopedName</td>
 *   </tr>
 *
 *   <tr><td colspan="7" height="3"></td></tr>
 *   <tr align="center">
 *     <td bgcolor="palegoldenrod" colspan="3" rowspan="3"><font size="-1">scope</font></td><td rowspan="3"></td>
 *     <td bgcolor="palegoldenrod" colspan="1"><font size="-1">head</font></td><td></td>
 *     <td bgcolor="palegoldenrod" colspan="1"><font size="-1">tail</font></td>
 *     <td rowspan="3"></td>
 *     <td rowspan="3" bgcolor="beige" align="left">{@literal "org.opengis"}</td>
 *     <td rowspan="3" bgcolor="beige" align="right">{@literal {"util", "Record"}}</td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="wheat" colspan="1"><font size="-1">path</font></td><td></td>
 *     <td bgcolor="wheat" colspan="1"><font size="-1">tip</font></td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="burlywood" colspan="3">ScopedName</td>
 *   </tr>
 *
 *   <tr><td colspan="7" height="3"></td></tr>
 *   <tr align="center">
 *     <td bgcolor="palegoldenrod" colspan="5" rowspan="3"><font size="-1">scope</font></td><td rowspan="3"></td>
 *     <td bgcolor="palegoldenrod" colspan="1"><font size="-1">head</font></td>
 *     <td rowspan="3"></td>
 *     <td rowspan="3" bgcolor="beige" align="left">{@literal "org.opengis.util"}</td>
 *     <td rowspan="3" bgcolor="beige" align="right">{@literal {"Record"}}</td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="wheat" colspan="1"><font size="-1">tip</font></td>
 *   </tr>
 *   <tr align="center">
 *     <td bgcolor="burlywood" colspan="1">{@linkplain LocalName}</td>
 *   </tr>
 * </table></td></tr></table></blockquote>
 * <p>
 * The {@linkplain Comparable natural ordering} for generic names is implementation dependent.
 * A recommended practice is to {@linkplain String#compareTo compare lexicographically} each
 * element in the {@linkplain #getParsedNames list of parsed names}. Specific attributes of
 * the name, such as how it treats case, may affect the ordering. In general, two names of
 * different classes may not be compared.
 *
 * @author Martin Desruisseaux (IRD)
 * @author Bryce Nordgren (USDA)
 * @since GeoAPI 1.0
 *
 * @see javax.naming.Name
 *
 * @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/modules/library/opengis/src/main/java/org/opengis/util/GenericName.java $
 */
@UML(identifier="GenericName", specification=ISO_19103)
public interface GenericName extends Comparable<GenericName> {
    /**
     * Returns the scope (name space) in which this name is local. The scope is set on creation
     * and is not modifiable. The scope of a name determines where a name starts.
     * <p>
     * <b>Example</b>:
     * For a {@linkplain #toFullyQualifiedName fully qualified name} (a name having a
     * {@linkplain NameSpace#isGlobal global namespace}) {@code "org.opengis.util.Record"},
     * if this instance is the name {@code "util.Record"}, then the scope of this instance
     * has the {@linkplain NameSpace#name name} {@code "org.opengis"}.
     *
     * @return The scope of this name.
     *
     * @since GeoAPI 2.1
     */
    @UML(identifier="scope", obligation=MANDATORY, specification=ISO_19103)
    NameSpace scope();

    /**
     * Indicates the number of levels specified by this name. The depth is the {@linkplain List#size size}
     * of the list returned by the {@link #getParsedNames} method. As such it is a derived parameter. For
     * any {@link LocalName}, it is always one. For a {@link ScopedName} it is some number greater than or
     * equal to 2.
     * <p>
     * This method is similar in purpose to {@link javax.naming.Name#size()}
     * from the <cite>Java Naming and Directory Interface</cite>.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "org.opengis.util.Record"}, then this method shall returns
     * {@code 4}. If this name is {@code "util.Record"} in scope {@code "org.opengis"}, then this
     * method shall returns {@code 2}.
     *
     * @return The depth of this name.
     *
     * @since GeoAPI 2.1
     */
    @UML(identifier="depth", obligation=MANDATORY, specification=ISO_19103)
    int depth();

    /**
     * Returns the sequence of {@linkplain LocalName local names} making this generic name.
     * The length of this sequence is the {@linkplain #depth depth}. It does not include the
     * {@linkplain #scope scope}.
     * <p>
     * This method is similar in purpose to {@link javax.naming.Name#getAll()}
     * from the <cite>Java Naming and Directory Interface</cite>.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "org.opengis.util.Record"}, then this method shall returns a
     * list containing {@code {"org", "opengis", "util", "Record"}} elements in that iteration order.
     * If this name is {@code "util.Record"} in scope {@code "org.opengis"}, then this method shall
     * returns a list containing only {@code {"util", "Record"}} elements.
     *
     * @return The local names making this generic name, without the {@linkplain #scope scope}.
     *         Shall never be {@code null} neither {@linkplain List#isEmpty empty}.
     */
    @UML(identifier="parsedName", obligation=MANDATORY, specification=ISO_19103)
    List<? extends LocalName> getParsedNames();

    /**
     * Returns the first element in the sequence of {@linkplain #getParsedNames parsed names}.
     * For any {@link LocalName}, this is always {@code this}.
     * <p>
     * This method is similar in purpose to <code>{@linkplain javax.naming.Name#get(int)
     * Name.get}(0)</code> from the <cite>Java Naming and Directory Interface</cite>.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "org.opengis.util.Record"} (no matter its
     * {@linkplain #scope scope}), then this method shall returns {@code "org"}.
     *
     * @return The first element in the list of {@linkplain #getParsedNames parsed names}.
     *
     * @since GeoAPI 2.2
     */
    @UML(identifier="ScopedName.head", obligation=MANDATORY, specification=ISO_19103)
    LocalName head();

    /**
     * Returns the last element in the sequence of {@linkplain #getParsedNames parsed names}.
     * For any {@link LocalName}, this is always {@code this}.
     * <p>
     * This method is similar in purpose to <code>{@linkplain javax.naming.Name#get(int)
     * Name.get}(size-1)</code> from the <cite>Java Naming and Directory Interface</cite>.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "org.opengis.util.Record"} (no matter its
     * {@linkplain #scope scope}), then this method shall returns {@code "Record"}.
     *
     * @return The last element in the list of {@linkplain #getParsedNames parsed names}.
     *
     * @since GeoAPI 2.1
     */
    @Extension
    LocalName tip();

    /**
     * Returns a view of this name as a fully-qualified name. The {@linkplain #scope scope}
     * of a fully qualified name must be {@linkplain NameSpace#isGlobal global}. If the scope
     * of this name is already global, then this method shall returns {@code this}.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "util.Record"} ({@linkplain #depth depth} of two) and its
     * {@linkplain #scope scope} has the {@linkplain NameSpace#name name} {@code "org.opengis"},
     * then the fully qualified name shall be {@code "org.opengis.util.Record"}.
     *
     * @return The fully-qualified name (never {@code null}).
     *
     * @since GeoAPI 2.1
     */
    @Extension
    GenericName toFullyQualifiedName();

    /**
     * Returns this name expanded with the specified scope. One may represent this operation
     * as a concatenation of the specified {@code scope} with {@code this}. In pseudo-code,
     * the following relationships must hold (the last one is specific to {@link ScopedName}):
     * <p>
     * <ul>
     *   <li><code>push(</code><var>foo</var><code> : LocalName).{@linkplain #head}</code>
     *       {@linkplain #equals equals} <var>foo</var></li>
     *
     *   <li><code>push(</code><var>foo</var><code> : LocalName).{@linkplain ScopedName#tail tail()}</code>
     *       {@linkplain #equals equals} <var>this</var></li>
     *
     *   <li><code>push(</code><var>foo</var><code> : GenericName).{@linkplain #scope}</code>
     *       {@linkplain #equals equals} <var>foo</var>.{@link #scope()}</li>
     *
     *   <li><code>push(</code><var>foo</var><code> : GenericName).{@linkplain #getParsedNames}</code>
     *       {@linkplain List#equals equals} <var>foo</var>.<code>getParsedNames().{@linkplain
     *       List#addAll addAll}(</code><var>this</var>.<code>getParsedNames())</code></li>
     * </ul>
     * <p>
     * This method is similar in purpose to <code>{@linkplain javax.naming.Name#addAll(int,javax.naming.Name)
     * Name.addAll}(0,name)</code> from the <cite>Java Naming and Directory Interface</cite>.
     * <p>
     * <b>Example</b>:
     * If {@code this} name is {@code "util.Record"} and the given {@code scope} argument is
     * {@code "org.opengis"}, then {@code this.push(scope)} shall returns
     * {@code "org.opengis.util.Record"}.
     *
     * @param scope The name to use as prefix.
     * @return A concatenation of the given name with this name.
     *
     * @since GeoAPI 2.1
     */
    @UML(identifier="push", obligation=MANDATORY, specification=ISO_19103)
    ScopedName push(GenericName scope);

    /**
     * Returns a string representation of this generic name. This string representation is
     * local-independant. It contains all elements listed by {@link #getParsedNames} separated
     * by a namespace-dependant character (usually {@code :} or {@code /}). This rule implies
     * that the result may or may not be fully qualified. Special cases:
     * <p>
     * <ul>
     *   <li><code>{@linkplain #toFullyQualifiedName}.toString()</code> is garanteed to
     *       contains the {@linkplain #scope scope} (if any).</li>
     *   <li><code>{@linkplain #name}.toString()</code> is garanteed to <strong>not</strong>
     *       contains any scope.</li>
     * </ul>
     *
     * @return A local-independant string representation of this name.
     */
/// @Override
    @Extension
    String toString();

    /**
     * Returns a local-dependent string representation of this generic name. This string
     * is similar to the one returned by {@link #toString} except that each element has
     * been localized in the {@linkplain InternationalString#toString(java.util.Locale)
     * specified locale}. If no international string is available, then this method shall
     * returns an implementation mapping to {@link #toString} for all locales.
     * <p>
     * <b>Example</b>:
     * An implementation may want to localize the {@code "My Documents"} directory name
     * into {@code "Mes Documents"} on French installation of Windows operating system.
     *
     * @return A localizable string representation of this name.
     */
    @Extension
    InternationalString toInternationalString();
}
