using System;
using System.Collections;

using Opc.Ua;
using Opc.Ua.Client;

namespace Siemens.OpcUA
{
    public class Subscription
    {
        System.Collections.Generic.List<MonitoredItem> itemsrefresh = new System.Collections.Generic.List<MonitoredItem>();//20150103Ôö¼Ó¶ÏÍø»Ö¸´
        #region Construction
        public Subscription()
        { }
        #endregion

        #region Fields
        /// <summary>
        /// Keeps the session. 
        /// </summary>
        private Session m_Session = null;
        /// <summary>
        /// Keeps the subscription. 
        /// </summary>
        private Opc.Ua.Client.Subscription m_Subscription = null;
        #endregion

        #region Properties
        // Session
        public Session Session
        {
            get { return m_Session; }
            set { m_Session = value; }
        }
        // Subscription
        public Opc.Ua.Client.Subscription innerSubscription
        {
            get { return m_Subscription; }
            set { m_Subscription = value; }
        }
        #endregion

        #region MonitoredItem
        /// <summary>
        /// Creates a monitored item and adds it to the existing subscription.
        /// </summary>
        /// <param name="variableNodeId">The according nodeid.</param>
        /// <param name="clientHandle">The handle of the client registering items.</param>
        /// <param name="callback">The callback to retrieve value changes.</param>
        /// <param name="samplingRate">The requested sampling rate.</param>
        /// <param name="serverHandle">The handle of the item.</param>
        public void AddDataMonitoredItem(NodeId variableNodeId, object clientHandle, valueChanged callback, uint samplingRate, out object serverHandle)
        {
            serverHandle = null;

            try
            {
                MonitoredItem monitoredItem = new MonitoredItem(m_Subscription.DefaultItem);
                ClientMonitoredItemData clientData = new ClientMonitoredItemData();
                clientData.callback = callback;
                clientData.clientHandle = clientHandle;

                // Monitored item settings:
                monitoredItem.StartNodeId = variableNodeId;
                monitoredItem.AttributeId = Attributes.Value;
                monitoredItem.MonitoringMode = MonitoringMode.Reporting;//20151120 
                monitoredItem.SamplingInterval = (int)samplingRate; // Affects the read cycle between UA Server and data source
                monitoredItem.QueueSize = 1;
                monitoredItem.DiscardOldest = true;//20151120 
                monitoredItem.Handle = clientData;

                // Add item to subscription.
                m_Subscription.AddItem(monitoredItem);

                // Call the server and apply any changes to the state of the subscription or monitored items.
                m_Subscription.ApplyChanges();
               
                // Check result of add.
                if (monitoredItem.Status.Error != null && StatusCode.IsBad(monitoredItem.Status.Error.StatusCode))
                {
                    throw ServiceResultException.Create(
                        monitoredItem.Status.Error.StatusCode.Code,
                        "Creation of data monitored item failed");
                }

                serverHandle = monitoredItem;
                if (itemsrefresh.Exists(aa => aa.StartNodeId == variableNodeId) == false)
                {//20150103Ôö¼Ó¶ÏÍø»Ö¸´
                    itemsrefresh.Add(monitoredItem);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// Modifies a monitored item.
        /// </summary>
        public void ModifyMonitoredItem(object serverHandle)
        {
            try
            {
               m_Subscription.ApplyChanges();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// Removes a monitored item.
        /// </summary>
        public void RemoveMonitoredItem(object serverHandle)
        {
            try
            {
                m_Subscription.RemoveItem((MonitoredItem)serverHandle);
                m_Subscription.ApplyChanges();
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public void RemoveAllMonitoredItems()
        {//20150103Ôö¼Ó¶ÏÍø»Ö¸´
            if (itemsrefresh.Count > 0)
            {
                itemsrefresh.RemoveAll(aa => aa.Handle != null);
            }
        }
        /// <summary>
        /// ͨ¹ýÉèÖö©ÔÄµÄ¼à¿ØÄ£Ê½£¬Ë¢Ð¶©ÔÄ
        /// </summary>
        /// <returns></returns>
        public bool RefreshMonitoringMode()
        {//20150103Ôö¼Ó¶ÏÍø»Ö¸´
            try
            {
                if (itemsrefresh.Count > 0)
                {
                    m_Subscription.SetMonitoringMode(MonitoringMode.Disabled, itemsrefresh);
                    m_Subscription.SetMonitoringMode(MonitoringMode.Reporting, itemsrefresh);
                }
                return true;
            }
            catch (Exception e)
            {
                throw e;
            }
            
        }
        
        #endregion
       }
    
    public class ClientMonitoredItemData
    {
        public object clientHandle = null;
        public valueChanged callback = null;
    }

}