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;
}
}