using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Volpe.Cafe.IO;
using Volpe.Cafe.Utils;
using Volpe.Cafe.Generic;
namespace Volpe.Cafe.Data
{
    [Serializable]
    public sealed class Industry : ICloneable
    {
        #region 
        [Serializable]
        public sealed class CModelData
        {
            #region 
            internal CModelData() { }
            #endregion
            #region 
            internal Industry.CModelData Clone()
            {
                Industry.CModelData imd = new Industry.CModelData();
                if (this.TechUsedSales != null)
                {
                    imd.TechUsedSales = new RCDouble[this.TechUsedSales.Length];
                    for (int i = 0; i < this.TechUsedSales.Length; i++)
                    {
                        imd.TechUsedSales[i] = this.TechUsedSales[i].Clone();
                    }
                }
                imd.MinFP = this.MinFP;
                imd.MaxFP = this.MaxFP;
                imd.MinCW = this.MinCW;
                imd.MaxCW = this.MaxCW;
                return imd;
            }
            internal void UpdateFPCW(List<Manufacturer> mfrs)
            {
                double minFP = 99999; double minCW = 99999;
                double maxFP = -1;    double maxCW = -1;
                for (int i = 0, mfrCount = mfrs.Count; i < mfrCount; i++)
                {   
                    Manufacturer mfr = mfrs[i];
                    for (int j = 0, vehCount = mfr.VehicleCount; j < vehCount; j++)
                    {
                        Vehicle.CDescription vd = mfr.Vehicles[j].Description;
                        double fp = vd.Footprint, cw = vd.CurbWeight;
                        if (fp < minFP) { minFP = fp; } else if (fp > maxFP) { maxFP = fp; }
                        if (cw < minCW) { minCW = cw; } else if (cw > maxCW) { maxCW = cw; }
                    } 
                } 
                this.MinFP = minFP; this.MaxFP = maxFP;
                this.MinCW = minCW; this.MaxCW = maxCW;
            }
            #endregion
            #region 
            public RCDouble[] TechUsedSales;
            public double MinFP;
            public double MaxFP;
            public double MinCW;
            public double MaxCW;
            #endregion
        }
        #endregion
        #region 
        Industry() { }
        internal Industry(List<Manufacturer> mfrs, int minYear, int maxYear)
        {
            this._modelData     = new CModelData();
            this._manufacturers = mfrs;
            this._minYear = new ModelYear(minYear);
            this._maxYear = new ModelYear(maxYear);
        }
        #endregion
        #region 
        #region 
        object ICloneable.Clone()
        {
            return this.Clone();
        }
        public Industry Clone()
        {
            Industry ind = new Industry();
            ind._modelData     = this._modelData.Clone();
            ind._manufacturers = this.CloneManufacturers(this._manufacturers);
            ind._minYear       = new ModelYear(this._minYear.Year);
            ind._maxYear       = new ModelYear(this._maxYear.Year);
            return ind;
        }
        List<Manufacturer> CloneManufacturers(List<Manufacturer> list)
        {
            List<Manufacturer> newList = new List<Manufacturer>(list.Count);
            for (int i = 0, count = list.Count; i < count; i++)
            {
                newList.Add((Manufacturer)(list[i].Clone()));
            }
            return newList;
        }
        #endregion
        public void WriteSummaryLog(LogWriter writer)
        {
            if (writer.Summary == null) { return; }
            writer.Summary.WriteLine("---------- Modeling Data ----------");
            writer.Summary.WriteLine("--- Model Years Analyzed ---\n  "
                + this._minYear.ToString() + " to " + this._maxYear.ToString() + "\n");
            writer.Summary.WriteLine("--- Valid Manufacturers ---");
            for (int i = 0, mfrCount = this._manufacturers.Count; i < mfrCount; i++)
            {
                Manufacturer mfr = this._manufacturers[i];
                string mfrSummary = "  " + mfr.Index + ". Code=" + mfr.Description.Code + ", Name=" + mfr.Description.Name;
                mfrSummary += "\n      Vehicles=" + mfr.VehicleCount;
                for (int j = 0; j < VCValue<object>.Classes.Length; j++)
                {
                    mfrSummary += ((j == 0) ? " (" : ", ") + VCValue<object>.Names[j] + "=" +
                        this.Log_GetVehCountByClass(mfr.Vehicles, VCValue<object>.Classes[j]);
                }
                mfrSummary += ")";
                mfrSummary += "\n      Engines=" + mfr.Engines.Count;
                mfrSummary += "\n      Transmissions=" + mfr.Transmissions.Count;
                writer.Summary.WriteLine(mfrSummary);
            }
            writer.Summary.WriteLine();
            writer.Summary.WriteLine("--- Industry Summary ---");
            int engs = 0, trns = 0, vehs = 0;
            VCValue<int> vehsByClass = new VCValue<int>();
            for (int i = 0, mfrCount = this._manufacturers.Count; i < mfrCount; i++)
            {
                Manufacturer mfr = this._manufacturers[i];
                engs += mfr.Engines.Count;
                trns += mfr.Transmissions.Count;
                vehs += mfr.VehicleCount;
                foreach(VehicleClass vehClass in VCValue<object>.Classes)
                {
                    vehsByClass[vehClass] += this.Log_GetVehCountByClass(mfr.Vehicles, vehClass);
                }
            }
            writer.Summary.WriteLine("  Total Manufacturers Analyzed:  " + this._manufacturers.Count);
            writer.Summary.WriteLine("  Total Vehicles Analyzed:  " + vehs);
            for (int i = 0; i < VCValue<object>.Classes.Length; i++)
            {
                string vcName = VCValue<object>.Names[i];
                vcName = "    " + vcName + ":" + new string(' ', vcName.Length - 2);
                writer.Summary.WriteLine(vcName + vehsByClass.Items[i]);
            }
            writer.Summary.WriteLine("  Total Engines Analyzed:   " + engs);
            writer.Summary.WriteLine("  Total Transmissions Analyzed:  " + trns);
            writer.Summary.WriteLine();
        }
        int Log_GetVehCountByClass(List<Vehicle> vehs, VehicleClass vehClass)
        {
            int count = 0;
            for (int i = 0, vehCount = vehs.Count; i < vehCount; i++)
            {
                if (vehs[i].VehicleClass == vehClass) { count++; }
            }
            return count;
        }
        public void UpdateMinMaxFpCw()
        {
            this._modelData.UpdateFPCW(this._manufacturers);
        }
        public static Industry BuildMergedFleet(Industry ind)
        {
            return BuildMergedFleet(ind, "MERGED FLEET");
        }
        public static Industry BuildMergedFleet(Industry ind, string newMfrName)
        {
            if (newMfrName == null || newMfrName.Trim().Length == 0) { throw new ArgumentException(ErrorStrings.MergedFleetNewMfrNameNull, "newMfrName"); }
            Manufacturer.CDescription baseMD = ind.Manufacturers[0].Description.Clone();
            ind = ind.Clone();
            List<Vehicle     > vehs = new List<Vehicle     >();
            List<Engine      > engs = new List<Engine      >();
            List<Transmission> trns = new List<Transmission>();
            for (int i = 0, mfrCount = ind._manufacturers.Count; i < mfrCount; i++)
            {   
                vehs.AddRange(ind._manufacturers[i].Vehicles     );
                engs.AddRange(ind._manufacturers[i].Engines      );
                trns.AddRange(ind._manufacturers[i].Transmissions);
            }
            int vehIndex = 1, engIndex = 1, trnIndex = 1;
            for (int i = 0, vehCount = vehs.Count; i < vehCount; i++)
            {   
                string mfrName = vehs[i].Description.Manufacturer;
                vehs[i].Description.Manufacturer = newMfrName;
                vehs[i].Description.Code         = vehIndex;
                vehs[i].Description.Model        = mfrName + "_" + vehs[i].Description.Model;
                vehs[i].Description.Nameplate    = mfrName + "_" + vehs[i].Description.Nameplate;
                vehs[i].Description.Origin       = 'D';
                vehIndex++;
            }
            for (int i = 0, engCount = engs.Count; i < engCount; i++)
            {   
                string mfrName = engs[i].Description.Manufacturer;
                engs[i].Description.Manufacturer = newMfrName;
                engs[i].Description.Code         = engIndex;
                for (int j = 0, vehCount = engs[i].Vehicles.Count; j < vehCount; j++)
                {   
                    engs[i].Vehicles[j].Description.EngineCode = engIndex;
                }
                engIndex++;
            }
            for (int i = 0, trnCount = trns.Count; i < trnCount; i++)
            {   
                string mfrName = trns[i].Description.Manufacturer;
                trns[i].Description.Manufacturer = newMfrName;
                trns[i].Description.Code         = trnIndex;
                for (int j = 0, vehCount = trns[i].Vehicles.Count; j < vehCount; j++)
                {   
                    trns[i].Vehicles[j].Description.TransmissionCode = trnIndex;
                }
                trnIndex++;
            }
            Manufacturer.CDescription md = new Manufacturer.CDescription();
            md.Code                      = 1;
            md.Name                      = newMfrName;
            md.CostAllocationStrategy    = 0;
            md.DiscountRate              = baseMD.DiscountRate;
            md.PaybackPeriod             = baseMD.PaybackPeriod;
            md.PaybackPeriod_OC          = baseMD.PaybackPeriod_OC;
            md.WillingToPayFines         = new bool  [ind._maxYear.Index + 1];
            md.AvailableCredits          = new RCObject<double[]>(
                                                new double[ind._maxYear.Index + 1],
                                                new double[ind._maxYear.Index + 1],
                                                new double[ind._maxYear.Index + 1]);
            md.CreditsApplyToBaseline    = false;
            int minYear, maxYear;
            Manufacturer mfr = new Manufacturer(md);
            mfr.Initialize(vehs, engs, trns, out minYear, out maxYear);
            mfr.Index = 0;
            ind._manufacturers.Clear();
            ind._manufacturers.Add(mfr);
            return ind;
        }
        public double CalcLaborHours(ModelYear year, RegulatoryClass regClass)
        {
            double hours = 0;
            for (int i = 0, mfrCount = this._manufacturers.Count; i < mfrCount; i++)
            {
                hours += this._manufacturers[i].CalcLaborHours(year, regClass);
            }
            return hours;
        }
        public double CalcLaborHours(ModelYear minYear, ModelYear maxYear, RegulatoryClass regClass)
        {
            double hours = 0;
            for (int i = 0, mfrCount = this._manufacturers.Count; i < mfrCount; i++)
            {
                hours += this._manufacturers[i].CalcLaborHours(minYear, maxYear, regClass);
            }
            return hours;
        }
        bool HasValues(bool[] value)
        {
            if (value == null) { return false; }
            for (int i = 0; i < value.Length; i++)
            {
                if (value[i]) { return true; }
            }
            return false;
        }
        #endregion
        #region 
        public Industry.CModelData ModelData { get { return this._modelData; } }
        public List<Manufacturer> Manufacturers { get { return this._manufacturers; } }
        public int ManufacturerCount { get { return (this._manufacturers == null) ? 0 : this._manufacturers.Count; } }
        public List<Vehicle> Vehicles
        {
            get
            {
                List<Vehicle> list = new List<Vehicle>(this.VehicleCount);
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    list.AddRange(this._manufacturers[i].Vehicles);
                }
                return list;
            }
        }
        public List<Engine> Engines
        {
            get
            {
                List<Engine> list = new List<Engine>(this.EngineCount);
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    list.AddRange(this._manufacturers[i].Engines);
                }
                return list;
            }
        }
        public List<Transmission> Transmissions
        {
            get
            {
                List<Transmission> list = new List<Transmission>(this.TransmissionCount);
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    list.AddRange(this._manufacturers[i].Transmissions);
                }
                return list;
            }
        }
        public List<Platform> Platforms
        {
            get
            {
                List<Platform> list = new List<Platform>(this.PlatformCount);
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    list.AddRange(this._manufacturers[i].Platforms);
                }
                return list;
            }
        }
        public int VehicleCount
        {
            get
            {
                int count = 0;
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    count += this._manufacturers[i].VehicleCount;
                }
                return count;
            }
        }
        public int EngineCount
        {
            get
            {
                int count = 0;
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    count += this._manufacturers[i].Engines.Count;
                }
                return count;
            }
        }
        public int TransmissionCount
        {
            get
            {
                int count = 0;
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    count += this._manufacturers[i].Transmissions.Count;
                }
                return count;
            }
        }
        public int PlatformCount
        {
            get
            {
                int count = 0;
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    count += this._manufacturers[i].Platforms.Count;
                }
                return count;
            }
        }
        public RCValue<bool> RegClasses
        {
            get
            {
                if (this._regClasses != null) { return this._regClasses; }
                RCValue<bool> regClasses = new RCValue<bool>();
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    List<Vehicle> mfrVehs = this._manufacturers[i].Vehicles;
                    for (int j = 0; j < mfrVehs.Count; j++)
                    {
                        if (mfrVehs[j].RegClass != RegulatoryClass.None)
                        {
                            this._regClasses[mfrVehs[j].RegClass] = true;
                        }
                    }
                }
                if (this.HasValues(regClasses.Items)) { this._regClasses = regClasses; }
                return regClasses;
            }
        }
        public VCValue<bool> VehClasses
        {
            get
            {
                if (this._vehClasses != null) { return this._vehClasses; }
                VCValue<bool> vehClasses = new VCValue<bool>();
                for (int i = 0; i < this._manufacturers.Count; i++)
                {
                    List<Vehicle> mfrVehs = this._manufacturers[i].Vehicles;
                    for (int j = 0; j < mfrVehs.Count; j++)
                    {
                        if (mfrVehs[j].VehicleClass != VehicleClass.None)
                        {
                            vehClasses[mfrVehs[j].VehicleClass] = true;
                        }
                    }
                }
                if (this.HasValues(vehClasses.Items)) { this._vehClasses = vehClasses; }
                return vehClasses;
            }
        }
        public ModelYear MinYear { get { return this._minYear; } }
        public ModelYear MaxYear { get { return this._maxYear; } }
        #endregion
        #region 
        Industry.CModelData _modelData;
        List<Manufacturer> _manufacturers;
        ModelYear _minYear;
        ModelYear _maxYear;
        RCValue<bool> _regClasses;
        VCValue<bool> _vehClasses;
        #endregion
    }
}

