using System;

namespace Volpe.Cafe.Reporting
{
    /// <summary>
    /// Specifies the level of reporting to use.
    /// </summary>
    [Serializable, Flags]
    public enum ReportingLevel : uint
    {
        /// <summary>
        /// Specifies that reporting should be disabled.
        /// </summary>
        Disabled = 0U,

        /// <summary>
        /// Specifies a minimal level of reporting, where only the compliance, societal effects and costs, consumer
        /// costs, and technology utilization reports are generated.
        /// </summary>
        Minimal = 1U << 0,

        /// <summary>
        /// Specifies a custom reporting level, that enables the generating of annual societal effects and costs
        /// reports, along with their annual summary versions.
        /// </summary>
        AnnualEffectsAndCosts = 1U << 1,
        /// <summary>
        /// Specifies a custom reporting level, that enables the generating of vehicle-, platform-, engine-, and
        /// transmission-level reports.
        /// </summary>
        VehicleAndComponent = 1U << 2,
        /// <summary>
        /// Specifies a custom reporting level, that enables the generating of all diagnostic reports (e.g., vehicles
        /// diagnostic report).
        /// </summary>
        DiagnosticReports = 1U << 3,

        /// <summary>
        /// Specifies a default level of reporting, where all <see cref="Minimal"/> reports are generated, along with
        /// the <see cref="AnnualEffectsAndCosts"/> and <see cref="VehicleAndComponent"/> reports.
        /// </summary>
        Default = Minimal | AnnualEffectsAndCosts | VehicleAndComponent,
        /// <summary>
        /// Specifies a diagnostic level of reporting, where all <see cref="Minimal"/> and <see cref="Default"/>
        /// reports are generated, along with all <see cref="DiagnosticReports"/>.
        /// </summary>
        Diagnostic = Default | DiagnosticReports,

        /// <summary>
        /// Specifies that the large reports should be split into multiple files by scenario.
        /// </summary>
        SplitLargeReports = 1U << 30

    }

    /// <summary>
    /// Specifies additional flags to pass to a <see cref="ReportDataGenerator"/>.
    /// </summary>
    [Serializable, Flags]
    public enum DataGeneratorFlags
    {
        /// <summary>
        /// Specifies that no additional flags shall be passed to a <see cref="ReportDataGenerator"/>.
        /// </summary>
        None = 0,

        /// <summary>
        /// Specifies whether to generate data for a "summarized" version of the report.
        /// </summary>
        Summary = 1,
        /// <summary>
        /// Specifies whether to generate data for an "incremental" version of the report.
        /// </summary>
        Incremental = 2
    }

    /// <summary>
    /// Provides extension methods for various enumerations.
    /// </summary>
    [Serializable]
    public static class EnumExtensions
    {
        #region < Enum ReportingLevel >

        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance is
        /// <see cref="ReportingLevel.Disabled"/>.
        /// </summary>
        public static bool IsDisabled(this ReportingLevel src) => (src == ReportingLevel.Disabled);

        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance is
        /// <see cref="ReportingLevel.Minimal"/>.
        /// </summary>
        public static bool IsMinimal(this ReportingLevel src) => (src == ReportingLevel.Minimal);
        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance is
        /// <see cref="ReportingLevel.Default"/>.
        /// </summary>
        public static bool IsDefault(this ReportingLevel src) => (src == ReportingLevel.Default);
        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance is
        /// <see cref="ReportingLevel.Diagnostic"/>.
        /// </summary>
        public static bool IsDiagnostic(this ReportingLevel src) => (src == ReportingLevel.Diagnostic);

        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance enables
        /// <see cref="ReportingLevel.Minimal"/> reports.
        /// </summary>
        public static bool HasMinimal(this ReportingLevel src)
        {
            return src.Contains(ReportingLevel.Minimal);
        }
        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance enables
        /// <see cref="ReportingLevel.AnnualEffectsAndCosts"/> reports.
        /// </summary>
        public static bool HasAnnualEffectsAndCosts(this ReportingLevel src)
        {
            return src.Contains(ReportingLevel.AnnualEffectsAndCosts);
        }
        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance enables
        /// <see cref="ReportingLevel.VehicleAndComponent"/> reports.
        /// </summary>
        public static bool HasVehicleAndComponent(this ReportingLevel src)
        {
            return src.Contains(ReportingLevel.VehicleAndComponent);
        }
        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance enables
        /// <see cref="ReportingLevel.Diagnostic"/> reports.
        /// </summary>
        public static bool HasDiagnosticReports(this ReportingLevel src)
        {
            return src.Contains(ReportingLevel.DiagnosticReports);
        }

        /// <summary>
        /// Determines whether the specified <see cref="ReportingLevel"/> instance enables the
        /// <see cref="ReportingLevel.SplitLargeReports"/> option.
        /// </summary>
        public static bool HasSplitLargeReports(this ReportingLevel src)
        {
            return src.Contains(ReportingLevel.SplitLargeReports);
        }

        private static bool Contains(this ReportingLevel src, ReportingLevel value)
        {
            return (src & value) == value;
        }

        #endregion

        #region < Enum DataGeneratorFlags >

        /// <summary>
        /// Determines whether the specified <see cref="DataGeneratorFlags"/> instance is
        /// <see cref="DataGeneratorFlags.None"/>.
        /// </summary>
        public static bool IsNone(this DataGeneratorFlags src) => (src == DataGeneratorFlags.None);

        /// <summary>
        /// Determines whether the specified <see cref="DataGeneratorFlags"/> instance is
        /// <see cref="DataGeneratorFlags.Summary"/>.
        /// </summary>
        public static bool IsSummary(this DataGeneratorFlags src) => (src == DataGeneratorFlags.Summary);
        /// <summary>
        /// Determines whether the specified <see cref="DataGeneratorFlags"/> instance is
        /// <see cref="DataGeneratorFlags.Incremental"/>.
        /// </summary>
        public static bool IsIncremental(this DataGeneratorFlags src) => (src == DataGeneratorFlags.Incremental);

        /// <summary>
        /// Determines whether the specified <see cref="DataGeneratorFlags"/> instance is a composite value, containing
        /// a <see cref="DataGeneratorFlags.Summary"/> flag.
        /// </summary>
        public static bool HasSummary(this DataGeneratorFlags src) => src.Contains(DataGeneratorFlags.Summary);
        /// <summary>
        /// Determines whether the specified <see cref="DataGeneratorFlags"/> instance is a composite value, containing
        /// a <see cref="DataGeneratorFlags.Incremental"/> flag.
        /// </summary>
        public static bool HasIncremental(this DataGeneratorFlags src) => src.Contains(DataGeneratorFlags.Incremental);

        private static bool Contains(this DataGeneratorFlags src, DataGeneratorFlags value)
        {
            return (src & value) == value;
        }

        #endregion
    }
}
