using BoFilTest.Domain.Modules.Balance;
using BoFilTest.Utils;
using System;
using Unity;

namespace BoFilTest.Domain.Modules
{
    class HardwareFactory
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        private readonly IUnityContainer scopedContainer;
        private readonly Configuration config;

        public HardwareFactory(IUnityContainer scopedContainer, Configuration config)
        {
            this.scopedContainer = scopedContainer;
            this.config = config;
        }

        public IBalance CreateBalance()
        {
            try
            {
                return CreateBalanceFor(config.Balance().Mode().ToLower());
            }
            catch (Exception e)
            {
                logger.Error(Translated.NotYet("Unable to create balance: {0}", e.Message));
                return new NoBalance();
            }
        }

        public IGasFlowMeasure CreateGasFlowMeasure()
        {
            try
            {
                return CreateGasFlowMeasureFor(config.GasFlowMeasure().Mode().ToLower());
            }
            catch (Exception e)
            {
                logger.Error(Translated.NotYet("Unable to create gas flow measure: {0}", e.Message));
                return new NoGasFlowMeasure();
            }
        }

        public IPressureMeasure CreatePressureMeasure()
        {
            try
            {
                return CreatePressureMeasureFor(config.PressureMeasure().Mode().ToLower());
            }
            catch (Exception e)
            {
                logger.Error(Translated.NotYet("Unable to create pressure measure: {0}", e.Message));
                return new NoPressureMeasure();
            }
        }

        public IExtraMeasure CreateExtraMeasure()
        {
            try
            {
                return CreateConfiguredUnitMeasureFor(config.ExtraMeasure().Mode().ToLower());
            }
            catch (Exception e)
            {
                logger.Error(Translated.NotYet("Unable to create configured unit measure: {0}", e.Message));
                return new NoExtraMeasure();
            }
        }

        private IPressureMeasure CreatePressureMeasureFor(string mode)
        {
            switch (mode)
            {
                case ModuleMode.EMULATED: return new EmulatedPressureMeasure();
                case ModuleMode.REAL: return new VoegtlinPressureMeasure(GetOrCreateVoegtlinDevice());
                case ModuleMode.LEGACY: return new YoctopucePressureMeasure(this.config.PressureMeasure().DeviceName());
                case ModuleMode.NONE: return new NoPressureMeasure();

            }
            throw new HardwareException(mode + " is not a valid mode for the pressure measure. Check the configuration file.");
        }

        private IBalance CreateBalanceFor(string mode)
        {
            switch (mode)
            {
                case ModuleMode.EMULATED: return new EmulatedBalance();
                case ModuleMode.REAL: return new SerialMettlerToledoBalance(this.config.Balance());
                case ModuleMode.SARTORIUS: return new SartoriusBalance(this.config.Balance());
                case ModuleMode.NONE: return new NoBalance();
            }
            throw new HardwareException(mode + " is not a valid mode for the balance. Check the configuration file.");
        }

        private IGasFlowMeasure CreateGasFlowMeasureFor(string mode)
        {
            switch (mode)
            {
                case ModuleMode.EMULATED: return new EmulatedGasFlowMeasure();
                case ModuleMode.LEGACY: return new MKSOverModbusGasFlowMeasure(this.config.GasFlowMeasure().ModbusHost());
                case ModuleMode.REAL: return new VoegtlinGasFlowMeasure(GetOrCreateVoegtlinDevice());
                case ModuleMode.NONE: return new NoGasFlowMeasure();
            }
            throw new HardwareException(mode + " is not a valid mode for the gas flow measure. Check the configuration file.");
        }

        private IExtraMeasure CreateConfiguredUnitMeasureFor(string mode)
        {
            switch (mode)
            {
                case ModuleMode.EMULATED: return new EmulatedExtraMeasure();
                case ModuleMode.REAL: return new YoctupuceExtraMeasure(this.config.ExtraMeasure().DeviceName());
                case ModuleMode.NONE: return new NoExtraMeasure();
            }
            throw new HardwareException(mode + " is not a valid mode for the extra measure. Check the configuration file.");
        }

        private VoegtlinDevice GetOrCreateVoegtlinDevice()
        {
            return scopedContainer.Resolve<VoegtlinDevice>();
        }
    }
}
