using System;
using System.IO;

namespace Volpe.Cafe.Logging
{
    /// <summary>
    /// Defines a logger object that includes output file streams for logging errors, warnings, summary, and compliance
    /// findings of the compliance models.
    /// </summary>
    public interface ILogger : IDisposable
    {
        /// <summary>
        /// Gets an object that can be used to synchronize access to the <see cref="ILogger"/>.
        /// </summary>
        object SyncRoot { get; }

        /// <summary>
        /// Gets whether the <see cref="ILogger"/> is disposed.
        /// </summary>
        bool IsDisposed { get; }

        /// <summary>
        /// Gets the level of logging associated with this <see cref="ILogger"/>.
        /// </summary>
        LogLevel LogLevel { get; }

        /// <summary>
        /// Gets the path where all standard log files are located.
        /// </summary>
        string LogPath { get; }
        /// <summary>
        /// Gets the path where all debugging log files are located.
        /// </summary>
        string DebugLogPath { get; }

        /// <summary>
        /// Gets the "summary.txt" file stream to use for logging summary information for the compliance model.
        /// This value may be null.
        /// </summary>
        TextWriter Summary { get; }
        /// <summary>
        /// Gets the "warnings.txt" file stream to use for logging non-critical modeling warnings.
        /// This value may be null.
        /// </summary>
        TextWriter Warnings { get; }
        /// <summary>
        /// Gets the "errors.txt" file stream to use for logging critical modeling errors.
        /// This value may be null.
        /// </summary>
        TextWriter Errors { get; }

        /// <inheritdoc cref="Dispose()"/>
        void Close();

        /// <summary>
        /// Closes all open log files and disposes of this <see cref="ILogger"/> object.
        /// </summary>
        /// <exception cref="IOException">An I/O error has occurred.</exception>
        /// <inheritdoc cref="StreamWriter.Close()" path="/exception"/>
        new void Dispose();

        //----- compliance logs -----
        /// <summary>
        /// Initializes one or more buffered writers for logging compliance findings (CFs) to a text file, using the
        /// specified number of buffers for each file. If compliance finding logs have already been initialized, if
        /// <see cref="LogLevel"/> is less than <see cref="LogLevel.L2"/>, or if logging has been disabled for this
        /// object (i.e., <see cref="LogLevel.Disabled"/>), this call has no effect.
        /// </summary>
        /// <param name="logCount">
        ///     The number of log files to create for logging. This should typically match the number of compliance
        ///     scenarios being evaluated.
        /// </param>
        /// <param name="bufferCount">
        ///     <inheritdoc cref="BufferedComplianceWriter(string, int, bool)" path="/param[@name='bufferCount']"/>
        ///     This should typically match the number of manufacturers being evaluated.
        /// </param>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        /// <exception cref="ArgumentOutOfRangeException">log count or buffer count less than one.</exception>
        /// <inheritdoc cref="ComplianceWriter(string, bool)" path="/exception"/>
        void InitCfLogs(int logCount, int bufferCount);

        /// <summary>
        /// Returns a compliance finding log file for the specified <paramref name="index"/>, or null, if compliance
        /// finding logging has not been initialized.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     index is less than 0. -or- index is equal to or greater than number of defined compliance finding logs.
        /// </exception>
        BufferedComplianceWriter GetCfLog(int index);

        /// <summary>
        /// Flushes the buffered writes of all compliance finding log files to the underlying streams.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void FlushCfLogs();

        //----- credit trading logs -----
        /// <summary>
        /// Initializes one or more writers for logging credit trading transactions to a text file. If credit trading
        /// logs have already been initialized, if <see cref="LogLevel"/> is less than <see cref="LogLevel.L2"/>, or if
        /// logging has been disabled for this object (i.e., <see cref="LogLevel.Disabled"/>), this call has no effect.
        /// </summary>
        /// <param name="logCount">
        ///     The number of log files to create for logging. This should typically match the number of compliance
        ///     scenarios being evaluated.
        /// </param>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        /// <exception cref="ArgumentOutOfRangeException">log count less than one.</exception>
        /// <inheritdoc cref="StreamWriter(string, bool)" path="/exception"/>
        void InitCreditTradingLogs(int logCount);

