// Copyright 2017 European Union.
// Licensed under the EUPL (the 'Licence');
// 
// * You may not use this work except in compliance with the Licence.
// * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
// * Unless required by applicable law or agreed to in writing,
// software distributed under the Licence is distributed on an "AS IS" basis,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// 
// See the LICENSE.txt for the specific language governing permissions and limitations.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.BusAuxiliaries.DownstreamModules.Impl;
using TUGraz.VectoCore.BusAuxiliaries.DownstreamModules.Impl.Electrics;
using TUGraz.VectoCore.BusAuxiliaries.DownstreamModules.Impl.HVAC;
using TUGraz.VectoCore.BusAuxiliaries.DownstreamModules.Impl.Pneumatics;
using TUGraz.VectoCore.BusAuxiliaries.Interfaces;
using TUGraz.VectoCore.BusAuxiliaries.Interfaces.DownstreamModules;
using TUGraz.VectoCore.BusAuxiliaries.Interfaces.DownstreamModules.Electrics;
using TUGraz.VectoCore.BusAuxiliaries.Interfaces.DownstreamModules.PneumaticSystem;
using TUGraz.VectoCore.BusAuxiliaries.Util;

namespace TUGraz.VectoCore.BusAuxiliaries {
	/// <summary>

	/// ''' Main entry point for the advanced auxiliary module. 

	/// ''' This class represents slide number 17 titled Calculations of Cycle FC accounting for Smart Auxiliaries.

	/// ''' </summary>

	/// ''' <remarks></remarks>
	public class AdvancedAuxiliaries : IAdvancedAuxiliaries
	{
		protected internal AuxiliaryConfig auxConfig;

		// Supporting classes which may generate event messages
		private ICompressorMap compressorMap;

		private SSMTOOL ssmTool;
		private SSMTOOL ssmToolModule14;

		private IAlternatorMap alternatorMap;
		public IPneumaticActuationsMAP actuationsMap;
		private IFuelConsumptionMap fuelMap;

		// Classes which compose the model.
		private IM0_NonSmart_AlternatorsSetEfficiency M0;
		private IM0_5_SmartAlternatorSetEfficiency M05;
		private IM1_AverageHVACLoadDemand M1;
		private IM2_AverageElectricalLoadDemand M2;
		private IM3_AveragePneumaticLoadDemand M3;
		private IM4_AirCompressor M4;
		private IM5_SmartAlternatorSetGeneration M5;
		private IM6 M6;
		private IM7 M7;
		private IM8 M8;
		private IM9 M9;
		private IM10 M10;
		private IM11 M11;
		private IM12 M12;
		private IM13 M13;
		private IM14 M14;

		private string vectoDirectory;

		private HVACConstants hvacConstants;

		// Event Handler top level bubble.
		// Public Sub VectoEventHandler(ByRef sender As Object, message As String, messageType As AdvancedAuxiliaryMessageType) _
		// Handles compressorMap.AuxiliaryEvent, alternatorMap.AuxiliaryEvent, ssmTool.Message, ssmToolModule14.Message

		// If Signals.AuxiliaryEventReportingLevel <= messageType Then

		// RaiseEvent AuxiliaryEvent(sender, message, messageType)

		// End If
		// End Sub

		// Constructor
		public AdvancedAuxiliaries()
		{
			VectoInputs = new VectoInputs();
			Signals = new Signals();
		}

	

