package com.atlassian.bitbucket.mesh.git.content;

import com.atlassian.bitbucket.mesh.git.GitNodeType;
import com.atlassian.bitbucket.mesh.git.GitObjectInfo;
import com.atlassian.bitbucket.mesh.git.exception.CommitNotFoundException;
import com.atlassian.bitbucket.mesh.git.exception.PathNotFoundException;

import javax.annotation.Nonnull;

public interface ContentManager {

    /**
     * Retrieves the {@link GitNodeType node type} for the specified path at the requested commit, which can be
     * used to determine whether the path identifies a directory, file or submodule.
     *
     * @param parameters parameters describing the node type to retrieve
     * @return the requested node type
     * @throws CommitNotFoundException if the requested commit does not exist
     * @throws PathNotFoundException if the specified path does not exist at the requested commit
     */
    @Nonnull
    GitNodeType getNodeType(@Nonnull GetNodeTypeParameters parameters);

    /**
     * Retrieves {@link GitObjectInfo info} for the object at the specified path at the requested commit, which
     * provides the object ID, size and type. This is similar to {@link #getNodeType}, but is more flexible for
     * what objects can be handled.
     *
     * @param parameters parameters describing the object to retrieve info for
     * @return the requested object info
     * @throws CommitNotFoundException if the requested commit does not exist
     * @throws PathNotFoundException if the specified path does not exist at the requested commit
     */
    @Nonnull
    GitObjectInfo getObjectInfo(@Nonnull GetObjectInfoParameters parameters);

    /**
     * Lists the files, subdirectories and submodules containing by the specified path at the requested commit.
     * The specified path must identify a <i>directory</i>.
     * <p>
     * If the requested listing is {@link ListDirectoryParameters#isRecursive recursive}, only files and submodules
     * will be streamed. For non-recursive listings, subdirectories will also be included. Any subdirectories that
     * contain a single subdirectory (not a file or submodule) will be collapsed. Consider the following layout:
     * <pre>
     * src/
     *   main/
     *     java/
     *       com/
     *         atlassian/
     *           bitbucket/
     *             comment/
     *               CommentService.java
     *             repository/
     *               RepositoryService.java
     *   test/
     *     java/
     *       com/
     *         atlassian/
     *           bitbucket/
     *             SomeTest.java
     * </pre>
     * When listing {@code src}, both {@code main} and {@code test} each contain only a single directory, and that
     * repeats for many layers. In this case, the callback would receive 2 entries:
     * <ul>
     *     <li>{@code main/java/com/atlassian/bitbucket}
     *     <ul>
     *         <li>{@code bitbucket} has 2 subdirectories, so it is not collapsed</li>
     *     </ul>
     *     </li>
     *     <li>{@code test/java/com/atlassian/bitbucket}
     *     <ul>
     *         <li>{@code bitbucket} contains a file, so it is not collapsed</li>
     *     </ul>
     *     </li>
     * </ul>
     *
     * @param parameters parameters describing the directory to list
     * @param callback a callback to receive the directory
     * @throws CommitNotFoundException if the requested commit does not exist
     * @throws PathNotFoundException if the specified path does not exist at the requested commit
     */
    void listDirectory(@Nonnull ListDirectoryParameters parameters, @Nonnull DirectoryCallback callback);
}
