/// <summary>
        /// Converts a ONEVENTSTRUCT struct to a EventNotification object.
        /// </summary>
        internal static TsCAeEventNotification GetEventNotification(OpcRcw.Ae.ONEVENTSTRUCT input)
        {
            TsCAeEventNotification output = new TsCAeEventNotification();

            output.SourceID         = input.szSource;
            output.Time             = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(input.ftTime));
            output.Severity         = input.dwSeverity;
            output.Message          = input.szMessage;
            output.EventType        = (TsCAeEventType)input.dwEventType;
            output.EventCategory    = input.dwEventCategory;
            output.ChangeMask       = input.wChangeMask;
            output.NewState         = input.wNewState;
            output.Quality          = new TsCDaQuality(input.wQuality);
            output.ConditionName    = input.szConditionName;
            output.SubConditionName = input.szSubconditionName;
            output.AckRequired      = input.bAckRequired != 0;
            output.ActiveTime       = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(input.ftActiveTime));
            output.Cookie           = input.dwCookie;
            output.ActorID          = input.szActorID;

            object[] attributes = Technosoftware.DaAeHdaClient.Com.Interop.GetVARIANTs(ref input.pEventAttributes, input.dwNumEventAttrs, false);

            output.SetAttributes(attributes);

            return(output);
        }
        /// <summary>
        /// Removes a subscription from the control.
        /// </summary>
        public void RemoveSubscription(TsCAeSubscription subscription)
        {
            State state = (State)mSubscriptions_[subscription.ClientHandle];

            if (state != null)
            {
                // unregister call backs.
                subscription.DataChangedEvent -= state.EventHandler;

                // remove subscription.
                mSubscriptions_.Remove(subscription.ClientHandle);

                // compile list of item to delete.
                ArrayList itemsToDelete = new ArrayList();

                foreach (ListViewItem item in notificationsLv_.Items)
                {
                    TsCAeEventNotification notification = (TsCAeEventNotification)item.Tag;

                    if (notification.ClientHandle.Equals(subscription.ClientHandle))
                    {
                        itemsToDelete.Add(item);
                    }
                }

                // delete items.
                foreach (ListViewItem item in itemsToDelete)
                {
                    item.Remove();
                }
            }
        }
        /// <summary>
        /// Sends acknowledgement for an event notification.
        /// </summary>
        private void AcknowledgeMI_Click(object sender, System.EventArgs e)
        {
            try
            {
                // get current selection.
                TsCAeEventNotification[] notifications = new TsCAeEventNotification[notificationsLv_.SelectedItems.Count];

                for (int ii = 0; ii < notifications.Length; ii++)
                {
                    notifications[ii] = (TsCAeEventNotification)notificationsLv_.SelectedItems[ii].Tag;
                }

                // show dialog.
                bool result = new AcknowledgerEditDlg().ShowDialog(mServer_, notifications);

                // delete events if successful.
                if (result)
                {
                    DeleteMI_Click(sender, e);
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }
        /// <summary>
        /// Enables items in popup menu based on current selection.
        /// </summary>
        private void NotificationsLV_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // ignore left button actions.
            if (e.Button != MouseButtons.Right)
            {
                return;
            }

            // disable everything.
            viewMi_.Enabled        = false;
            acknowledgeMi_.Enabled = false;
            deleteMi_.Enabled      = false;
            clearAllMi_.Enabled    = true;

            // selects the item that was right clicked on.
            ListViewItem clickedItem = notificationsLv_.GetItemAt(e.X, e.Y);

            // no item clicked on - do nothing.
            if (clickedItem == null)
            {
                return;
            }

            // force selection to clicked node.
            clickedItem.Selected = true;

            // check for single selection.
            if (notificationsLv_.SelectedItems.Count == 1)
            {
                viewMi_.Enabled = true;
            }

            // check for multiple selection.
            if (notificationsLv_.SelectedItems.Count > 0)
            {
                acknowledgeMi_.Enabled = true;
                deleteMi_.Enabled      = true;

                // make sure all selected events require acknowledgement.
                foreach (ListViewItem item in notificationsLv_.SelectedItems)
                {
                    TsCAeEventNotification notification = (TsCAeEventNotification)item.Tag;

                    if (!notification.AckRequired)
                    {
                        acknowledgeMi_.Enabled = false;
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Converts an array of ONEVENTSTRUCT structs to an array of EventNotification objects.
        /// </summary>
        internal static TsCAeEventNotification[] GetEventNotifications(OpcRcw.Ae.ONEVENTSTRUCT[] input)
        {
            TsCAeEventNotification[] output = null;

            if (input != null && input.Length > 0)
            {
                output = new TsCAeEventNotification[input.Length];

                for (int ii = 0; ii < input.Length; ii++)
                {
                    output[ii] = GetEventNotification(input[ii]);
                }
            }

            return(output);
        }
        /// <summary>
        /// Displays the event notifications.
        /// </summary>
        public void ShowDialog(TsCAeSubscription subscription, TsCAeEventNotification notification)
        {
            if (subscription == null)
            {
                throw new ArgumentNullException("subscription");
            }

            mSubscription_ = subscription;
            mNotification_ = notification;

            acknowledgeBtn_.Enabled = notification.AckRequired;

            notificationCtrl_.ShowNotification(subscription, notification);

            ShowDialog();
        }
        /// <summary>
        /// Adds the area or source to the list.
        /// </summary>
        public void Add(TsCAeEventNotification notification, bool refresh)
        {
            ListViewItem item = new ListViewItem(notification.Time.ToString("HH:mm:ss.fff"));

            item.SubItems.Add(notification.Severity.ToString());
            item.SubItems.Add(notification.SourceID);
            item.SubItems.Add((notification.AckRequired)?"Y":"");
            item.SubItems.Add(notification.ConditionName + "." + notification.SubConditionName);
            item.SubItems.Add(notification.Message);

            item.ImageIndex = (notification.EventType != TsCAeEventType.Condition)?Resources.IMAGE_YELLOW_SCROLL:Resources.IMAGE_GREEN_SCROLL;
            item.Tag        = notification;
            item.ForeColor  = (refresh)?Color.IndianRed:Color.Empty;

            notificationsLv_.Items.Insert(0, item);
        }
        /// <summary>
        /// Displays the event notifications.
        /// </summary>
        public void ShowDialog(Ae.TsCAeSubscription subscription, TsCAeEventNotification notification)
        {
            if (subscription == null)
            {
                throw new ArgumentNullException("subscription");
            }

            m_subscription = subscription;
            m_notification = notification;

            AcknowledgeBTN.Enabled = notification.AckRequired;

            NotificationCTRL.ShowNotification(subscription, notification);

            ShowDialog();
        }
        /// <summary>
        /// Displays a detailed view of an event notification.
        /// </summary>
        private void ViewMI_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (notificationsLv_.SelectedItems.Count != 1)
                {
                    return;
                }

                TsCAeEventNotification notification = (TsCAeEventNotification)notificationsLv_.SelectedItems[0].Tag;
                State state = (State)mSubscriptions_[notification.ClientHandle];

                new NotificationDlg().ShowDialog(state.Subscription, notification);
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }
        /// <summary>
        /// Displays the notification in the control.
        /// </summary>
        public void ShowNotification(TsCAeSubscription subscription, TsCAeEventNotification notification)
        {
            // check for null value.
            if (notification == null)
            {
                sourceTb_.Text           = "";
                timeTb_.Text             = "";
                messageTb_.Text          = "";
                eventTypeTb_.Text        = "";
                eventCategoryTb_.Text    = "";
                conditionNameTb_.Text    = "";
                subConditionNameTb_.Text = "";
                newStateTb_.Text         = "";
                ackRequiredTb_.Text      = "";
                qualityTb_.Text          = "";
                activeTimeTb_.Text       = "";
                actorTb_.Text            = "";

                attributesLv_.Items.Clear();
                return;
            }

            // find category.
            Technosoftware.DaAeHdaClient.Ae.TsCAeCategory category = null;

            try
            {
                Technosoftware.DaAeHdaClient.Ae.TsCAeCategory[] categories = subscription.Server.QueryEventCategories((int)notification.EventType);

                for (int ii = 0; ii < categories.Length; ii++)
                {
                    if (categories[ii].ID == notification.EventCategory)
                    {
                        category = categories[ii];
                        break;
                    }
                }
            }
            catch
            {
                category = null;
            }

            // find attributes.
            ArrayList attributes = new ArrayList();

            try
            {
                // get attribute descriptions.
                Technosoftware.DaAeHdaClient.Ae.TsCAeAttribute[] descriptions = subscription.Server.QueryEventAttributes(notification.EventCategory);

                // get selected attributes.
                int[] attributeIDs = null;

                if (subscription.Attributes.Contains(notification.EventCategory))
                {
                    attributeIDs = subscription.Attributes[notification.EventCategory].ToArray();
                }

                // find decriptions for selected attributes.
                if (attributeIDs != null)
                {
                    for (int ii = 0; ii < attributeIDs.Length; ii++)
                    {
                        for (int jj = 0; jj < descriptions.Length; jj++)
                        {
                            if (descriptions[jj].ID == attributeIDs[ii])
                            {
                                attributes.Add(descriptions[jj]);
                                break;
                            }
                        }
                    }
                }
            }
            catch
            {
                // ignore errors.
            }

            sourceTb_.Text           = notification.SourceID;
            timeTb_.Text             = Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.Time);
            messageTb_.Text          = notification.Message;
            eventTypeTb_.Text        = Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.EventType);
            eventCategoryTb_.Text    = (category != null)?category.Name:"";
            conditionNameTb_.Text    = notification.ConditionName;
            subConditionNameTb_.Text = notification.SubConditionName;
            newStateTb_.Text         = "";
            ackRequiredTb_.Text      = Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.AckRequired);
            qualityTb_.Text          = Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.Quality);
            activeTimeTb_.Text       = Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.ActiveTime);
            actorTb_.Text            = notification.ActorID;

            // convert state to a string.
            if ((notification.NewState & (int)TsCAeConditionState.Active) != 0)
            {
                newStateTb_.Text += TsCAeConditionState.Active.ToString();
            }

            if ((notification.NewState & (int)TsCAeConditionState.Enabled) != 0)
            {
                if (newStateTb_.Text != "")
                {
                    newStateTb_.Text += " AND ";
                }
                newStateTb_.Text += TsCAeConditionState.Enabled.ToString();
            }

            if ((notification.NewState & (int)TsCAeConditionState.Acknowledged) != 0)
            {
                if (newStateTb_.Text != "")
                {
                    newStateTb_.Text += " AND ";
                }
                newStateTb_.Text += TsCAeConditionState.Acknowledged.ToString();
            }

            // fill attributes list.
            attributesLv_.Items.Clear();

            for (int ii = 0; ii < notification.Attributes.Count; ii++)
            {
                Technosoftware.DaAeHdaClient.Ae.TsCAeAttribute attribute = (ii < attributes.Count)?(Technosoftware.DaAeHdaClient.Ae.TsCAeAttribute)attributes[ii]:null;

                ListViewItem item = new ListViewItem((attribute != null)?attribute.Name:"Unknown");

                item.SubItems.Add(Technosoftware.DaAeHdaClient.OpcConvert.ToString(notification.Attributes[ii]));

                attributesLv_.Items.Add(item);
            }

            AdjustColumns(attributesLv_);
        }