using System;
using System.IO;

namespace Volpe.Cafe.IO.DSV
{
    /// <summary>
    /// Provides helper methods for delegating exception handling for the <see cref="DsvReader"/> and the
    /// <see cref="DsvWriter"/>.
    /// </summary>
    [Serializable]
    public static class ThrowHelper
    {
        /// <summary>
        /// Checks if the <see cref="DsvReader"/> is disposed, and throws an <see cref="ObjectDisposedException"/> if
        /// it was.
        /// </summary>
        public static void ThrowIfDisposed(this DsvReader reader)
        {
            if (reader.IsDisposed) {
                ReaderClosed(reader);
            }
        }

        /// <summary>
        /// Checks if the <see cref="DsvWriter"/> is disposed, and throws an <see cref="ObjectDisposedException"/> if
        /// it was.
        /// </summary>
        public static void ThrowIfDisposed(this DsvWriter writer)
        {
            if (writer.IsDisposed) {
                WriterClosed(writer);
            }
        }

        /// <summary>
        /// Checks if a file at the specified path exists, and throws a <see cref="FileNotFoundException"/> if it does
        /// not exist.
        /// </summary>
        public static void ThrowIfFileNotFound(string path)
        {
            if (!File.Exists(path)) {
                FileNotFound(path);
            }
        }

        /// <summary>
        /// Checks if the specified headers are valid, and throws an <see cref="ArgumentNullException"/> or an
        /// <see cref="ArgumentException"/> if they are not.
        /// </summary>
        public static void ThrowIfHeadersNotValid(string[] headers)
        {
            if (headers == null) {
                HeadersArrayMayNotBeNull();
            }
            if (headers.Length == 0) {
                HeadersArrayMayNotBeEmpty();
            }
        }

        /// <summary>
        /// Checks if the specified values are valid for writing to the DSV file, and throws an
        /// <see cref="ArgumentNullException"/> or an <see cref="ArgumentException"/> if they are not.
        /// </summary>
        public static void ThrowIfValuesNotValid(object[] values, int headersLength)
        {
            if (values == null) {
                ValuesArrayMayNotBeNull();
            }
            if (values.Length == 0) {
                ValuesArrayMayNotBeEmpty();
            }
            if (values.Length != headersLength) {
                ValuesAndHeadersLengthDiffers();
            }
        }

        /// <summary>
        /// Throws: FileNotFoundException("The specified file cannot be found.", path)
        /// </summary>
        internal static void FileNotFound(string path)
        {
            throw new FileNotFoundException("The specified file cannot be found.", path);
        }

        /// <summary>
        /// Throws: ObjectDisposedException(null, $"Cannot read from a closed {reader.GetType().Name}.")
        /// </summary>
        internal static void ReaderClosed(DsvReader reader)
        {
            throw new ObjectDisposedException(null, $"Cannot read from a closed {reader.GetType().Name}.");
        }

        /// <summary>
        /// Throws: ObjectDisposedException(null, $"Cannot write to a closed {writer.GetType().Name}.")
        /// </summary>
        internal static void WriterClosed(DsvWriter writer)
        {
            throw new ObjectDisposedException(null, $"Cannot write to a closed {writer.GetType().Name}.");
        }

        /// <summary>
        /// Throws: ArgumentNullException(null, "'headers' array may not be null when creating new file.")
        /// </summary>
        internal static void HeadersArrayMayNotBeNull()
        {
            throw new ArgumentNullException(null, "'headers' array may not be null when creating new file.");
        }

        /// <summary>
        /// Throws: ArgumentException("'headers' array may not be empty when creating new file.")
        /// </summary>
        internal static void HeadersArrayMayNotBeEmpty()
        {
            throw new ArgumentException("'headers' array may not be empty when creating new file.");
        }

        /// <summary>
        /// Throws: ArgumentNullException(null, "'values' array may not be null.")
        /// </summary>
        internal static void ValuesArrayMayNotBeNull()
        {
            throw new ArgumentNullException(null, "'values' array may not be null.");
        }

        /// <summary>
        /// Throws: ArgumentException("'values' array may not be empty.")
        /// </summary>
        internal static void ValuesArrayMayNotBeEmpty()
        {
            throw new ArgumentException("'values' array may not be empty.");
        }

        /// <summary>
        /// Throws: ArgumentException("'values' and 'headers' length differs.")
        /// </summary>
        internal static void ValuesAndHeadersLengthDiffers()
        {
            throw new ArgumentException("'values' and 'headers' length differs.");
        }

    }
}
