/* ========================================================================
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System;
namespace Opc.Ua.Server.Fluent
{
///
/// Strongly-typed fluent builder for a
/// instance. Returned by
/// .
///
///
///
/// The builder is a configurator over an existing
/// subclass — typically one
/// emitted by the source generator (e.g.
/// InstallationStateMachineState) or a stack-shipped
/// subclass (,
/// ,
/// ). It does NOT
/// attempt to build the state/transition/cause tables at runtime;
/// those remain compiled into the subclass.
///
///
/// Identifiers exchanged with the builder are internal numeric
/// state IDs / transition IDs / cause IDs (e.g.
/// Objects.ProgramStateMachineType_Ready), NOT the OPC UA
/// Number field on the state variable. Use the
/// StateIds / TransitionIds / MethodIds
/// generated by the source generator wherever possible.
///
///
/// All callbacks are composed with any pre-existing handler
/// on the underlying state machine: pre-wired
/// /
/// handlers
/// run alongside the builder's coordinator, so stack default
/// behaviour is preserved.
///
///
///
/// Concrete state-machine type. Must derive from
/// .
///
public interface IStateMachineBuilder
where TState : FiniteStateMachineState
{
///
/// The configured state machine.
///
TState StateMachine { get; }
///
/// The owning node builder, for chain termination via
/// .
///
INodeBuilder Builder { get; }
///
/// Forces the machine into the specified state via
/// . Intended
/// for setting the initial state during configuration; does
/// NOT fire transition callbacks (matches stack semantics for
/// SetState).
///
///
/// The internal state ID (e.g.
/// Objects.ProgramStateMachineType_Ready).
///
IStateMachineBuilder WithInitialState(uint stateId);
///
/// Runs after the machine transitions into the specified
/// state. Fired by the composed
///
/// coordinator after the stack has updated
/// .
///
/// The destination state ID.
/// Callback invoked once per matching
/// transition.
IStateMachineBuilder OnEnterState(
uint stateId,
Action handler);
///
/// Runs when the machine transitions out of the specified
/// state. Fired by the composed coordinator using the
/// from state captured in
/// .
///
IStateMachineBuilder OnExitState(
uint stateId,
Action handler);
///
/// Runs for every successful transition. Receives the
/// fromStateId (captured pre-transition) and
/// toStateId (the new ).
///
IStateMachineBuilder OnTransition(
Action handler);
///
/// Installs a pre-transition guard. Return a non-Good
/// to cancel the transition. The
/// guard is composed with any existing
///
/// handler (existing first, then fluent guards in registration
/// order; first bad result wins).
///
///
/// Guards receive the fromStateId (the machine's
/// current state before the transition); the destination state
/// is computed by the stack from internal
/// TransitionMappings and is not exposed to guards in
/// this MVP. Read StateMachine.CurrentState.Id.Value for
/// the same information from inside the guard if needed.
///
IStateMachineBuilder OnBeforeTransition(
Func guard);
///
/// Wires the supplied method node so calling it invokes
/// with the
/// supplied cause ID. The cause-to-transition lookup happens
/// inside the stack via the subclass's
/// CauseMappings.
///
///
/// NodeId of the method that triggers the cause.
///
///
/// The internal cause ID (e.g.
/// Methods.ProgramStateMachineType_Start).
///
IStateMachineBuilder WithCause(NodeId methodNodeId, uint causeId);
///
/// Auto-fires for
/// when the machine has been in
/// for at least
/// . Uses the owning manager's
/// simulation registry — the manager must derive from
/// .
///
///
/// State the machine must be in for the timer to be armed.
///
///
/// Duration the machine must remain in
/// before the cause fires. Must
/// be positive.
///
///
/// Cause ID passed to
/// when the timeout elapses.
///
///
/// Thrown when the owning manager does not derive from
/// .
///
IStateMachineBuilder WithTimedTransition(
uint fromStateId,
TimeSpan timeout,
uint causeId);
///
/// Escape hatch: directly mutate the underlying state machine
/// for properties not covered by the narrow MVP surface (e.g.
/// ,
/// ).
///
IStateMachineBuilder ConfigureStateMachine(Action configure);
}
}