//------------------------------------------------------------------------------
// Copyright (C) 2008 Invensys Systems Inc.  All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//------------------------------------------------------------------------------

using System;
using System.Runtime.InteropServices;
using System.Collections;
using ArchestrA.Core;
using ArchestrA.Toolkit;

namespace ArchestrA.Toolkit.Monitor
{
    [Guid("df4726d8-fe33-4d79-a6a1-b8198f1e5ac1")]
    /// <summary>
    /// Summary description for Monitor
    /// </summary>
    public class MonitorRuntime : RuntimeBase
    {
        #region Attributes - Toolkit generated code
        // The following C# properties have been defined to simplify access to
        // attribute values - do not modify the contents of this region with
        // the code editor.
        private CMxBoolean ResetInputAvg
        {
            get { return InternalReferenceOnly.ResetInputAvg; }
            set { InternalReferenceOnly.ResetInputAvg.Set(value); }
        }

        private CMxFloat PVHiLimit
        {
            get { return InternalReferenceOnly.PVHiLimit; }
            set { InternalReferenceOnly.PVHiLimit.Set(value); }
        }

        private CMxDouble PVInputAvg
        {
            get { return InternalReferenceOnly.PVInputAvg; }
            set { InternalReferenceOnly.PVInputAvg.Set(value); }
        }

        private CMxFloat PV
        {
            get { return InternalReferenceOnly.PV; }
            set { InternalReferenceOnly.PV.Set(value); }
        }



        public __PVInputOutput PVInputOutput = null;

        public class __PVInputOutput : InputOutputPrimBase
        {
            protected override void Initialize(SupportWrapper _Wrapper)
            {
                if (_ReadValue == null) { _ReadValue = new CMxVariant(Wrapper, "PVInputOutput.ReadValue"); }
                if (_WriteValue == null) { _WriteValue = new CMxVariant(Wrapper, "PVInputOutput.WriteValue"); }
                if (_DataType == null) { _DataType = new CMxDataType(Wrapper, "PVInputOutput.DataType"); }

                attrId = _ReadValue.Attribute.shAttributeId;
                attrId2 = _WriteValue.Attribute.shAttributeId;
                primId = _ReadValue.Attribute.shPrimitiveId;
                dataType = _DataType.Value;

                base.Initialize(Wrapper);
            }

            public SupportWrapper Wrapper = new SupportWrapper();

            private CMxStatus _ReadStatus = null;

            public CMxStatus ReadStatus
            {
                get { if (_ReadStatus == null) { _ReadStatus = new CMxStatus(Wrapper, "PVInputOutput.ReadStatus"); } return _ReadStatus; }
                set { if (_ReadStatus == null) { _ReadStatus = new CMxStatus(Wrapper, "PVInputOutput.ReadStatus"); } _ReadStatus.Set(value); }
            }

            private CMxVariant _ReadValue = null;

            public CMxVariant ReadValue
            {
                get { if (_ReadValue == null) { _ReadValue = new CMxVariant(Wrapper, "PVInputOutput.ReadValue"); } return _ReadValue; }
                set { if (_ReadValue == null) { _ReadValue = new CMxVariant(Wrapper, "PVInputOutput.ReadValue"); } _ReadValue.Set(value); }
            }

            private CMxReference _ReferenceSecondary = null;

            public CMxReference ReferenceSecondary
            {
                get { if (_ReferenceSecondary == null) { _ReferenceSecondary = new CMxReference(Wrapper, "PVInputOutput.ReferenceSecondary"); } return _ReferenceSecondary; }
                set { if (_ReferenceSecondary == null) { _ReferenceSecondary = new CMxReference(Wrapper, "PVInputOutput.ReferenceSecondary"); } _ReferenceSecondary.Set(value); }
            }

            private CMxReference _Reference = null;

            public CMxReference Reference
            {
                get { if (_Reference == null) { _Reference = new CMxReference(Wrapper, "PVInputOutput.Reference"); } return _Reference; }
                set { if (_Reference == null) { _Reference = new CMxReference(Wrapper, "PVInputOutput.Reference"); } _Reference.Set(value); }
            }

            private CMxDataType _DataType = null;

            public CMxDataType DataType
            {
                get { if (_DataType == null) { _DataType = new CMxDataType(Wrapper, "PVInputOutput.DataType"); } return _DataType; }
            }

            private CMxVariant _WriteValue = null;

            public CMxVariant WriteValue
            {
                get { if (_WriteValue == null) { _WriteValue = new CMxVariant(Wrapper, "PVInputOutput.WriteValue"); } return _WriteValue; }
                set { if (_WriteValue == null) { _WriteValue = new CMxVariant(Wrapper, "PVInputOutput.WriteValue"); } _WriteValue.Set(value); }
            }

            private CMxStatus _WriteStatus = null;

