using System;
using System.Collections;
using System.Collections.Generic;
using Opc.Ua;
using Opc.Ua.Client;


namespace IMCS_CCS.Utils.DeviceProtocol
{
    public class FilterDefinition
    {
        public NodeId AreaId;
        public EventSeverity Severity;
        public IList<NodeId> EventTypes;
        public bool IgnoreSuppressedOrShelved;
        public SimpleAttributeOperandCollection SelectClauses;

        public MonitoredItem CreateMonitoredItem(Session session)
        {
            if (this.AreaId == (object)null)
                this.AreaId = ObjectIds.Server;
            return new MonitoredItem()
            {
                DisplayName = (string)null,
                StartNodeId = this.AreaId,
                RelativePath = (string)null,
                NodeClass = NodeClass.Object,
                AttributeId = 12,
                IndexRange = (string)null,
                Encoding = (QualifiedName)null,
                MonitoringMode = MonitoringMode.Reporting,
                SamplingInterval = 0,
                QueueSize = uint.MaxValue,
                DiscardOldest = true,
                Filter = (MonitoringFilter)this.ConstructFilter(session),
                Handle = (object)this
            };
        }

        public SimpleAttributeOperandCollection ConstructSelectClauses(
          Session session,
          params NodeId[] eventTypeIds)
        {
            SimpleAttributeOperandCollection eventFields = new SimpleAttributeOperandCollection();
            eventFields.Add(new SimpleAttributeOperand()
            {
                TypeDefinitionId = ObjectTypeIds.BaseEventType,
                AttributeId = 1U,
                BrowsePath = new QualifiedNameCollection()
            });
            if (eventTypeIds != null)
            {
                for (int index = 0; index < eventTypeIds.Length; ++index)
                    this.CollectFields(session, eventTypeIds[index], eventFields);
            }
            else
                this.CollectFields(session, ObjectTypeIds.BaseEventType, eventFields);
            return eventFields;
        }

        public EventFilter ConstructFilter(Session session)
        {
            EventFilter eventFilter = new EventFilter();
            eventFilter.SelectClauses = this.SelectClauses;
            ContentFilter contentFilter = new ContentFilter();
            ContentFilterElement contentFilterElement1 = (ContentFilterElement)null;
            if (this.Severity > EventSeverity.Min)
            {
                SimpleAttributeOperand attributeOperand = new SimpleAttributeOperand();
                attributeOperand.TypeDefinitionId = ObjectTypeIds.BaseEventType;
                attributeOperand.BrowsePath.Add((QualifiedName)"Severity");
                attributeOperand.AttributeId = 13U;
                contentFilterElement1 = contentFilter.Push(FilterOperator.GreaterThanOrEqual, (object)attributeOperand, (object)new LiteralOperand()
                {
                    Value = new Variant((ushort)this.Severity)
                });
            }
            if (!this.IgnoreSuppressedOrShelved)
            {
                SimpleAttributeOperand attributeOperand = new SimpleAttributeOperand();
                attributeOperand.TypeDefinitionId = ObjectTypeIds.BaseEventType;
                attributeOperand.BrowsePath.Add((QualifiedName)"SuppressedOrShelved");
                attributeOperand.AttributeId = 13U;
                ContentFilterElement contentFilterElement2 = contentFilter.Push(FilterOperator.Equals, (object)attributeOperand, (object)new LiteralOperand()
                {
                    Value = new Variant(false)
                });
                if (contentFilterElement1 != null)
                    contentFilterElement1 = contentFilter.Push(FilterOperator.And, (object)contentFilterElement1, (object)contentFilterElement2);
                else
                    contentFilterElement1 = contentFilterElement2;
            }
            if (this.EventTypes != null && this.EventTypes.Count > 0)
            {
                ContentFilterElement contentFilterElement2 = (ContentFilterElement)null;
                for (int index = 0; index < this.EventTypes.Count; ++index)
                {
                    ContentFilterElement contentFilterElement3 = contentFilter.Push(FilterOperator.OfType, (object)new LiteralOperand()
                    {
                        Value = new Variant(this.EventTypes[index])
                    });
                    if (contentFilterElement2 != null)
                        contentFilterElement2 = contentFilter.Push(FilterOperator.Or, (object)contentFilterElement2, (object)contentFilterElement3);
                    else
                        contentFilterElement2 = contentFilterElement3;
                }
                if (contentFilterElement1 != null)
                    contentFilter.Push(FilterOperator.And, (object)contentFilterElement1, (object)contentFilterElement2);
            }
            eventFilter.WhereClause = contentFilter;
            return eventFilter;
        }

