/* ======================================================================== * 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); } }