using System; using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HC_APTBS.Models; using HC_APTBS.Services; using HC_APTBS.ViewModels.Dialogs; using HC_APTBS.Views.Dialogs; namespace HC_APTBS.ViewModels { /// /// ViewModel for manual bench controls: direction toggle, RPM start/stop with /// PID ramp, oil pump toggle, and turn downcounter. /// Created by as a child ViewModel. /// public sealed partial class BenchControlViewModel : ObservableObject { private readonly IBenchService _bench; private readonly IConfigurationService _config; // ── Direction ───────────────────────────────────────────────────────────── /// True when the bench rotates clockwise (right). False for counter-clockwise (left). [ObservableProperty] private bool _isDirectionRight = true; // ── Oil pump ────────────────────────────────────────────────────────────── /// True when the oil pump relay is energised. [ObservableProperty] private bool _isOilPumpOn; // ── RPM control ─────────────────────────────────────────────────────────── /// True when the bench motor is running (last RPM command > 0). [ObservableProperty] private bool _isBenchRunning; /// Controls the RPM quick-select popup visibility. [ObservableProperty] private bool _isRpmPopupOpen; /// Text in the RPM input field. [ObservableProperty] private string _rpmInputText = string.Empty; /// Last RPM setpoint commanded via PID or direct set. [ObservableProperty] private double _targetRpm; /// Last voltage sent to the motor CAN parameter. [ObservableProperty] private double _commandVoltage; // ── Counter ─────────────────────────────────────────────────────────────── /// Controls the counter popup visibility. [ObservableProperty] private bool _isCounterPopupOpen; /// Text in the counter input field. [ObservableProperty] private string _counterInputText = string.Empty; /// Live counter count-down value read from CAN. [ObservableProperty] private double _benchCounterValue; // ── Constructor ─────────────────────────────────────────────────────────── /// /// Creates the bench control ViewModel and subscribes to service events. /// /// Bench service for RPM, relay, and parameter operations. /// Configuration service for bench parameters. public BenchControlViewModel(IBenchService benchService, IConfigurationService configService) { _bench = benchService; _config = configService; _bench.RpmCommandSent += () => Application.Current.Dispatcher.Invoke(() => { TargetRpm = _bench.LastTargetRpm; CommandVoltage = _bench.LastCommandVoltage; }); } // ── Direction toggle ────────────────────────────────────────────────────── partial void OnIsDirectionRightChanged(bool value) { _bench.SetRelay(RelayNames.DirectionRight, value); _bench.SetRelay(RelayNames.DirectionLeft, !value); } // ── Oil pump toggle ─────────────────────────────────────────────────────── partial void OnIsOilPumpOnChanged(bool value) { // Show confirmation dialog when turning oil pump ON (WAcceptOilTurnOn equivalent). if (value) { var vm = new OilPumpConfirmViewModel(); var dlg = new OilPumpConfirmDialog(vm) { Owner = Application.Current.MainWindow }; dlg.ShowDialog(); if (!vm.Accepted) { // Revert without re-triggering this handler. _isOilPumpOn = false; OnPropertyChanged(nameof(IsOilPumpOn)); return; } } _bench.SetRelay(RelayNames.OilPump, value); } // ── RPM commands ────────────────────────────────────────────────────────── /// Opens the RPM quick-select popup. [RelayCommand] private void OpenRpmPopup() { IsRpmPopupOpen = true; } /// /// Starts the bench motor at the RPM specified in . /// Shows a safety warning dialog if the oil pump is off. /// [RelayCommand] private void StartBench() { if (!int.TryParse(RpmInputText, out int rpm) || rpm <= 0) return; // Safety warning if oil pump is not running (WCareOnRpmOn equivalent). if (!IsOilPumpOn) { var vm = new RpmSafetyWarningViewModel(); var dlg = new RpmSafetyWarningDialog(vm) { Owner = Application.Current.MainWindow }; dlg.ShowDialog(); switch (vm.Result) { case RpmSafetyResult.Cancel: return; case RpmSafetyResult.ProceedWithOil: IsOilPumpOn = true; break; case RpmSafetyResult.ProceedWithoutOil: // Operator accepted the risk. break; } } // Ensure direction relays are set. _bench.SetRelay(RelayNames.DirectionRight, IsDirectionRight); _bench.SetRelay(RelayNames.DirectionLeft, !IsDirectionRight); _bench.StartRpmPid(rpm); IsBenchRunning = true; IsRpmPopupOpen = false; } /// /// Stops the bench motor via PID stop and clears direction relays. /// [RelayCommand] private void StopBench() { _bench.StopRpmPid(); _bench.SetRelay(RelayNames.DirectionLeft, false); _bench.SetRelay(RelayNames.DirectionRight, false); IsBenchRunning = false; } /// /// Quick-select button handler: sets the RPM input and starts the bench. /// /// RPM value as a string from the button content. [RelayCommand] private void SetQuickRpm(string rpmString) { RpmInputText = rpmString; StartBench(); } // ── Counter commands ────────────────────────────────────────────────────── /// Toggles the counter popup visibility. [RelayCommand] private void ToggleCounterPopup() { IsCounterPopupOpen = !IsCounterPopupOpen; } /// /// Sends the counter value over CAN and activates the counter relay. /// [RelayCommand] private void SendCounter() { if (!int.TryParse(CounterInputText, out int count) || count <= 0) return; // Set the counter parameter value and transmit. _bench.SetParameter(BenchParameterNames.Counter, count); if (_config.Bench.ParametersByName.TryGetValue( BenchParameterNames.Counter, out var counterParam)) { _bench.SendParameters(counterParam.MessageId); } // Activate the counter relay. _bench.SetRelay(RelayNames.Counter, true); } // ── Refresh (called from MainViewModel timer tick) ──────────────────────── /// /// Updates live counter readback from CAN. /// Called on the UI thread from . /// public void RefreshFromTick() { BenchCounterValue = _bench.ReadBenchParameter(BenchParameterNames.BenchCounter); } } }