        private void CollectFields(
          Session session,
          NodeId eventTypeId,
          SimpleAttributeOperandCollection eventFields)
        {
            ReferenceDescriptionCollection descriptionCollection = FormUtils.BrowseSuperTypes(session, eventTypeId, false);
            if (descriptionCollection == null)
                return;
            Dictionary<NodeId, QualifiedNameCollection> foundNodes = new Dictionary<NodeId, QualifiedNameCollection>();
            QualifiedNameCollection parentPath = new QualifiedNameCollection();
            for (int index = descriptionCollection.Count - 1; index >= 0; --index)
                this.CollectFields(session, (NodeId)descriptionCollection[index].NodeId, parentPath, eventFields, foundNodes);
            this.CollectFields(session, eventTypeId, parentPath, eventFields, foundNodes);
        }

        private void CollectFields(
          Session session,
          NodeId nodeId,
          QualifiedNameCollection parentPath,
          SimpleAttributeOperandCollection eventFields,
          Dictionary<NodeId, QualifiedNameCollection> foundNodes)
        {
            ReferenceDescriptionCollection descriptionCollection = FormUtils.Browse(session, new BrowseDescription()
            {
                NodeId = nodeId,
                BrowseDirection = BrowseDirection.Forward,
                ReferenceTypeId = ReferenceTypeIds.Aggregates,
                IncludeSubtypes = true,
                NodeClassMask = 3U,
                ResultMask = 63U
            }, false);
            if (descriptionCollection == null)
                return;
            for (int index = 0; index < descriptionCollection.Count; ++index)
            {
                ReferenceDescription referenceDescription = descriptionCollection[index];
                if (!referenceDescription.NodeId.IsAbsolute)
                {
                    QualifiedNameCollection qualifiedNameCollection = new QualifiedNameCollection((IEnumerable<QualifiedName>)parentPath);
                    qualifiedNameCollection.Add(referenceDescription.BrowseName);
                    if (!this.ContainsPath(eventFields, qualifiedNameCollection))
                        eventFields.Add(new SimpleAttributeOperand()
                        {
                            TypeDefinitionId = ObjectTypeIds.BaseEventType,
                            BrowsePath = qualifiedNameCollection,
                            AttributeId = referenceDescription.NodeClass == NodeClass.Variable ? 13U : 1U
                        });
                    NodeId nodeId1 = (NodeId)referenceDescription.NodeId;
                    if (!foundNodes.ContainsKey(nodeId1))
                    {
                        foundNodes.Add(nodeId1, qualifiedNameCollection);
                        this.CollectFields(session, (NodeId)referenceDescription.NodeId, qualifiedNameCollection, eventFields, foundNodes);
                    }
                }
            }
        }

        private bool ContainsPath(
          SimpleAttributeOperandCollection selectClause,
          QualifiedNameCollection browsePath)
        {
            for (int index1 = 0; index1 < selectClause.Count; ++index1)
            {
                SimpleAttributeOperand attributeOperand = selectClause[index1];
                if (attributeOperand.BrowsePath.Count == browsePath.Count)
                {
                    bool flag = true;
                    for (int index2 = 0; index2 < attributeOperand.BrowsePath.Count; ++index2)
                    {
                        if (attributeOperand.BrowsePath[index2] != browsePath[index2])
                        {
                            flag = false;
                            break;
                        }
                    }
                    if (flag)
                        return true;
                }
            }
            return false;
        }
    }


    public static class FormUtils
    {
        public static NodeId[] KnownEventTypes = new NodeId[8]
        {
      ObjectTypeIds.BaseEventType,
      ObjectTypeIds.ConditionType,
      ObjectTypeIds.DialogConditionType,
      ObjectTypeIds.AlarmConditionType,
      ObjectTypeIds.ExclusiveLimitAlarmType,
      ObjectTypeIds.NonExclusiveLimitAlarmType,
      ObjectTypeIds.AuditEventType,
      ObjectTypeIds.AuditUpdateMethodEventType
        };