            public CMxStatus WriteStatus
            {
                get { if (_WriteStatus == null) { _WriteStatus = new CMxStatus(Wrapper, "PVInputOutput.WriteStatus"); } return _WriteStatus; }
                set { if (_WriteStatus == null) { _WriteStatus = new CMxStatus(Wrapper, "PVInputOutput.WriteStatus"); } _WriteStatus.Set(value); }
            }

            public AoAWrapper AoA = null;

            public void SuspendUpdatesList()
            {
                if (AoA == null) { AoA = new AoAWrapper(Wrapper, new string[] { "PVInputOutput.ReadValue" }); } AoA.SuspendUpdatesList();
            }

            public void ActivateUpdatesList()
            {
                if (AoA == null) { AoA = new AoAWrapper(Wrapper, new string[] { "PVInputOutput.ReadValue" }); } AoA.ActivateUpdatesList();
            }

            public __PVInputOutput(AObjectBase baseClass)
            {
                Wrapper.baseClass = baseClass;
            }

        }

        #endregion Attributes

        #region Internal Reference Only
        //Toolkit code required to access the attributes declared in the Object Class
        private Monitor InternalReferenceOnly = null;
        #endregion Internal Reference Only

        #region Declarations
        //Declare Runtime Class Variables here.
        //Variables declared in this region are available to all methods 
        //in the Runtime Class.
        long totalReads;
        double accumulatedInput;

        #endregion Declarations


        public MonitorRuntime()
        {
            InternalReferenceOnly = new Monitor();
            this.AObjectInstance = InternalReferenceOnly;

            #region Runtime Event Registration - Toolkit generated code
            // Required region for Runtime Events - do not modify 
            // the contents of this region with the code editor.
            base.RuntimeGetStatusDesc += new RuntimeGetStatusDescDelegate(MonitorRuntime_RuntimeGetStatusDesc);
            base.RuntimeSetScanState += new RuntimeSetScanStateDelegate(Monitor_RuntimeSetScanState);
            base.RuntimeExecute += new RuntimeExecuteDelegate(Monitor_RuntimeExecute);
            base.RuntimeShutdown += new RuntimeShutdownDelegate(Monitor_RuntimeShutdown);
            base.RuntimeStartup += new RuntimeStartupDelegate(Monitor_RuntimeStartup);
            base.RuntimeDynamic += new RuntimeDynamicSetHandlerDelegate(MonitorRuntime_RuntimeDynamic);
            base.RuntimeInitialize += new RuntimeInitializeDelegate(MonitorRuntime_RuntimeInitialize);
            #endregion Runtime Event Registration

            #region Runtime Set Handler Registration – Toolkit generated code
            // Required method for Runtime SetHandlers.  
            // Changes made using the code editor will appear in the Toolkit Editor.
            // 
            // WARNING: Changes made to this region will result in a Shape Change.

            //	TODO: Runtime SetHandler registration
            this.RegisterRuntimeSetHandler("ResetInputAvg", new RuntimeSetHandlerDelegate(ResetInputAvgSetHandler));
            this.RegisterRuntimeSetHandler("PVHiLimit", new RuntimeSetHandlerDelegate(PVHiLimitSetHandler));
            this.RegisterRuntimeSetHandler("PV", new RuntimeSetHandlerDelegate(PVSetHandler));
            #endregion Runtime Set Handler Registration

            #region Primitive Wrapper Initialization - Toolkit generated code
            PVInputOutput = new __PVInputOutput(this);
            #endregion Primitive Wrapper Initialization

            #region Primitive Advise only Activate Registration - Toolkit generated code
            #endregion Primitive Advise only Activate Initialization

        }

        private void MonitorRuntime_RuntimeInitialize(object sender)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime - Initialize
            //
            //  Do not read or write attribute values of this primitive during Initialize
            //------------------------------------------------------------------------------
        }

        private void Monitor_RuntimeExecute(object sender)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime - Execute
            //
            //  This is where the main logic of the object periodically executes when
            //  the object is on scan.
            //
            //  Read or write the attributes of this primitive using the generated 
            //  properties (Value, Quality).
            //------------------------------------------------------------------------------
            #region Example code
            //          // The lines below both increment the value of the attribute "Attribute1" by 1
            //          Example_001 ++;  
            //          Example_001 = Example_001 + 1;
            //
            //          //Example_001 quality is set to Bad on Condition_001 being true.
            //          Example_001.Quality = (Condition_001 ?  DataQuality.DataQualityBad : DataQuality.DataQualityGood);
            //
            //          // The attribute "ElapsedTime" contains the time elapsed since the last reset
            //          ElapsedTime = GetScanTime() - TimeOfLastReset;
            //
            //          // Increment the 3rd element of an array
            //          FloatArray[3] ++; 
            //
            //          // Increment all the elements of an array
            //          for( short counter = 1; counter <= FloatArray.Length; counter ++)
            //          {
            //            FloatArray[counter] ++;
            //          }
            #endregion