		// Initialise Model
		public void Initialise(string IAuxPath, string vectoFilePath)
		{
			string auxPath;
			vectoDirectory = FilePathUtils.fPATH(vectoFilePath);

			auxPath = FilePathUtils.ResolveFilePath(vectoDirectory, IAuxPath);

			hvacConstants = new HVACConstants(VectoInputs.FuelDensity);

			Signals.CurrentCycleTimeInSeconds = 0;
			auxConfig = new AuxiliaryConfig(auxPath);

			// Pass some signals from config to Signals. ( These are stored in the configuration but shared in the signal distribution around modules )
			Signals.SmartElectrics = auxConfig.ElectricalUserInputsConfig.SmartElectrical;
			Signals.StoredEnergyEfficiency = auxConfig.ElectricalUserInputsConfig.StoredEnergyEfficiency;
			Signals.SmartPneumatics = auxConfig.PneumaticUserInputsConfig.SmartAirCompression;
			Signals.PneumaticOverrunUtilisation = auxConfig.PneumaticAuxillariesConfig.OverrunUtilisationForCompressionFraction;

			alternatorMap = new CombinedAlternator(FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.ElectricalUserInputsConfig.AlternatorMap), Signals);

			actuationsMap = new PneumaticActuationsMap(FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.PneumaticUserInputsConfig.ActuationsMap));

