/// <summary>
        /// Replaces the generic node with a node specific to the model.
        /// </summary>
        protected override NodeState AddBehaviourToPredefinedNode(ISystemContext context, NodeState predefinedNode)
        {
            BaseObjectState passiveNode = predefinedNode as BaseObjectState;

            if (passiveNode == null)
            {
                return(predefinedNode);
            }

            NodeId typeId = passiveNode.TypeDefinitionId;

            if (!IsNodeIdInNamespace(typeId) || typeId.IdType != IdType.Numeric)
            {
                return(predefinedNode);
            }

            switch ((uint)typeId.Identifier)
            {
            case ObjectTypes.BoilerType:
            {
                if (passiveNode is BoilerState)
                {
                    break;
                }

                BoilerState activeNode = new BoilerState(passiveNode.Parent);
                activeNode.Create(context, passiveNode);

                // replace the node in the parent.
                if (passiveNode.Parent != null)
                {
                    passiveNode.Parent.ReplaceChild(context, activeNode);
                }

                // Autostart boiler simulation state machine
                MethodState start = (MethodState)activeNode.Simulation.FindChild(context, Opc.Ua.BrowseNames.Start);

                if (start != null)
                {
                    IList <Variant>      inputArguments  = new List <Variant>();
                    IList <Variant>      outputArguments = new List <Variant>();
                    List <ServiceResult> errors          = new List <ServiceResult>();
                    start.Call(context, activeNode.NodeId, inputArguments, errors, outputArguments);
                }

                return(activeNode);
            }
            }

            return(predefinedNode);
        }
        /// <summary>
        /// Creates a boiler and adds it to the address space.
        /// </summary>
        /// <param name="context">The context to use.</param>
        /// <param name="unitNumber">The unit number for the boiler.</param>
        private void CreateBoiler(SystemContext context, int unitNumber)
        {
            BoilerState boiler = new BoilerState(null);

            string name = Utils.Format("Boiler #{0}", unitNumber);

            boiler.Create(
                context,
                null,
                new QualifiedName(name, m_namespaceIndex),
                null,
                true);

            NodeState folder = (NodeState)FindPredefinedNode(
                ExpandedNodeId.ToNodeId(ObjectIds.Boilers, Server.NamespaceUris),
                typeof(NodeState));

            folder.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, false, boiler.NodeId);
            boiler.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, true, folder.NodeId);

            string unitLabel = Utils.Format("{0}0", unitNumber);

            UpdateDisplayName(boiler.InputPipe, unitLabel);
            UpdateDisplayName(boiler.Drum, unitLabel);
            UpdateDisplayName(boiler.OutputPipe, unitLabel);
            UpdateDisplayName(boiler.LevelController, unitLabel);
            UpdateDisplayName(boiler.FlowController, unitLabel);
            UpdateDisplayName(boiler.CustomController, unitLabel);

            m_boilers.Add(boiler);

            AddPredefinedNode(context, boiler);

            // Autostart boiler simulation state machine
            MethodState start = (MethodState)boiler.Simulation.FindChild(context, Opc.Ua.BrowseNames.Start);

            if (start != null)
            {
                IList <Variant>      inputArguments  = new List <Variant>();
                IList <Variant>      outputArguments = new List <Variant>();
                List <ServiceResult> errors          = new List <ServiceResult>();
                start.Call(context, boiler.NodeId, inputArguments, errors, outputArguments);
            }
        }
        /// <summary>
        /// Calls a method on an object.
        /// </summary>
        protected virtual ServiceResult Call(
            ISystemContext context,
            CallMethodRequest methodToCall,
            NodeState source,
            MethodState method,
            CallMethodResult result)
        {
            ServerSystemContext systemContext = context as ServerSystemContext;
            List<ServiceResult> argumentErrors = new List<ServiceResult>();
            VariantCollection outputArguments = new VariantCollection();

            ServiceResult error = method.Call(
                context,
                source.NodeId,
                methodToCall.InputArguments,
                argumentErrors,
                outputArguments);

            if (ServiceResult.IsBad(error))
            {
                return error;
            }

            // check for argument errors.
            bool argumentsValid = true;

            for (int jj = 0; jj < argumentErrors.Count; jj++)
            {
                ServiceResult argumentError = argumentErrors[jj];

                if (argumentError != null)
                {
                    result.InputArgumentResults.Add(argumentError.StatusCode);
                                  
                    if (ServiceResult.IsBad(argumentError))
                    {
                        argumentsValid = false;
                    }
                }
                else
                {
                    result.InputArgumentResults.Add(StatusCodes.Good);
                }

                // only fill in diagnostic info if it is requested.
                if ((systemContext.OperationContext.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                {
                    if (ServiceResult.IsBad(argumentError))
                    {
                        argumentsValid = false;
                        result.InputArgumentDiagnosticInfos.Add(new DiagnosticInfo(argumentError, systemContext.OperationContext.DiagnosticsMask, false, systemContext.OperationContext.StringTable));
                    }
                    else
                    {
                        result.InputArgumentDiagnosticInfos.Add(null);
                    }
                }
            }

            // check for validation errors.
            if (!argumentsValid)
            {
                result.StatusCode = StatusCodes.BadInvalidArgument;
                return result.StatusCode;
            }

            // do not return diagnostics if there are no errors.
            result.InputArgumentDiagnosticInfos.Clear();

            // return output arguments.
            result.OutputArguments = outputArguments;

            return ServiceResult.Good;
        }