        public static EndpointDescription SelectEndpoint(
          string discoveryUrl,
          bool useSecurity)
        {
            if (!discoveryUrl.StartsWith("opc.tcp") && !discoveryUrl.EndsWith("/discovery"))
                discoveryUrl += "/discovery";
            Uri discoveryUrl1 = new Uri(discoveryUrl);
            EndpointConfiguration configuration = EndpointConfiguration.Create();
            configuration.OperationTimeout = 5000;
            EndpointDescription endpointDescription1 = (EndpointDescription)null;
            using (DiscoveryClient discoveryClient = DiscoveryClient.Create(discoveryUrl1, configuration))
            {
                EndpointDescriptionCollection endpoints = discoveryClient.GetEndpoints((StringCollection)null);
                for (int index = 0; index < endpoints.Count; ++index)
                {
                    EndpointDescription endpointDescription2 = endpoints[index];
                    if (endpointDescription2.EndpointUrl.StartsWith(discoveryUrl1.Scheme))
                    {
                        if (endpointDescription1 == null)
                            endpointDescription1 = endpointDescription2;
                        if (useSecurity)
                        {
                            if (endpointDescription2.SecurityMode != MessageSecurityMode.None && (int)endpointDescription2.SecurityLevel > (int)endpointDescription1.SecurityLevel)
                                endpointDescription1 = endpointDescription2;
                        }
                        else if (endpointDescription2.SecurityMode == MessageSecurityMode.None)
                            endpointDescription1 = endpointDescription2;
                    }
                    if (endpointDescription1 == null && endpoints.Count > 0)
                        endpointDescription1 = endpoints[0];
                }
            }
            Uri uri = Opc.Ua.Utils.ParseUri(endpointDescription1.EndpointUrl);
            if (uri != (Uri)null && uri.Scheme == discoveryUrl1.Scheme)
                endpointDescription1.EndpointUrl = new UriBuilder(uri)
                {
                    Host = discoveryUrl1.DnsSafeHost,
                    Port = discoveryUrl1.Port
                }.ToString();
            return endpointDescription1;
        }

        public static NodeId FindEventType(
          MonitoredItem monitoredItem,
          EventFieldList notification)
        {
            EventFilter filter = monitoredItem.Status.Filter as EventFilter;
            if (filter != null)
            {
                for (int index = 0; index < filter.SelectClauses.Count; ++index)
                {
                    SimpleAttributeOperand selectClause = filter.SelectClauses[index];
                    if (selectClause.BrowsePath.Count == 1 && selectClause.BrowsePath[0] == (QualifiedName)"EventType")
                        return notification.EventFields[index].Value as NodeId;
                }
            }
            return (NodeId)null;
        }

        public static BaseEventState ConstructEvent(
          Session session,
          MonitoredItem monitoredItem,
          EventFieldList notification,
          Dictionary<NodeId, NodeId> eventTypeMappings)
        {
            NodeId eventType = FormUtils.FindEventType(monitoredItem, notification);
            if (eventType == (object)null)
                return (BaseEventState)null;
            NodeId nodeId = (NodeId)null;
            if (!eventTypeMappings.TryGetValue(eventType, out nodeId))
            {
                for (int index = 0; index < FormUtils.KnownEventTypes.Length; ++index)
                {
                    if (FormUtils.KnownEventTypes[index] == (object)eventType)
                    {
                        nodeId = eventType;
                        eventTypeMappings.Add(eventType, eventType);
                        break;
                    }
                }
                if (nodeId == (object)null)
                {
                    ReferenceDescriptionCollection descriptionCollection = FormUtils.BrowseSuperTypes(session, eventType, false);
                    if (descriptionCollection == null)
                        return (BaseEventState)null;
                    for (int index1 = 0; index1 < descriptionCollection.Count; ++index1)
                    {
                        for (int index2 = 0; index2 < FormUtils.KnownEventTypes.Length; ++index2)
                        {
                            if (FormUtils.KnownEventTypes[index2] == (object)descriptionCollection[index1].NodeId)
                            {
                                nodeId = FormUtils.KnownEventTypes[index2];
                                eventTypeMappings.Add(eventType, nodeId);
                                break;
                            }
                        }
                        if (nodeId != (object)null)
                            break;
                    }
                }
            }
            if (nodeId == (object)null)
                return (BaseEventState)null;
            uint? identifier = nodeId.Identifier as uint?;
            if (!identifier.HasValue)
                return (BaseEventState)null;
            BaseEventState baseEventState;
            switch (identifier.Value)
            {
                case 2052:
                    baseEventState = (BaseEventState)new AuditEventState((NodeState)null);
                    break;
                case 2127:
                    baseEventState = (BaseEventState)new AuditUpdateMethodEventState((NodeState)null);
                    break;
                case 2782:
                    baseEventState = (BaseEventState)new ConditionState((NodeState)null);
                    break;
                case 2830:
                    baseEventState = (BaseEventState)new DialogConditionState((NodeState)null);
                    break;
                case 2915:
                    baseEventState = (BaseEventState)new AlarmConditionState((NodeState)null);
                    break;
                case 9341:
                    baseEventState = (BaseEventState)new ExclusiveLimitAlarmState((NodeState)null);
                    break;
                case 9906:
                    baseEventState = (BaseEventState)new NonExclusiveLimitAlarmState((NodeState)null);
                    break;
                default:
                    baseEventState = new BaseEventState((NodeState)null);
                    break;
            }
            EventFilter filter = monitoredItem.Status.Filter as EventFilter;
            baseEventState.Update(session.SystemContext, filter.SelectClauses, notification);
            baseEventState.Handle = (object)notification;
            return baseEventState;
        }

