using AutoMapper; using Edge.Core.Database; using Edge.Core.Database.Models; using Edge.Core.IndustryStandardInterface.Pump; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Wayne.FDCPOSLibrary; namespace EagleStar_Pump { public class PumpHandler : IFdcPumpController, IDisposable { private PumpGroupConfiguration appConfig; private ILogger logger; private IServiceProvider services; private System.Timers.Timer autoCallingTimer; private string owner = "EagleStarPumpApp"; private string type = "YingGaoFlag"; /// /// /// public PumpHandler(PumpGroupConfiguration appConfig, ILogger logger, IServiceProvider services) { this.appConfig = appConfig; this.logger = logger; this.services = services; int fid = 0; var genericDatas = GetGenericData(type); if (genericDatas.Count() > 0) { fid = (int)genericDatas.First().IntProperty0; } else { _ = SaveDbAsync(type, new GenericData() { Type = type, IntProperty0 = fid }); } this.autoCallingTimer = new System.Timers.Timer(3000); this.autoCallingTimer.Elapsed += (_, __) => { this.autoCallingTimer?.Stop(); var dataList = SqlClientHelper.ReadTransactionData(this.appConfig, this.logger, ref fid); foreach (var trx in dataList) { this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(trx)); } _ = UpdateDbAsync(type, new GenericData() { Type = type, IntProperty0 = fid }); this.autoCallingTimer?.Start(); }; this.autoCallingTimer?.Start(); } private IEnumerable GetGenericData(string type) { using (var scope = this.services.CreateScope()) { var objMapper = this.services.GetRequiredService(); var dbContext = scope.ServiceProvider.GetRequiredService(); var genericDatas = dbContext.GenericDatas.Where(gd => gd.Type == type && gd.Owner == owner); return objMapper.Map>(genericDatas.ToList()); } } private async Task SaveDbAsync(string type, GenericData data) { using (var scope = this.services.CreateScope()) { try { var dbContext = scope.ServiceProvider.GetRequiredService(); data.Owner = owner; dbContext.GenericDatas.Add(data); await dbContext.SaveChangesAsync(); } catch (Exception ex) { logger.LogError($"In SaveOrUpdateDbAsync: {ex}"); } } } private async Task UpdateDbAsync(string type, GenericData data) { using (var scope = this.services.CreateScope()) { try { var dbContext = scope.ServiceProvider.GetRequiredService(); var genericDatas = dbContext.GenericDatas.Where(gd => gd.Type == type && gd.Owner == owner); if (genericDatas.Count() > 0) { var gdt = genericDatas.First(); gdt.IntProperty0 = data.IntProperty0; dbContext.GenericDatas.Update(gdt); await dbContext.SaveChangesAsync(); } } catch (Exception ex) { logger.LogError($"In SaveOrUpdateDbAsync: {ex}"); } } } private IEnumerable nozzles = new List(); private bool enableFuelSimulation; private int pumpId; private int pumpPhysicalId; private LogicalDeviceState currentState = LogicalDeviceState.FDC_READY; public string Name => "Bogus_Pump handler"; public int PumpId => this.pumpId; public int PumpPhysicalId => this.pumpPhysicalId; public IEnumerable Nozzles => this.nozzles; public int AmountDecimalDigits => 2; public int VolumeDecimalDigits => 2; public int PriceDecimalDigits => 2; public int VolumeTotalizerDecimalDigits => 2; public event EventHandler OnStateChange; public event EventHandler OnCurrentFuellingStatusChange; public async Task AuthorizeAsync(byte logicalNozzleId) { //if (this.enableFuelSimulation) // return false; if (this.currentState == LogicalDeviceState.FDC_AUTHORISED || this.currentState == LogicalDeviceState.FDC_FUELLING) return false; LogicalNozzle n = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId); if (n == null) return await Task.FromResult(false); await Task.Delay(1000); this.currentState = LogicalDeviceState.FDC_AUTHORISED; this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(this.currentState, n)); await Task.Delay(1000); this.currentState = LogicalDeviceState.FDC_FUELLING; this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(this.currentState, n)); await Task.Delay(300); _ = Task.Run(() => { int amt = 0; int vol = 0; int seqNumber = (int)(DateTime.Now.Subtract(new DateTime(2021, 1, 1)).TotalSeconds); const int FireMaxTimes = 12; int firedTimes = 0; while (true) { amt += new Random().Next(500, 1000); vol += new Random().Next(100, 300); this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction() { Amount = amt, Volumn = vol, Nozzle = n, Price = n.RealPriceOnPhysicalPump ?? -1, SequenceNumberGeneratedOnPhysicalPump = seqNumber, Finished = false })); Thread.Sleep(1000); firedTimes++; if (firedTimes > FireMaxTimes) { this.currentState = LogicalDeviceState.FDC_READY; this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(this.currentState, n)); this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction() { Amount = amt, Volumn = vol, Nozzle = n, Price = n.RealPriceOnPhysicalPump ?? -1, SequenceNumberGeneratedOnPhysicalPump = seqNumber, AmountTotalizer = new Random().Next(9999, 99999999), VolumeTotalizer = new Random().Next(1000, 11999999), Finished = true })); break; } } }); return await Task.FromResult(true); } public Task AuthorizeWithAmountAsync(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId) { return this.AuthorizeAsync(logicalNozzleId); } public Task AuthorizeWithVolumeAsync(int volumnWithoutDecimalPoint, byte logicalNozzleId) { return this.AuthorizeAsync(logicalNozzleId); } public Task ChangeFuelPriceAsync(int newPriceWithoutDecimalPoint, byte logicalNozzleId) { if (this.enableFuelSimulation) return Task.FromResult(false); var targetNozzle = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId); if (targetNozzle != null) { targetNozzle.RealPriceOnPhysicalPump = newPriceWithoutDecimalPoint; targetNozzle.ExpectingPriceOnFcSide = newPriceWithoutDecimalPoint; return Task.FromResult(true); } else return Task.FromResult(false); } public Task FuelingRoundUpByAmountAsync(int amount) { return Task.FromResult(true); } public Task FuelingRoundUpByVolumeAsync(int volume) { return Task.FromResult(true); } public Task LockNozzleAsync(byte logicalNozzleId) { return Task.FromResult(true); } public void OnFdcServerInit(Dictionary parameters) { if (parameters.ContainsKey("LastPriceChange")) { // nozzle logical id:rawPrice var lastPriceChanges = parameters["LastPriceChange"] as Dictionary; foreach (var priceChange in lastPriceChanges) { var targetNozzle = this.nozzles.FirstOrDefault(n => n.LogicalId == priceChange.Key); if (targetNozzle != null) { targetNozzle.RealPriceOnPhysicalPump = priceChange.Value; targetNozzle.ExpectingPriceOnFcSide = priceChange.Value; } } } } public Task QueryStatusAsync() { return Task.FromResult(this.currentState); } public Task> QueryTotalizerAsync(byte logicalNozzleId) { if (this.enableFuelSimulation) Task.FromResult(new Tuple(-1, -1)); return Task.FromResult( new Tuple( new Random().Next(100000, 999999), new Random().Next(50000, 99999))); } public Task ResumeFuellingAsync() { return Task.FromResult(true); } public Task SuspendFuellingAsync() { return Task.FromResult(true); } public Task UnAuthorizeAsync(byte logicalNozzleId) { return Task.FromResult(true); } public Task UnlockNozzleAsync(byte logicalNozzleId) { return Task.FromResult(true); } public void Dispose() { this.autoCallingTimer?.Dispose(); } internal void DrivenPumpStateTo(byte? logicalNozzleId, LogicalDeviceState pumpNewState, int? amountWithoutDecimalPoint, int? volumeWithoutDecimalPoint, int? priceWithoutDecimalPoint) { var targetNozzle = this.nozzles?.FirstOrDefault(n => n.LogicalId == logicalNozzleId); if (pumpNewState == LogicalDeviceState.FDC_FUELLING) { this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction() { Amount = amountWithoutDecimalPoint ?? 0, Volumn = volumeWithoutDecimalPoint ?? 0, Nozzle = targetNozzle, Price = priceWithoutDecimalPoint ?? 0, //SequenceNumberGeneratedOnPhysicalPump = seqNumber, Finished = false })); } if (this.currentState == pumpNewState) return; this.currentState = pumpNewState; this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(this.currentState, targetNozzle)); } internal void DrivenPumpRaiseNewTrx(byte? logicalNozzleId, int amountWithoutDecimalPoint, int volumeWithoutDecimalPoint, int priceWithoutDecimalPoint, int trxSeqNumber) { var targetNozzle = this.nozzles?.FirstOrDefault(n => n.LogicalId == logicalNozzleId); this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction() { Amount = amountWithoutDecimalPoint, Volumn = volumeWithoutDecimalPoint, Nozzle = targetNozzle, Price = priceWithoutDecimalPoint, SequenceNumberGeneratedOnPhysicalPump = trxSeqNumber, Finished = true })); } } }