#region << Using Directives >>
using System;
using System.IO;
using Volpe.Cafe.Data;
using Volpe.Cafe.Model;
using Volpe.Cafe.Settings;
using System.Collections.Generic;
#endregion
namespace Volpe.Cafe.IO.Reporting.CSV
{
    [Serializable]
    public class CsvReportGenerator
    {
        #region 
        CsvReportGenerator()
        {
            this._isEmpty = true;
        }
        public CsvReportGenerator(ICompliance compliance)
        {
            this._compliance = compliance;
            this._compliance.ScenarioCompleted += new ModelingProgressEventHandler(this.Compliance_ScenarioCompleted);
            this._compliance.ModelingCompleted += new ModelingEventHandler(this.Compliance_ModelingStoppedOrCompleted);
            this._compliance.ModelingStopped   += new ModelingEventHandler(this.Compliance_ModelingStoppedOrCompleted);
            this._isEmpty = false;
        }
        #endregion
        #region 
        void Compliance_ModelingStoppedOrCompleted(object sender, ModelingEventArgs e)
        {
            this._compliance.ScenarioCompleted -= new ModelingProgressEventHandler(this.Compliance_ScenarioCompleted);
            this._compliance.ModelingCompleted -= new ModelingEventHandler(this.Compliance_ModelingStoppedOrCompleted);
            this._compliance.ModelingStopped   -= new ModelingEventHandler(this.Compliance_ModelingStoppedOrCompleted);
        }
        void Compliance_ScenarioCompleted(object sender, ModelingProgressEventArgs e)
        {
            this.GenerateReportsForScenario((e.Progress == null) ? null : e.Progress.Scenario);
        }
        protected void GenerateReportsForScenario(Scenario scen)
        {
            if (scen == null || this.IsModelStopped()) { return; }
            try
            {
                this._reporting = true;
                this._reportingProgress = "Initializing reports ...";
                this._csvReports = this.OpenReports(scen.Index);
                if (!this.IsModelStopped())
                {
                    for (int i = 0; i < this._compliance.ModelYears.Length; i++)
                    {
                        if (this.IsModelStopped()) { break; }
                        ModelYear year = this._compliance.ModelYears[i];
                        this.WriteReportData(scen, year);
                    } 
                }
            }
            catch (OutputException ex) { Console.WriteLine(ex.ToString()); throw ex; }
            catch (Exception       ex) { Console.WriteLine(ex.ToString()); throw new OutputException("<unknown file>", null, ex); }
            finally
            {
                this.CloseReports(scen.Index);  
                this._reportingProgress = "Reporting for scenario " + scen.Index + " completed.";
                this._reporting = false;
            }
        }
        protected virtual List<CsvReportingBase> OpenReports(int snIndex)
        {
            return this.OpenReports(snIndex, this.OutputPath);
        }
        protected virtual List<CsvReportingBase> OpenReports(int snIndex, string path)
        {
            this.UpdateProgress("Opening CSV reports ...");
            if (!Directory.Exists(path)) { Directory.CreateDirectory(path); }
            List<CsvReportingBase> csvReports = new List<CsvReportingBase>(10);
            csvReports.Add(new CsvComplianceReport               (path + "\\compliance_report.csv"             , (snIndex > 0)));
            csvReports.Add(new CsvTechnologyUtilizationReport    (path + "\\technology_utilization_report.csv" , (snIndex > 0)));
            csvReports.Add(new CsvVehiclesReport                 (path + "\\vehicles_report.csv"               , (snIndex > 0)));
            csvReports.Add(new CsvSocietalEffectsByVehClassReport(path + "\\societal_effects_report_vc.csv"    , (snIndex > 0)));
            csvReports.Add(new CsvSocietalEffectsByRegClassReport(path + "\\societal_effects_report_rc.csv"    , (snIndex > 0)));
            csvReports.Add(new CsvAnnualSocietalEffectsReport    (path + "\\annual_societal_effects_report.csv", (snIndex > 0)));
            csvReports.Add(new CsvSocietalCostsByVehClassReport  (path + "\\societal_costs_report_vc.csv"      , (snIndex > 0)));
            csvReports.Add(new CsvSocietalCostsByRegClassReport  (path + "\\societal_costs_report_rc.csv"      , (snIndex > 0)));
            csvReports.Add(new CsvAnnualSocietalCostsReport      (path + "\\annual_societal_costs_report.csv"  , (snIndex > 0)));
            return csvReports;
        }
         void WriteReportData(Scenario scen, ModelYear year)
        {
            if (this._csvReports != null)
            {
                for (int i = 0; i < this._csvReports.Count; i++)
                {
                    this.WriteReportData(this._csvReports[i], scen, year);
                }
            }
        }
         void WriteReportData(CsvReportingBase report, Scenario scen, ModelYear year)
        {
            if (report != null && !report.Disposed)
            {
                this.UpdateProgress("Writing model year " + year.Year + " data for the " + report.ReportName + ".");
                report.ParseData(scen, year, this._compliance);
            }
        }
         void CloseReports(int snIndex)
        {
            if (this._csvReports != null)
            {
                for (int i = 0; i < this._csvReports.Count; i++)
                {
                    this.CloseReport(this._csvReports[i]);
                    this._csvReports[i] = null;
                }
            }
        }
         void CloseReport(CsvReportingBase report)
        {
            if (report != null && !report.Disposed)
            {
                this.UpdateProgress("Saving " + report.ReportName + ".");
                report.Close();
            }
        }
         void UpdateProgress(string progress)
        {
            this._reportingProgress = progress;
        }
        protected bool IsModelStopped()
        {
            return (this._compliance.Stopped || this._compliance.State == ModelingState.StopRequested);
        }
        #endregion
        #region 
        public bool Reporting { get { return !this._isEmpty && this._reporting; } }
        public string ReportingProgress { get { return this._reportingProgress; } }
        protected ICompliance Compliance { get { return this._compliance; } }
        protected string OutputPath { get { return this._compliance.Settings.OutputSettings.OutputPath + "\\reports-csv"; } }
        #endregion
        #region 
        public static readonly CsvReportGenerator Empty = new CsvReportGenerator();
        ICompliance _compliance;
        List<CsvReportingBase> _csvReports;
        bool   _isEmpty;
        bool   _reporting;
        string _reportingProgress;
        #endregion
    }
}

