/// <remarks/>
        public ItemResult[] AddItems(Item[] items)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            lock (this)
            {
                // handle trivial case.
                if (items.Length == 0)
                {
                    return(new ItemResult[0]);
                }

                // create item results.
                ItemResult[] results = new ItemResult[items.Length];

                for (int ii = 0; ii < items.Length; ii++)
                {
                    // initialize result with item.
                    results[ii] = new ItemResult((ItemIdentifier)items[ii]);

                    // check that the item is valid.
                    if (items[ii].ItemName == null || items[ii].ItemName.Length == 0)
                    {
                        results[ii].ResultID = ResultID.Da.E_INVALID_ITEM_NAME;
                        continue;
                    }

                    // check that the item exists.
                    if (!m_cache.IsValidItem(items[ii].ItemName))
                    {
                        results[ii].ResultID = ResultID.Da.E_UNKNOWN_ITEM_NAME;
                        continue;
                    }

                    // check that requested datatype is valid.
                    if (items[ii].ReqType == typeof(Opc.Type))
                    {
                        results[ii].ResultID = ResultID.Da.E_BADTYPE;
                        continue;
                    }

                    // create a new subscription item.
                    SubscriptionItem item = new SubscriptionItem(items[ii].ItemName, m_cache);

                    item.Active        = (items[ii].ActiveSpecified)?items[ii].Active:true;
                    item.ClientHandle  = items[ii].ClientHandle;
                    item.ReqType       = items[ii].ReqType;
                    item.Deadband      = (items[ii].DeadbandSpecified)?items[ii].Deadband:-1;
                    item.SamplingRate  = (items[ii].SamplingRateSpecified)?items[ii].SamplingRate:-1;
                    item.BufferEnabled = (items[ii].EnableBufferingSpecified)?items[ii].EnableBuffering:false;

                    // update sampling rate.
                    if (item.SamplingRate != -1)
                    {
                        item.SamplingRate = Cache.AdjustUpdateRate(item.SamplingRate);
                    }

                    // assign unique server handle.
                    results[ii].ServerHandle = item.ServerHandle = AssignHandle();

                    // update result object.
                    results[ii].Active                   = item.Active;
                    results[ii].ActiveSpecified          = true;
                    results[ii].ClientHandle             = item.ClientHandle;
                    results[ii].ReqType                  = item.ReqType;
                    results[ii].Deadband                 = (item.Deadband != -1)?item.Deadband:0;
                    results[ii].DeadbandSpecified        = item.Deadband != -1;
                    results[ii].SamplingRate             = (item.SamplingRate != -1)?item.SamplingRate:0;
                    results[ii].SamplingRateSpecified    = item.SamplingRate != -1;
                    results[ii].EnableBuffering          = item.BufferEnabled;
                    results[ii].EnableBufferingSpecified = item.SamplingRate != -1;

                    // save reference to new item.
                    m_items[results[ii].ServerHandle] = item;
                }

                // return results.
                return(results);
            }
        }
        /// <remarks/>
        public ItemResult[] ModifyItems(int masks, Item[] items)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            lock (this)
            {
                // handle trivial case.
                if (items.Length == 0)
                {
                    return(new ItemResult[0]);
                }

                // create item results.
                ItemResult[] results = new ItemResult[items.Length];

                for (int ii = 0; ii < items.Length; ii++)
                {
                    // initialize result with item.
                    results[ii] = new ItemResult(items[ii]);

                    // check for invalid handle.
                    if (items[ii].ServerHandle == null)
                    {
                        results[ii].ResultID = ResultID.Da.E_INVALIDHANDLE;
                        continue;
                    }

                    // lookup existing item.
                    SubscriptionItem item = (SubscriptionItem)m_items[items[ii].ServerHandle];

                    // check that the item is valid.
                    if (m_items.Contains(items))
                    {
                        results[ii].ResultID = ResultID.Da.E_INVALIDHANDLE;
                        continue;
                    }

                    // update subscription item.
                    System.Type reqType         = item.ReqType;
                    bool        active          = item.Active;
                    object      clientHandle    = item.ClientHandle;
                    float       deadband        = item.Deadband;
                    int         samplingRate    = item.SamplingRate;
                    bool        enableBuffering = item.BufferEnabled;

                    // requested data type.
                    if ((masks & (int)StateMask.ReqType) != 0)
                    {
                        // check that requested datatype is valid.
                        if (items[ii].ReqType == Type.ILLEGAL_TYPE)
                        {
                            results[ii].ResultID = ResultID.Da.E_BADTYPE;
                            continue;
                        }

                        reqType = items[ii].ReqType;
                    }

                    // client handle.
                    if ((masks & (int)StateMask.ClientHandle) != 0)
                    {
                        clientHandle = items[ii].ClientHandle;
                    }

                    // deadband.
                    if ((masks & (int)StateMask.Deadband) != 0)
                    {
                        if (items[ii].DeadbandSpecified)
                        {
                            deadband = items[ii].Deadband;

                            if (deadband < 0.0 || deadband > 100.0)
                            {
                                results[ii].ResultID = ResultID.E_INVALIDARG;
                                continue;
                            }
                        }
                        else
                        {
                            deadband = -1;
                        }
                    }

                    // sampling rate.
                    if ((masks & (int)StateMask.SamplingRate) != 0)
                    {
                        samplingRate = (items[ii].SamplingRateSpecified)?items[ii].SamplingRate:-1;

                        int requestedSamplingRate = samplingRate;

                        if (samplingRate != -1)
                        {
                            samplingRate = Cache.AdjustUpdateRate(requestedSamplingRate);
                        }

                        if (requestedSamplingRate != samplingRate)
                        {
                            results[ii].ResultID = ResultID.Da.S_UNSUPPORTEDRATE;
                        }
                    }

                    if ((masks & (int)StateMask.EnableBuffering) != 0)
                    {
                        enableBuffering = (items[ii].EnableBufferingSpecified)?items[ii].EnableBuffering:false;
                    }

                    // active.
                    if ((masks & (int)StateMask.Active) != 0)
                    {
                        active = (items[ii].ActiveSpecified)?items[ii].Active:item.Active;

                        // ensure a callback is sent on the next update.
                        if (active && !item.Active)
                        {
                            item.ResetLastUpdate();
                        }
                    }

                    // save new values.
                    item.ReqType       = reqType;
                    item.Active        = active;
                    item.ClientHandle  = clientHandle;
                    item.Deadband      = deadband;
                    item.SamplingRate  = samplingRate;
                    item.BufferEnabled = enableBuffering;

                    // update result object.
                    results[ii].Active                   = item.Active;
                    results[ii].ActiveSpecified          = true;
                    results[ii].ClientHandle             = item.ClientHandle;
                    results[ii].ReqType                  = item.ReqType;
                    results[ii].Deadband                 = (item.Deadband != -1)?item.Deadband:0;
                    results[ii].DeadbandSpecified        = item.Deadband != -1;
                    results[ii].SamplingRate             = (item.SamplingRate != -1)?item.SamplingRate:0;
                    results[ii].SamplingRateSpecified    = item.SamplingRate != -1;
                    results[ii].EnableBuffering          = item.BufferEnabled;
                    results[ii].EnableBufferingSpecified = item.BufferEnabled;
                }

                // return results.
                return(results);
            }
        }
        /// <remarks/>
        public SubscriptionState ModifyState(int masks, SubscriptionState state)
        {
            if (state == null)
            {
                throw new ArgumentNullException("state");
            }

            lock (this)
            {
                // save copy of current state.
                SubscriptionState modifiedState = (SubscriptionState)m_state.Clone();

                // update subscription defaults.
                if ((masks & (int)StateMask.Name) != 0)
                {
                    modifiedState.Name = state.Name;
                }
                if ((masks & (int)StateMask.ClientHandle) != 0)
                {
                    modifiedState.ClientHandle = state.ClientHandle;
                }
                if ((masks & (int)StateMask.Active) != 0)
                {
                    modifiedState.Active = state.Active;
                }
                if ((masks & (int)StateMask.UpdateRate) != 0)
                {
                    modifiedState.UpdateRate = state.UpdateRate;
                }
                if ((masks & (int)StateMask.KeepAlive) != 0)
                {
                    modifiedState.KeepAlive = state.KeepAlive;
                }
                if ((masks & (int)StateMask.Deadband) != 0)
                {
                    modifiedState.Deadband = state.Deadband;
                }

                if ((masks & (int)StateMask.Locale) != 0)
                {
                    modifiedState.Locale = Opc.Server.FindBestLocale(state.Locale, m_server.GetSupportedLocales());
                }

                // check for unsupported update rate.
                modifiedState.UpdateRate = Cache.AdjustUpdateRate(modifiedState.UpdateRate);

                // check update rate chanegd.
                if ((masks & (int)StateMask.UpdateRate) != 0)
                {
                    // resynch timebase but don't send an update.
                    m_tickOffset = -2;
                }

                // check for unsupported keepalive rate.
                if (modifiedState.KeepAlive != 0)
                {
                    modifiedState.KeepAlive = Cache.AdjustUpdateRate(modifiedState.KeepAlive);
                }

                // check if subscription deactivated.
                if (!m_state.Active && modifiedState.Active)
                {
                    m_cache.ActivateSubscription(this);

                    // force an update to be sent.
                    m_tickOffset = -1;
                }

                // check if subscription deactivated.
                else if (m_state.Active && !modifiedState.Active)
                {
                    m_cache.DeactivateSubscription(this);
                    m_updateQueue.Clear();
                }

                // replace existing state.
                m_state = modifiedState;

                // return new state.
                return(GetState());
            }
        }