#region << Using Directives >>
using System;
using System.Collections.Generic;
using System.Text;
using Volpe.Cafe.Data;
using Volpe.Cafe.Model;
using Volpe.Cafe.Settings;
using Volpe.Cafe.Utils;
using Volpe.Cafe.Generic;
#endregion
namespace Volpe.Cafe.IO.Reporting.CSV
{
    [Serializable]
    public sealed class CsvVehiclesReport : CsvReportingBase
    {
        #region 
        static CsvVehiclesReport()
        {
            string[] feStrings = new string[7];
            foreach (string fuelName in FTValue<object>.Acronyms)
            {
                feStrings[0] += "FE Initial ("         + fuelName + "),";
                feStrings[1] += "FS Initial ("         + fuelName + "),";
                feStrings[2] += "FE Rated ("           + fuelName + "),";
                feStrings[3] += "Delta FE AC ("        + fuelName + "),";
                feStrings[4] += "Delta FE Off-Cycle (" + fuelName + "),";
                feStrings[5] += "FE Compliance ("      + fuelName + "),";
                feStrings[6] += "FS ("                 + fuelName + "),";
            }
            Header =
                "Scenario,Scenario Name,Model Year,Manufacturer,Veh Index,Veh Code,Model,Name Plate," +
                "Platform,Plt Version," +
                "Eng Code,Eng Fuel Initial,Eng Type Initial,Eng Version,Eng Fuel,Eng Type," +
                "Trn Code,Trn Type Initial,Trn Version,Trn Type," +
                feStrings[0] + "FE Initial," +
                feStrings[1] + "Fuel Initial," +
                feStrings[2] + "FE Rated," +
                feStrings[5] + "FE Compliance," +
                feStrings[6] + "Fuel," +
                "Veh Class,Reg Class,Tech Class,Safety Class,Redesign State,Refresh State,Platform Leader," +
                "Sales Initial,Sales,MSRP Initial,MSRP,k.Labor Hours," +
                "CW Initial,CW,TW Initial,TW,GVWR Initial,GVWR,GCWR Initial,GCWR,Footprint,Work Factor,FE Target,CO2 Target,CO2 Rating," +
                "Tech Cost,Price Increase,Tax Credit,Value Loss,Rel. Value Loss,Maint Cost,Repair Cost,Taxes/Fees,Financing,Insurance," +
                TechnologyIndexes.TechAbbrCSV;
        }
        public CsvVehiclesReport(string path, bool append) : base(path, append) { }
        #endregion
        #region 
        protected override string GetHeader()
        {
            return Header;
        }
        protected override void ParseData_Internal(Scenario scen, ModelYear year, ICompliance compliance)
        {
            Industry         ppData   = compliance.Data;
            Industry         scenData = compliance.GetData(scen, year);
            ModelingSettings settings = compliance.Settings;
            List<Vehicle> ppVehs  = ppData  .Vehicles;
            List<Vehicle> snVehs  = scenData.Vehicles;
            int           yrIndex = year.Index;
            for (int i = 0, vehCount = ppVehs.Count; i < vehCount; i++)
            {
                Vehicle      pVeh = ppVehs[i];
                var          pVD  = pVeh.Description;
                Engine       pEng = pVeh.Engine;
                Transmission pTrn = pVeh.Transmission;
                Platform     pPlt = pVeh.Platform;
                Vehicle      veh  = snVehs[i];
                var          vd   = veh.Description;
                var          vmd  = veh.ModelData;
                Engine       eng  = veh.Engine;
                Transmission trn  = veh.Transmission;
                Platform     plt  = veh.Platform;
                var          mmd  = veh.Manufacturer.ModelData;
                RegulatoryClass vehRC    = veh.RegClass;
                double          vehSales = vd.Sales[yrIndex];
                string          mfrName  = Interaction.GetTitleCase(vd.Manufacturer, 4);
                this.Write(scen.Index);
                this.Write(Interaction.GetTitleCase(scen.Description));
                this.Write(year.Year);
                this.Write(mfrName);
                this.Write(i);
                this.Write(vd.Code);
                this.Write(Interaction.GetTitleCase(vd.Model));
                this.Write(Interaction.GetTitleCase(vd.Nameplate));
                this.Write(pPlt.Name);
                if (plt != null)
                {
                    string pltVer = (plt.Parent != null) ? plt.Name : plt.GetComponentVersion(veh);
                    this.Write(pltVer);
                }
                if (pEng == null) { this.WriteEmpty(3); }
                else
                {
                    this.Write(pEng.Description.Code);
                    this.Write(this.GetFuelTypeString(pEng.Description.Fuel, true));
                    this.Write(pEng.Description.ToString());
                }
                if (eng == null) { this.WriteEmpty(3); }
                else
                {
                    string engVer = eng.Description.Code +
                        " (" + ((eng.Parent != null) ? eng.Parent.Description.Code.ToString() : eng.GetComponentVersion(veh)) + ")";
                    this.Write(engVer);
                    this.Write(this.GetFuelTypeString(vd.FuelEconomy.FuelType, true));
                    this.Write(this.GetVehicleEngineType(vmd.TechUsed));
                }
                if (pTrn == null) { this.WriteEmpty(2); }
                else
                {
                    this.Write(pTrn.Description.Code);
                    this.Write(pTrn.Description.ToString());
                }
                if (trn == null) { this.WriteEmpty(2); }
                else
                {
                    string trnVer = trn.Description.Code +
                        " (" + ((trn.Parent != null) ? trn.Parent.Description.Code.ToString() : trn.GetComponentVersion(veh)) + ")";
                    string trnType = this.GetVehicleTransmissionType(vmd.TechUsed);
                    if (trnType == null) { trnType = pTrn.Description.ToString(); }
                    this.Write(trnVer);
                    this.Write(trnType);
                }
                FuelValue initFE    = pVD.FuelEconomy;
                double    avgInitFE = Standards.GetAverageFuelEconomy(initFE, pVD.FuelShare, vehRC, scen, year, settings);
                this.Write(initFE       );
                this.Write(avgInitFE    );
                this.Write(pVD.FuelShare);
                this.Write(this.GetFuelTypeString(pVD.FuelEconomy.FuelType, false));
                FuelValue ratedFE    = vd.FuelEconomy;
                FuelValue complFE    = Standards.GetAdjustedFuelEconomy(veh, scen, year, settings, true, true, true);
                double    avgRatedFE = Standards.GetAverageFuelEconomy (ratedFE, vd.FuelShare, vehRC, scen, year, settings);
                double    avgComplFE = Standards.GetAverageFuelEconomy (complFE, vd.FuelShare, vehRC, scen, year, settings);
                this.Write(ratedFE     );
                this.Write(avgRatedFE  );
                this.Write(complFE     );
                this.Write(avgComplFE  );
                this.Write(vd.FuelShare);
                this.Write(this.GetFuelTypeString(vd.FuelEconomy.FuelType, false));
                this.Write(veh.VehicleClass   .ToString());
                this.Write(veh.RegClass       .ToString());
                this.Write(veh.TechnologyClass.ToString());
                this.Write(veh.SafetyClass    .ToString());
                this.Write((veh.IsAtRedesign(year)) ? "At Redesign" : null);
                this.Write((veh.IsAtRefresh (year)) ? "At Refresh"  : null);
                this.Write(((eng != null && eng.GetPlatformLeader() == veh) ? "E" : string.Empty) +
                           ((trn != null && trn.GetPlatformLeader() == veh) ? "T" : string.Empty) +
                           ((plt != null && plt.GetPlatformLeader() == veh) ? "P" : string.Empty));
                this.Write(pVD.Sales[yrIndex]);
                if (vehSales == 0)
                {
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                }
                else
                {
                    this.Write(vehSales);
                    this.Write(pVD.Msrp[yrIndex]);
                    this.Write(vd .Msrp[yrIndex] + vmd.RegCost);
                    this.Write(veh.CalcLaborHours(year));
                }
                this.Write(vd.BaseWeight);
                this.Write(vd.CurbWeight);
                this.Write(Standards.GetTestWeight(veh, scen, year, vd.BaseWeight, vd.BaseGVWR, vd.BaseGCWR, 0));
                this.Write(Standards.GetTestWeight(veh, scen, year));
                this.Write(vd.BaseGVWR  );
                this.Write(vd.GVWR      );
                this.Write(vd.BaseGCWR  );
                this.Write(vd.GCWR      );
                this.Write(vd.Footprint );
                this.Write(Standards.GetWorkFactor      (veh, scen, year));
                this.Write(Standards.GetTarget          (veh, scen, year));
                this.Write(Standards.GetVehicleCO2Target(veh, scen, year, settings));
                this.Write(Standards.GetVehicleCO2Rating(veh, scen, year, settings, true, true, true));
                if (vehSales == 0)
                {
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                    this.Write(0);
                }
                else
                {
                    this.Write(vmd.TechCost           );
                    this.Write(vmd.RegCost            );
                    this.Write(vmd.TaxCredit          );
                    this.Write(vmd.LossOfValue        );
                    this.Write(vmd.RelativeLossOfValue);
                    this.Write(vmd.MaintenanceCost    );
                    this.Write(vmd.RepairCost         );
                    this.Write(vmd.TaxesAndFees       );
                    this.Write(vmd.FinancingCost      );
                    this.Write(vmd.InsuranceCost      );
                }
                for (int j = 0; j < TechnologyIndexes.TechnologyCount; j++)
                {
                    string techUsedStr = null;
                    techUsedStr =
                        ( vmd.TechUsed     [j] && !vmd.TechApplied  [j]                                        ) ? "U" :
                        ( vmd.TechUsed     [j] &&  vmd.TechInherited[j]                                        ) ? "I" :
                        ( vmd.TechUsed     [j] &&  vmd.TechApplied  [j] && vmd.TechAppliedYear[j] == year.Index) ? "A" :
                        ( vmd.TechUsed     [j] &&  vmd.TechApplied  [j]                                        ) ? "a" :
                        (!vmd.TechEnabled  [j]                                                                 ) ? "X" :
                        ( mmd.TechExhausted[j]                                                                 ) ? "P" : null;
                    if (vmd.TechSuperseded[j]) { techUsedStr += "S"; }
                    this.Write(techUsedStr);
                } 
                this.NewRow();
            } 
        }
        void Write(FuelValue value)
        {
            foreach (FuelType fuelType in FTValue<object>.Classes)
            {
                this.Write(value[fuelType]);
            }
        }
        string GetFuelTypeString(FuelType fuelType, bool engineFuelOnly)
        {
            StringBuilder sb = new StringBuilder(8);
            for (int i = 0, fuelCount = FTValue<object>.Classes.Length; i < fuelCount; i++)
            {
                FuelType fuel = FTValue<object>.Classes[i];
                if (engineFuelOnly && (fuel == FuelType.Hydrogen || fuel == FuelType.Electricity)) { continue; }
                if ((fuelType & fuel) == fuel)
                {
                    sb.Append(FTValue<object>.Acronyms[i]);
                    sb.Append("+");
                }
            }
            return sb.ToString(0, sb.Length - 1);
        }
        string GetVehicleEngineType(bool[] techUsed)
        {
            if (techUsed[TechnologyIndexes.TRBDS1] || techUsed[TechnologyIndexes.TRBDS2] || techUsed[TechnologyIndexes.SEGR ] ||
                techUsed[TechnologyIndexes. DWNSP] || techUsed[TechnologyIndexes. CEGR1] || techUsed[TechnologyIndexes.CEGR2])
            {
                return "T";
            }
            return "NA";
        }
        string GetVehicleTransmissionType(bool[] techUsed)
        {
            if      (techUsed[TechnologyIndexes.MAN6 ]) { return "M6"; }
            else if (techUsed[TechnologyIndexes.A8SPD]) { return ((techUsed[TechnologyIndexes.DCT]) ? "DCT" : "A") + "8"; }
            else if (techUsed[TechnologyIndexes.DCT  ]) { return "DCT6"; }
            else if (techUsed[TechnologyIndexes.NAUTO]) { return "A6"; }
            else                                        { return null; }
        }
        #endregion
        #region 
        public override string ReportName { get { return CsvReportName; } }
        #endregion
        #region 
        public const string CsvReportName = "Vehicles CSV Report";
        static readonly string Header;
        #endregion
    }
}