        public static ReferenceDescriptionCollection Browse(
          Session session,
          BrowseDescription nodeToBrowse,
          bool throwOnError)
        {
            try
            {
                ReferenceDescriptionCollection descriptionCollection = new ReferenceDescriptionCollection();
                BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
                nodesToBrowse.Add(nodeToBrowse);
                BrowseResultCollection results = (BrowseResultCollection)null;
                DiagnosticInfoCollection diagnosticInfos = (DiagnosticInfoCollection)null;
                session.Browse((RequestHeader)null, (ViewDescription)null, 0U, nodesToBrowse, out results, out diagnosticInfos);
                ClientBase.ValidateResponse((IList)results, (IList)nodesToBrowse);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, (IList)nodesToBrowse);
                while (!StatusCode.IsBad(results[0].StatusCode))
                {
                    for (int index = 0; index < results[0].References.Count; ++index)
                        descriptionCollection.Add(results[0].References[index]);
                    if (results[0].References.Count == 0 || results[0].ContinuationPoint == null)
                        return descriptionCollection;
                    ByteStringCollection continuationPoints = new ByteStringCollection();
                    continuationPoints.Add(results[0].ContinuationPoint);
                    session.BrowseNext((RequestHeader)null, false, continuationPoints, out results, out diagnosticInfos);
                    ClientBase.ValidateResponse((IList)results, (IList)continuationPoints);
                    ClientBase.ValidateDiagnosticInfos(diagnosticInfos, (IList)continuationPoints);
                }
                throw new ServiceResultException((ServiceResult)results[0].StatusCode);
            }
            catch (Exception ex)
            {
                if (throwOnError)
                    throw new ServiceResultException(ex, 2147549184U);
                return (ReferenceDescriptionCollection)null;
            }
        }

        public static ReferenceDescriptionCollection BrowseSuperTypes(
          Session session,
          NodeId typeId,
          bool throwOnError)
        {
            ReferenceDescriptionCollection descriptionCollection1 = new ReferenceDescriptionCollection();
            try
            {
                BrowseDescription nodeToBrowse = new BrowseDescription();
                nodeToBrowse.NodeId = typeId;
                nodeToBrowse.BrowseDirection = BrowseDirection.Inverse;
                nodeToBrowse.ReferenceTypeId = ReferenceTypeIds.HasSubtype;
                nodeToBrowse.IncludeSubtypes = false;
                nodeToBrowse.NodeClassMask = 0U;
                nodeToBrowse.ResultMask = 63U;
                for (ReferenceDescriptionCollection descriptionCollection2 = FormUtils.Browse(session, nodeToBrowse, throwOnError); descriptionCollection2 != null && descriptionCollection2.Count > 0; descriptionCollection2 = FormUtils.Browse(session, nodeToBrowse, throwOnError))
                {
                    descriptionCollection1.Add(descriptionCollection2[0]);
                    if (!descriptionCollection2[0].NodeId.IsAbsolute)
                        nodeToBrowse.NodeId = (NodeId)descriptionCollection2[0].NodeId;
                    else
                        break;
                }
                return descriptionCollection1;
            }
            catch (Exception ex)
            {
                if (throwOnError)
                    throw new ServiceResultException(ex, 2147549184U);
                return (ReferenceDescriptionCollection)null;
            }
        }
    }
}
