using System;
using System.Collections.Generic;
using System.IO;

namespace Umbraco.Core.IO
{
    /// <summary>
    /// Provides methods allowing the manipulation of files within an Umbraco application.
    /// </summary>
    public interface IFileSystem
    {
        /// <summary>
        /// Gets all directories matching the given path.
        /// </summary>
        /// <param name="path">The path to the directories.</param>
        /// <returns>
        /// The <see cref="IEnumerable{String}"/> representing the matched directories.
        /// </returns>
        IEnumerable<string> GetDirectories(string path);

        /// <summary>
        /// Deletes the specified directory.
        /// </summary>
        /// <param name="path">The name of the directory to remove.</param>
        void DeleteDirectory(string path);

        /// <summary>
        /// Deletes the specified directory and, if indicated, any subdirectories and files in the directory.
        /// </summary>
        /// <remarks>Azure blob storage has no real concept of directories so deletion is always recursive.</remarks>
        /// <param name="path">The name of the directory to remove.</param>
        /// <param name="recursive">Whether to remove directories, subdirectories, and files in path.</param>
        void DeleteDirectory(string path, bool recursive);

        /// <summary>
        /// Determines whether the specified directory exists.
        /// </summary>
        /// <param name="path">The directory to check.</param>
        /// <returns>
        /// <c>True</c> if the directory exists and the user has permission to view it; otherwise <c>false</c>.
        /// </returns>
        bool DirectoryExists(string path);

        /// <summary>
        /// Adds a file to the file system.
        /// </summary>
        /// <param name="path">The path to the given file.</param>
        /// <param name="stream">The <see cref="Stream"/> containing the file contents.</param>
        void AddFile(string path, Stream stream);

        /// <summary>
        /// Adds a file to the file system.
        /// </summary>
        /// <param name="path">The path to the given file.</param>
        /// <param name="stream">The <see cref="Stream"/> containing the file contents.</param>
        /// <param name="overrideIfExists">Whether to override the file if it already exists.</param>
        void AddFile(string path, Stream stream, bool overrideIfExists);

        /// <summary>
        /// Gets all files matching the given path.
        /// </summary>
        /// <param name="path">The path to the files.</param>
        /// <returns>
        /// The <see cref="IEnumerable{String}"/> representing the matched files.
        /// </returns>
        IEnumerable<string> GetFiles(string path);

        /// <summary>
        /// Gets all files matching the given path and filter.
        /// </summary>
        /// <param name="path">The path to the files.</param>
        /// <param name="filter">A filter that allows the querying of file extension. <example>*.jpg</example></param>
        /// <returns>
        /// The <see cref="IEnumerable{String}"/> representing the matched files.
        /// </returns>
        IEnumerable<string> GetFiles(string path, string filter);

        /// <summary>
        /// Gets a <see cref="Stream"/> representing the file at the gieven path.
        /// </summary>
        /// <param name="path">The path to the file.</param>
        /// <returns>
        /// <see cref="Stream"/>.
        /// </returns>
        Stream OpenFile(string path);

        /// <summary>
        /// Deletes the specified file.
        /// </summary>
        /// <param name="path">The name of the file to remove.</param>
        void DeleteFile(string path);

        /// <summary>
        /// Determines whether the specified file exists.
        /// </summary>
        /// <param name="path">The file to check.</param>
        /// <returns>
        /// <c>True</c> if the file exists and the user has permission to view it; otherwise <c>false</c>.
        /// </returns>
        bool FileExists(string path);

        /// <summary>
        /// Returns the application relative path to the file.
        /// </summary>
        /// <param name="fullPathOrUrl">The full path or url.</param>
        /// <returns>
        /// The <see cref="string"/> representing the relative path.
        /// </returns>
        string GetRelativePath(string fullPathOrUrl);

        /// <summary>
        /// Gets the full qualified path to the file.
        /// </summary>
        /// <param name="path">The file to return the full path for.</param>
        /// <returns>
        /// The <see cref="string"/> representing the full path.
        /// </returns>
        string GetFullPath(string path);

        /// <summary>
        /// Returns the application relative url to the file.
        /// </summary>
        /// <param name="path">The path to return the url for.</param>
        /// <returns>
        /// <see cref="string"/> representing the relative url.
        /// </returns>
        string GetUrl(string path);

        /// <summary>
        /// Gets the last modified date/time of the file, expressed as a UTC value.
        /// </summary>
        /// <param name="path">The path to the file.</param>
        /// <returns>
        /// <see cref="DateTimeOffset"/>.
        /// </returns>
        DateTimeOffset GetLastModified(string path);

        /// <summary>
        /// Gets the created date/time of the file, expressed as a UTC value.
        /// </summary>
        /// <param name="path">The path to the file.</param>
        /// <returns>
        /// <see cref="DateTimeOffset"/>.
        /// </returns>
        DateTimeOffset GetCreated(string path);
    }

    // this should be part of IFileSystem but we don't want to change the interface
    public interface IFileSystem2 : IFileSystem
    {
        long GetSize(string path);

        bool CanAddPhysical { get; }

        void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false);

        // TODO: implement these
        //
        //void CreateDirectory(string path);
        //
        //// move or rename, directory or file
        //void Move(string source, string target);
    }
}
