using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Timers; using PepperDash.Core; namespace PepperDash.Essentials.Core; /// /// An incrementer that can use the values of some other object/primitive value to do its thing. /// It uses an Action to set the value and a Func to get the value from whatever this is /// attached to. /// public class ActionIncrementer { /// /// The amount to change the value by each increment /// public int ChangeAmount { get; set; } /// /// The maximum value the incrementer can reach /// public int MaxValue { get; set; } /// /// The minimum value the incrementer can reach /// public int MinValue { get; set; } /// /// The delay before the incrementer starts repeating /// public uint RepeatDelay { get; set; } /// /// The time interval between each repeat /// public uint RepeatTime { get; set; } Action SetAction; Func GetFunc; Timer Timer; /// /// /// /// /// /// /// /// /// Action that will be called when this needs to set the destination value /// Func that is called to get the current value public ActionIncrementer(int changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime, Action setAction, Func getFunc) { SetAction = setAction; GetFunc = getFunc; ChangeAmount = changeAmount; MaxValue = maxValue; MinValue = minValue; RepeatDelay = repeatDelay; RepeatTime = repeatTime; } /// /// Starts incrementing cycle /// public void StartUp() { if (Timer != null) return; Go(ChangeAmount); } /// /// Starts decrementing cycle /// public void StartDown() { if (Timer != null) return; Go(-ChangeAmount); } /// /// Stops the repeat /// public void Stop() { if (Timer != null) Timer.Stop(); Timer = null; } /// /// Helper that does the work of setting new level, and starting repeat loop, checking against bounds first. /// /// void Go(int change) { int currentLevel = GetFunc(); // Fire once then pause int newLevel = currentLevel + change; bool atLimit = CheckLevel(newLevel, out newLevel); SetAction(newLevel); if (atLimit) // Don't go past end Stop(); else if (Timer == null) // Only enter the timer if it's not already running { Timer = new Timer(RepeatDelay) { AutoReset = false }; Timer.Elapsed += (s, e) => { Go(change); if (Timer != null) { Timer.Interval = RepeatTime; Timer.AutoReset = true; Timer.Start(); } }; Timer.Start(); } } /// /// Helper to check a new level against min/max. Returns revised level if new level /// will go out of bounds /// /// The level to check against bounds /// Revised level if bounds are exceeded. Min or max /// true if new level is at or past bounds bool CheckLevel(int levelIn, out int levelOut) { bool isAtLimit = false; if (levelIn > MaxValue) { levelOut = MaxValue; isAtLimit = true; } else if (levelIn < MinValue) { levelOut = MinValue; isAtLimit = true; } else levelOut = levelIn; return isAtLimit; } }