        /// <summary>
        /// Returns a credit trading log file for the specified <paramref name="index"/>, or null, if credit trading
        /// logging has not been initialized.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     index is less than 0. -or- index is equal to or greater than number of defined credit trading logs.
        /// </exception>
        LogFileWriter GetCreditTradingLog(int index);

        //----- custom & debug logs -----
        /// <summary>
        /// Obtains a custom log for the specified <paramref name="fileName"/> at the standard <see cref="LogPath"/>
        /// location.
        /// </summary>
        /// <param name="fileName">
        ///     The partial file name for the new log, which is written to the standard <see cref="LogPath"/>.
        /// </param>
        /// <param name="headers">
        ///     An array of column headers that will be written to the log file, if a new file is created.
        /// </param>
        /// <param name="persistent">
        ///     <c>true</c>, to save a newly created log file to this <see cref="ILogger"/> object for future use;
        ///     <c>false</c>, to return a log file without saving. Not applicable when reusing an existing log.
        /// </param>
        /// <returns>
        /// A custom log for the specified <paramref name="fileName"/>, or <c>null</c>, if <see cref="LogLevel"/> is
        /// less than <see cref="LogLevel.L2"/> or if logging has been disabled for this object (i.e.,
        /// <see cref="LogLevel.Disabled"/>).
        /// </returns>
        /// <remarks>
        /// If a valid log for this file exists (has previously been created and is not disposed), a reference to the
        /// previous <see cref="LogFileWriter"/> object will be returned. If the log does not exist (or was disposed),
        /// a new <see cref="LogFileWriter"/> instance will be created, overwriting any previous data. The specified
        /// <paramref name="headers"/> will be written to the file upon successful opening. Once a new log is created,
        /// it will be added to this <see cref="ILogger"/> object for future use, if the <paramref name="persistent"/>
        /// parameter is <c>true</c>.
        /// <br/><br/>
        /// Note that when the <see cref="ILogger"/> object is disposed, any custom logs will be disposed as well.
        /// </remarks>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        /// <inheritdoc cref="LogFileWriter(string, string[])" path="/exception"/>
        LogFileWriter GetCustomLog(string fileName, string[] headers, bool persistent = true);

        /// <summary>
        /// Obtains a custom log for the specified <paramref name="fileName"/> at the <see cref="DebugLogPath"/>
        /// location.
        /// </summary>
        /// <param name="fileName">
        ///     The partial file name for the new log, which is written to the <see cref="DebugLogPath"/>.
        /// </param>
        /// <param name="headers">
        ///     <inheritdoc cref="GetCustomLog(string, string[], bool)" path="/param[@name='headers']"/>
        /// </param>
        /// <param name="persistent">
        ///     <inheritdoc cref="GetCustomLog(string, string[], bool)" path="/param[@name='persistent']"/>
        /// </param>
        /// <returns>
        /// A custom log for the specified <paramref name="fileName"/>, or <c>null</c>, if <see cref="LogLevel"/> is
        /// less than <see cref="LogLevel.L3"/> or if logging has been disabled for this object (i.e.,
        /// <see cref="LogLevel.Disabled"/>).
        /// </returns>
        /// <inheritdoc cref="GetCustomLog(string, string[], bool)" path="/remarks"/>
        /// <inheritdoc cref="GetCustomLog(string, string[], bool)" path="/exception"/>
        LogFileWriter GetDebugLog(string fileName, string[] headers, bool persistent = true);

        //----- helpers for logging Summary/Warning/Error -----
        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Summary"/>
        /// log file.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void LogSummary(string value);
        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Warnings"/>
        /// log file.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void LogWarning(string value);
        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Errors"/>
        /// log file.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void LogError(string value);

        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Summary"/>
        /// log file, in a thread-safe context.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void SafeLogSummary(string value);
        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Warnings"/>
        /// log file, in a thread-safe context.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void SafeLogWarning(string value);
        /// <summary>
        /// Writes the specified <paramref name="value"/>, followed by a line terminator, to the <see cref="Errors"/>
        /// log file, in a thread-safe context.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The logger object is disposed.</exception>
        void SafeLogError(string value);

    }
}