            if ((PVInputOutput.ReadStatus.Value.success == -1) && PVInputOutput.ReadValue.Quality.isGood)
            {
                float inputValue = (float)PVInputOutput.GetReadValue();

                PV = inputValue;
                accumulatedInput += Convert.ToDouble(inputValue);
                totalReads++;

                PVInputAvg = accumulatedInput / totalReads;

                PVInputAvg.Quality = DataQuality.DataQualityGood;

            }
        }

        private void Monitor_RuntimeShutdown(object sender)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime Event - Shutdown
            //
            //  Clean up dynamic allocation, release open resources, etc.
            //------------------------------------------------------------------------------
        }

        private void Monitor_RuntimeStartup(object sender, RuntimeStartupEventArgs e)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime Event - Startup
            //
            //  Cache attributes. Cache Primitive IDs of other known primitives.
            //------------------------------------------------------------------------------

            // RestoreDynamicAttributes will recreate the Dynamic Attributes and restore the check pointed 
            // values during failover startup. The Failover Support for Dynamic Attributes option must
            // be enabled via the Object Editor to support this function. To maintain the 
            // Dynamic Attribute values the CheckpointDynamicAttributeData function must be called
            // when Dynamic Attribute values are modified (refer to the Dynamic Attribute Set Handler).

            //RestoreDynamicAttributes();

            // Execute offscan code to initialize the object in its offscan state.
            SetScanState(false);
        }

        private void Monitor_RuntimeSetScanState(object sender, RuntimeSetScanStateEventArgs e)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime Event - SetScanState
            //
            //  Perform actions when the object goes on or off scan.
            //------------------------------------------------------------------------------

            if (e.onScan)
            {
                PVInputAvg.Quality = DataQuality.DataQualityInitializing;
            }
            else
            {
                PVInputAvg.Quality = DataQuality.DataQualityBad;
            }
        }

        private void MonitorRuntime_RuntimeGetStatusDesc(object sender, ref RuntimeGetStatusDescEventArgs e)
        {
            //------------------------------------------------------------------------------
            //  TODO: Runtime Event - GetStatusDesc
            //
            //  This routine provides a String for an error code when a client requests it.
            //  By default this method looks for an entry in the dictionary that has the 
            //  DetailedErrorCode as the PhraseID.
            //
            //  You need to change this implmentation if you want to provide embedded values 
            //  within your messages, or you want to use string PhraseIDs instead of integer 
            //  PhraseIDs.
            //------------------------------------------------------------------------------

            switch (e.detailedErrorCode)
            {
                case 10000:
                    e.status = GetText("HiLimitExceeded");
                    break;
                default:
                    e.status = GetText((int)e.detailedErrorCode);
                    break;
            }
        }

        private void MonitorRuntime_RuntimeDynamic(object sender, ref RuntimeSetHandlerEventArgs e)
        {

            string attrName = Get(e.attributeHandle.shAttributeId, e.attributeHandle.shPrimitiveId, EATTRIBUTEPROPERTY.idxAttribPropName);

            //------------------------------------------------------------------------------
            //	TODO: Runtime Event - Dynamic Set Handler
            //
            //  Implement set handler code for any dynamic attributes you create with set handlers  
            //------------------------------------------------------------------------------

            // CheckpointDynamicAttributeData will update the checkpoint values for all Dynamic Attributes. 
            // To recreate Dynamic Attributes and restore Dynamic Attribute values the RestoreDynamicAttributes 
            // function must be called when starting up from failover (refer to the Startup method).

            //CheckpointDynamicAttributeData();

            #region Example
            // if (attrName == "MyDynamic")
            // {
            //     if (e.Value > 10)
            //     {
            //         LogWarning(string.Format("value for {0} must be less or equal to 10", attrName));
            //     }
            //     else
            //     {
            //         SetValue(attrName, e.Value);
            //     }
            //
            //    
            //     return;
            // }   
            #endregion

            // if unhandled a warning is shown as a reminder
            SetValue(e.attributeHandle.shAttributeId, e.attributeHandle.shPrimitiveId, e.Value);
            LogWarning(string.Format("Uknown set handler for attribute '{0}'", attrName));

        }

        private void PVSetHandler(object sender, ref RuntimeSetHandlerEventArgs e)
        {
            if (e.Value > PVHiLimit)
            {
                e.status.detail = 10000;
                e.status.Category = MxStatusCategory.MxCategoryOperationalError;
            }
            else
            {
                PV.SetHandlerValue = e;
                PVInputOutput.WriteValue = e.Value;
            }
        }

        private void PVHiLimitSetHandler(object sender, ref RuntimeSetHandlerEventArgs e)
        {
            PVHiLimit.SetHandlerValue = e;
        }

        private void ResetInputAvgSetHandler(object sender, ref RuntimeSetHandlerEventArgs e)
        {
            ResetInputAvg.SetHandlerValue = e;
            totalReads = 0;
            accumulatedInput = 0;
        }
    }
}