			compressorMap = new CompressorMap(FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.PneumaticUserInputsConfig.CompressorMap));
			compressorMap.Initialise();

			// fuelMap = New cMAP()
			// fuelMap.FilePath = FilePathUtils.ResolveFilePath(vectoDirectory, VectoInputs.FuelMap)
			// If Not fuelMap.ReadFile() Then
			// MessageBox.Show("Unable to read fuel map, aborting.")
			// Return
			// End If
			// fuelMap.Triangulate()
			fuelMap = VectoInputs.FuelMap;

			auxConfig.ElectricalUserInputsConfig.ElectricalConsumers.DoorDutyCycleFraction = GetDoorActuationTimeFraction();

			// SSM HVAC
			var ssmPath = FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.HvacUserInputsConfig.SSMFilePath);
			var BusDatabase = FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.HvacUserInputsConfig.BusDatabasePath);
			ssmTool = new SSMTOOL(ssmPath, hvacConstants, auxConfig.HvacUserInputsConfig.SSMDisabled);

			// This duplicate SSM is being created for use in M14 as its properties will be dynamically changed at that point
			// to honour EngineWaste Heat Usage in Fueling calculations.
			ssmToolModule14 = new SSMTOOL(ssmPath, hvacConstants, auxConfig.HvacUserInputsConfig.SSMDisabled);


			if ((ssmTool.Load(ssmPath) == false || ssmToolModule14.Load(ssmPath) == false))
				throw new Exception(string.Format("Unable to load the ssmTOOL with file {0}", ssmPath));


			M0 = new M00Impl(auxConfig.ElectricalUserInputsConfig.ElectricalConsumers, alternatorMap, auxConfig.ElectricalUserInputsConfig.PowerNetVoltage.SI<Volt>(), Signals, ssmTool);


			IM0_5_SmartAlternatorSetEfficiency M05tmp = new M0_5Impl(M0, auxConfig.ElectricalUserInputsConfig.ElectricalConsumers, alternatorMap, auxConfig.ElectricalUserInputsConfig.ResultCardIdle, auxConfig.ElectricalUserInputsConfig.ResultCardTraction, auxConfig.ElectricalUserInputsConfig.ResultCardOverrun, Signals);
			M05 = M05tmp;

			M1 = new M01Impl(M0, auxConfig.ElectricalUserInputsConfig.AlternatorGearEfficiency, auxConfig.PneumaticUserInputsConfig.CompressorGearEfficiency, auxConfig.ElectricalUserInputsConfig.PowerNetVoltage.SI<Volt>(), Signals, ssmTool);


			M2 = new M02Impl(auxConfig.ElectricalUserInputsConfig.ElectricalConsumers, M0, auxConfig.ElectricalUserInputsConfig.AlternatorGearEfficiency, auxConfig.ElectricalUserInputsConfig.PowerNetVoltage.SI<Volt>(), Signals);


			M3 = new M03Impl(auxConfig.PneumaticUserInputsConfig, auxConfig.PneumaticAuxillariesConfig, actuationsMap, compressorMap, VectoInputs.VehicleWeightKG, VectoInputs.Cycle, Signals);

			M4 = new M04Impl(compressorMap, auxConfig.PneumaticUserInputsConfig.CompressorGearRatio, auxConfig.PneumaticUserInputsConfig.CompressorGearEfficiency, Signals);
			M5 = new M05Impl(M05tmp, auxConfig.ElectricalUserInputsConfig.PowerNetVoltage.SI<Volt>(), auxConfig.ElectricalUserInputsConfig.AlternatorGearEfficiency);
			M6 = new M06Impl(M1, M2, M3, M4, M5, Signals);
			M7 = new M07Impl(M5, M6, Signals);
			M8 = new M08Impl(M1, M6, M7, Signals);
			M9 = new M09Impl(M1, M4, M6, M8, fuelMap, auxConfig.PneumaticAuxillariesConfig, Signals);
			M10 = new M10Impl(M3, M9, Signals);
			M11 = new M11Impl(M1, M3, M6, M8, fuelMap, Signals);
			M12 = new M12Impl(M10, M11, Signals);
			M13 = new M13Impl(M10, M11, M12, Signals);
			M14 = new M14Impl(M13, ssmToolModule14, hvacConstants, Signals);
		}


		public ISignals Signals { get; set; }
		public IVectoInputs VectoInputs { get; set; }

		public event TUGraz.VectoCore.BusAuxiliaries.Interfaces.AuxiliaryEventEventHandler AuxiliaryEvent;

		public delegate void AuxiliaryEventEventHandler(ref object sender, string message, AdvancedAuxiliaryMessageType messageType);

		//public bool Configure(string filePath, string vectoFilePath)
		//{
		//	try {
		//		frmAuxiliaryConfig frmAuxiliaryConfig = new frmAuxiliaryConfig(filePath, vectoFilePath);

		//		frmAuxiliaryConfig.Show();

		//		if (frmAuxiliaryConfig.DialogResult != DialogResult.OK) {
		//			return true;
		//		}

		//		return false;
		//	} catch (Exception ex) {
		//		return false;
		//	}
		//}

		public bool CycleStep(Second seconds, ref string message)
		{
			try {
				M9.CycleStep(seconds);
				M10.CycleStep(seconds);
				M11.CycleStep(seconds);

				Signals.CurrentCycleTimeInSeconds += seconds.Value();
			} catch (Exception ex) {
				MessageBox.Show("Exception: " + ex.Message + " Stack Trace: " + ex.StackTrace);
				return false;
			}


			return true;
		}

		public bool Running
		{
			get {
				throw new NotImplementedException();
			}
		}

		public bool RunStart(string auxFilePath, string vectoFilePath)
		{
			try {
				Initialise(auxFilePath, vectoFilePath);
			} catch (Exception ex) {
				return false;
			}

			return true;
		}

		public bool RunStop(ref string message)
		{
			throw new NotImplementedException();
		}

		public void ResetCalculations()
		{
			var modules = new List<IAbstractModule>() { M0, M05, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14 };
			foreach (var moduel in modules)
				moduel.ResetCalculations();
		}

		public Kilogram TotalFuelGRAMS
		{
			get {
				if (M13 != null)
					return M14.TotalCycleFCGrams;
				else
					return 0.SI<Kilogram>();
			}
		}

		public Liter TotalFuelLITRES
		{
			get {
				if (M14 != null)
					return M14.TotalCycleFCLitres;
				else
					return 0.SI<Liter>();
			}
		}

		public string AuxiliaryName
		{
			get {
				return "BusAuxiliaries";
			}
		}

		public string AuxiliaryVersion
		{
			get {
				return "Version 1.0 Beta";
			}
		}



		// Helpers
		private double GetDoorActuationTimeFraction()
		{
			var actuationsMap = new PneumaticActuationsMap(FilePathUtils.ResolveFilePath(vectoDirectory, auxConfig.PneumaticUserInputsConfig.ActuationsMap));
			var actuationsKey = new ActuationsKey("Park brake + 2 doors", VectoInputs.Cycle);

			var numActuations = actuationsMap.GetNumActuations(actuationsKey);
			var secondsPerActuation = auxConfig.ElectricalUserInputsConfig.DoorActuationTimeSecond;

			var doorDutyCycleFraction = (numActuations * secondsPerActuation) / (double)Signals.TotalCycleTimeSeconds;

			return doorDutyCycleFraction;
		}

		public bool ValidateAAUXFile(string filePath, ref string message)
		{
			var validResult = FilePathUtils.ValidateFilePath(filePath, ".aaux", ref message);

			return validResult;
		}

		// Diagnostics outputs for testing purposes in Vecto.
		// Eventually this can be removed or rendered non effective to reduce calculation load on the model.
		public double AA_NonSmartAlternatorsEfficiency
		{
			get {
				return M0.AlternatorsEfficiency;
			}
		}

		public Ampere AA_SmartIdleCurrent_Amps
		{
			get {
				return M05.SmartIdleCurrent;
			}
		}

		public double AA_SmartIdleAlternatorsEfficiency
		{
			get {
				return M05.AlternatorsEfficiencyIdleResultCard;
			}
		}

		public Ampere AA_SmartTractionCurrent_Amps
		{
			get {
				return M05.SmartTractionCurrent;
			}
		}

		public double AA_SmartTractionAlternatorEfficiency
		{
			get {
				return M05.AlternatorsEfficiencyTractionOnResultCard;
			}
		}

		public Ampere AA_SmartOverrunCurrent_Amps
		{
			get {
				return M05.SmartOverrunCurrent;
			}
		}

		public double AA_SmartOverrunAlternatorEfficiency
		{
			get {
				return M05.AlternatorsEfficiencyOverrunResultCard;
			}
		}

		public NormLiterPerSecond AA_CompressorFlowRate_LitrePerSec
		{
			get {
				return M4.GetFlowRate();
			}
		}

		public bool AA_OverrunFlag
		{
			get {
				return M6.OverrunFlag;
			}
		}

		public int? AA_EngineIdleFlag
		{
			get {
				return Signals.EngineSpeed <= Signals.EngineIdleSpeed && (!Signals.ClutchEngaged || Signals.InNeutral) ? 1 : 0;
			}
		}

		public bool AA_CompressorFlag
		{
			get {
				return M8.CompressorFlag;
			}
		}

		public Kilogram AA_TotalCycleFC_Grams
		{
			get {
				return M14.TotalCycleFCGrams;
			}
		}

		public Liter AA_TotalCycleFC_Litres
		{
			get {
				return M14.TotalCycleFCLitres;
			}
		}

		public Watt AuxiliaryPowerAtCrankWatts
		{
			get {
				return M8.AuxPowerAtCrankFromElectricalHVACAndPneumaticsAncillaries;
			}
		}

		public Watt AA_AveragePowerDemandCrankHVACMechanicals
		{
			get {
				return M1.AveragePowerDemandAtCrankFromHVACMechanicalsWatts();
			}
		}

		public Watt AA_AveragePowerDemandCrankHVACElectricals
		{
			get {
				return M1.AveragePowerDemandAtCrankFromHVACElectricsWatts();
			}
		}

		public Watt AA_AveragePowerDemandCrankElectrics
		{
			get {
				return M2.GetAveragePowerAtCrankFromElectrics();
			}
		}

		public Watt AA_AveragePowerDemandCrankPneumatics
		{
			get {
				return M3.GetAveragePowerDemandAtCrankFromPneumatics();
			}
		}

		public Kilogram AA_TotalCycleFuelConsumptionCompressorOff
		{
			get {
				return M9.TotalCycleFuelConsumptionCompressorOffContinuously;
			}
		}

		public Kilogram AA_TotalCycleFuelConsumptionCompressorOn
		{
			get {
				return M9.TotalCycleFuelConsumptionCompressorOnContinuously;
			}
		}
	}
}