/*
 * 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.commons.vfs2;

/**
 * Represents a file name. File names are immutable, and work correctly as keys in hash tables.
 *
 * @see FileObject
 */
public interface FileName extends Comparable<FileName> {

    /**
     * The separator character used in file paths.
     */
    char SEPARATOR_CHAR = '/';

    /**
     * The separator used in file paths.
     */
    String SEPARATOR = "/";

    /**
     * The absolute path of the root of a file system.
     */
    String ROOT_PATH = "/";

    /**
     * Empty array of FileName.
     *
     * @since 2.8.0
     */
    FileName[] EMPTY_ARRAY = new FileName[0];

    /**
     * Gets the base name of this file. The base name is the last element of the file name. For example the base name
     * of {@code /somefolder/somefile} is {@code somefile}.
     * <p>
     * The root file of a file system has an empty base name.
     * </p>
     *
     * @return The base name. Never returns null.
     */
    String getBaseName();

    /**
     * Gets the depth of this file name, within its file system. The depth of the root of a file system is 0. The
     * depth of any other file is 1 + the depth of its parent.
     *
     * @return The depth of this file name.
     */
    int getDepth();

    /**
     * Gets the extension of this file name.
     *
     * @return The extension. Returns an empty string if the name has no extension.
     */
    String getExtension();

    /**
     * Gets a "friendly path", this is a path without a password.
     * <p>
     * This path can not be used to resolve the path again.
     * </p>
     *
     * @return the friendly URI as a String.
     */
    String getFriendlyURI();

    /**
     * Gets the file name of the parent of this file. The root of a file system has no parent.
     *
     * @return A {@link FileName} object representing the parent name. Returns null for the root of a file system.
     */
    FileName getParent();

    /**
     * Gets the absolute path string of this file, within its file system. This path is normalized, so that {@code .}
     * and {@code ..} elements have been removed. Also, the path only contains {@code /} as its separator character. The
     * path always starts with {@code /}
     * <p>
     * The root of a file system has {@code /} as its absolute path.
     * </p>
     *
     * @return The path. Never returns null.
     */
    String getPath();

    /**
     * Returns the absolute path of this file, within its file system. This path is normalized, so that {@code .} and
     * {@code ..} elements have been removed. Also, the path only contains {@code /} as its separator character. The
     * path always starts with {@code /}
     * <p>
     * The root of a file system has {@code /} as its absolute path.
     * </p>
     * <p>
     * In contrast to {@link #getPath()}, this path is decoded: All %nn escapes are replaced by their respective
     * characters.
     * </p>
     *
     * @return The decoded path. Never returns null.
     * @throws FileSystemException if the path is not correctly encoded
     */
    String getPathDecoded() throws FileSystemException;

    /**
     * Converts a file name to a relative name, relative to this file name.
     *
     * @param name The name to convert to a relative path.
     * @return The relative name.
     * @throws FileSystemException On error.
     */
    String getRelativeName(FileName name) throws FileSystemException;

    /**
     * Gets the root of the file system.
     *
     * @return the file system root.
     */
    FileName getRoot();

    /**
     * Gets the root URI string of the file system this file belongs to.
     *
     * @return the root URI string.
     */
    String getRootURI();

    /**
     * Gets the URI scheme of this file.
     *
     * @return The URI scheme of this file.
     */
    String getScheme();

    /**
     * Gets the requested or current type of this name.
     * <p>
     * The "requested" type is the one determined during resolving the name. In this case the name is a
     * {@link FileType#FOLDER} if it ends with an "/" else it will be a {@link FileType#FILE}.
     * </p>
     * <p>
     * Once attached it will be changed to reflect the real type of this resource.
     * </p>
     *
     * @return {@link FileType#FOLDER} or {@link FileType#FILE}
     */
    FileType getType();

    /**
     * Gets the absolute URI string of this file.
     *
     * @return the absolute URI string of this file.
     */
    String getURI();

    /**
     * Tests if another file name is an ancestor of this file name.
     *
     * @param ancestor The FileName to check.
     * @return true if another file name is an ancestor of this file name.
     */
    boolean isAncestor(FileName ancestor);

    /**
     * Tests if another file name is a descendent of this file name.
     *
     * @param descendent the FileName to check.
     * @return true if the other FileName is a descendent of this file name.
     */
    boolean isDescendent(FileName descendent);

    /**
     * Tests if another file name is a descendent of this file name.
     *
     * @param descendent the FileName to check.
     * @param nameScope the NameScope of the FileName.
     * @return true if the other FileName is a descendent of this file name.
     */
    boolean isDescendent(FileName descendent, NameScope nameScope);

    /**
     * Tests if this file name is a name for a regular file.
     *
     * @return true if this file name is a name for a regular file.
     * @throws FileSystemException if an error occurs.
     * @see #getType()
     * @see FileType#FILE
     * @since 2.1
     */
    boolean isFile() throws FileSystemException;
}
