context: //
  // --------------------------------------------------------------------------
  //  Gurux Ltd
  //
  //
  //
  // Filename:        $HeadURL$
  //
  // Version:         $Revision$,
  //                  $Date$
  //                  $Author$
  //
  // Copyright (c) Gurux Ltd
  //
  //---------------------------------------------------------------------------
  //
  //  DESCRIPTION
  //
  // This file is a part of Gurux Device Framework.
  //
  // Gurux Device Framework is Open Source software; you can redistribute it
  // and/or modify it under the terms of the GNU General Public License
  // as published by the Free Software Foundation; version 2 of the License.
  // Gurux Device Framework is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  // See the GNU General Public License for more details.
  //
  // More information of Gurux products: https://www.gurux.org
  //
  // This code is licensed under the GNU General Public License v2.
  // Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
  //---------------------------------------------------------------------------
  
  using System;
  using System.Collections.Generic;
  using System.Xml.Serialization;
  using Gurux.DLMS.Enums;
  using Gurux.DLMS.Internal;
  
  namespace Gurux.DLMS.Objects
  {
      public enum CaptureMethod : byte
      {
          /// <summary>
          /// Data is captured with Capture-method.
          /// </summary>
          Invoke,
          /// <summary>
          /// Data is captured upon reading.
          /// </summary>
          Implicit
      }
  
      /// <summary>
      /// Online help:
      /// https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCompactData
      /// </summary>
      public class GXDLMSCompactData : GXDLMSObject, IGXDLMSBase
      {
          /// <summary>
          /// Constructor.
          /// </summary>
          public GXDLMSCompactData()
          : this("0.0.66.0.1.255", 0)
          {
          }
  
          /// <summary>
          /// Constructor.
          /// </summary>
          /// <param name="ln">Logical Name of the object.</param>
          public GXDLMSCompactData(string ln)
          : this(ln, 0)
          {
          }
  
          /// <summary>
          /// Constructor.
          /// </summary>
          /// <param name="ln">Logical Name of the object.</param>
          /// <param name="sn">Short Name of the object.</param>
          public GXDLMSCompactData(string ln, ushort sn)
          : base(ObjectType.CompactData, ln, sn)
          {
              CaptureObjects = new List<GXKeyValuePair<GXDLMSObject, GXDLMSCaptureObject>>();
          }
  
          /// <summary>
          /// Compact buffer
          /// </summary>
          [XmlIgnore()]
          public byte[] Buffer
          {
              get;
              set;
          }
  
          /// <summary>
          /// Capture objects.
          /// </summary>
          [XmlIgnore()]
          [XmlArray("CaptureObjects")]
          public List<GXKeyValuePair<GXDLMSObject, GXDLMSCaptureObject>> CaptureObjects
          {
              get;
              internal set;
          }
  
          /// <summary>
          /// Template ID.
          /// </summary>
          [XmlIgnore()]
          public byte TemplateId
          {
              get;
              set;
          }
  
          /// <summary>
          /// Template description.
          /// </summary>
          [XmlIgnore()]
          public byte[] TemplateDescription
          {
              get;
              set;
          }
  
          /// <summary>
          /// Capture method.
          /// </summary>
          [XmlIgnore()]
          public CaptureMethod CaptureMethod
          {
              get;
              set;
          }
  
          /// <inheritdoc cref="GXDLMSObject.GetValues"/>
          public override object[] GetValues()
          {
              return new object[] { LogicalName, Buffer, CaptureObjects, TemplateId, TemplateDescription, CaptureMethod };
          }
  
          #region IGXDLMSBase Members
  
          byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, ValueEventArgs e)
          {
              if (e.Index == 1)
              {
                  //Reset.
                  Reset();
              }
              else if (e.Index == 2)
              {
                  //Capture.
                  Capture(e.Server);
              }
              else
              {
                  e.Error = ErrorCode.ReadWriteDenied;
              }
              return null;
          }
  
          int[] IGXDLMSBase.GetAttributeIndexToRead(bool all)
          {
              List<int> attributes = new List<int>();
              //LN is static and read only once.
              if (all || string.IsNullOrEmpty(LogicalName))
              {
                  attributes.Add(1);
              }
              //CaptureObjects
              if (all || CanRead(3))
              {
                  attributes.Add(3);
              }
              //TemplateDescription
              if (all || CanRead(5))
              {
                  attributes.Add(5);
              }
              //Buffer
              if (all || CanRead(2))
              {
                  attributes.Add(2);
              }
              //TemplateId
              if (all || CanRead(4))
              {
                  attributes.Add(4);
              }
              //CaptureMethod
              if (all || CanRead(6))
              {
                  attributes.Add(6);
              }
              return attributes.ToArray();
          }
  
          /// <inheritdoc cref="IGXDLMSBase.GetNames"/>
          string[] IGXDLMSBase.GetNames()
          {
              return new string[] { Internal.GXCommon.GetLogicalNameString(), "Buffer", "CaptureObjects", "TemplateId", "TemplateDescription", "CaptureMethod" };
          }
  
          /// <inheritdoc cref="IGXDLMSBase.GetMethodNames"/>
          string[] IGXDLMSBase.GetMethodNames()
          {
              return new string[] {"Reset", "Capture" };
          }
  
          int IGXDLMSBase.GetMaxSupportedVersion()
          {
              return 0;
          }
  
          int IGXDLMSBase.GetAttributeCount()
          {
              return 6;
          }
  
          int IGXDLMSBase.GetMethodCount()
          {
              return 2;
          }
  
          public static List<object> GetDataTypes(byte[] value)
          {
              if (value == null || value.Length == 0)
              {
                  return new List<object>();
              }
              GXDataInfo info = new GXDataInfo();
              object ret = GXCommon.GetCompactArray(null, new GXByteBuffer(value), info, true);
              return ((List<object>)ret);
          }
  
          public static List<object> GetData(byte[] columns, byte[] value)
          {
              return GetData(columns, value, false);
          }
  
          public static List<object> GetData(byte[] columns, byte[] value, bool AppendAA)
          {
              if (columns == null || columns.Length == 0 ||
                  value == null || value.Length == 0)
              {
                  return new GXArray();
              }
              List<DataType> list = new List<DataType>();
              GXDataInfo info = new GXDataInfo();
              info.AppendAA = AppendAA;
              GXByteBuffer bb = new GXByteBuffer();
              bb.Set(columns);
              GXCommon.SetObjectCount(value.Length, bb);
              bb.Set(value);
              List<object> tmp = (List<object>)GXCommon.GetCompactArray(null, bb, info, false);
              return tmp;
          }
  
          /// <inheritdoc cref="IGXDLMSBase.GetDataType"/>
          public override DataType GetDataType(int index)
          {
              switch (index)
              {
                  case 1:
                      return DataType.OctetString;
                  case 2:
                      return DataType.OctetString;
                  case 3:
                      return DataType.Array;
                  case 4:
                      return DataType.UInt8;
                  case 5:
                      return DataType.OctetString;
                  case 6:
                      return DataType.Enum;
                  default:
                      throw new ArgumentException("GetDataType failed. Invalid attribute index.");
              }
          }
  
          /// <summary>
          /// Returns captured objects.
          /// </summary>
          /// <param name="settings">DLMS settings.</param>
          /// <returns></returns>
          byte[] GetCaptureObjects(GXDLMSSettings settings)
          {
              GXByteBuffer data = new GXByteBuffer();
              data.SetUInt8((byte)DataType.Array);
              //Add count
              GXCommon.SetObjectCount(CaptureObjects.Count, data);
              foreach (var it in CaptureObjects)
              {
                  data.SetUInt8((byte)DataType.Structure);
                  //Count
                  data.SetUInt8(4);
                  //ClassID
                  GXCommon.SetData(settings, data, DataType.UInt16, it.Key.ObjectType);
                  //LN
                  GXCommon.SetData(settings, data, DataType.OctetString, GXCommon.LogicalNameToBytes(it.Key.LogicalName));
                  //Selected Attribute Index
                  GXCommon.SetData(settings, data, DataType.Int8, it.Value.AttributeIndex);
                  //Selected Data Index
                  GXCommon.SetData(settings, data, DataType.UInt16, it.Value.DataIndex);
              }
              return data.Array();
          }
  
          object IGXDLMSBase.GetValue(GXDLMSSettings settings, ValueEventArgs e)
          {
              switch (e.Index)
              {
                  case 1:
                      return GXCommon.LogicalNameToBytes(LogicalName);
                  case 2:
                      return Buffer;
                  case 3:
                      return GetCaptureObjects(settings);
                  case 4:
                      return TemplateId;
                  case 5:
                      return TemplateDescription;
                  case 6:
                      return CaptureMethod;
                  default:
                      e.Error = ErrorCode.ReadWriteDenied;
                      break;
              }
              return null;
          }
  
          private static void SetCaptureObjects(GXDLMSSettings settings, List<GXKeyValuePair<GXDLMSObject, GXDLMSCaptureObject>> list, IEnumerable<object> array)
          {
              GXDLMSConverter c = null;
              list.Clear();
              try
              {
                  if (array != null)
                  {
                      foreach (object tmp in array)
                      {
                          List<object> it;
                          if (tmp is List<object>)
                          {
                              it = (List<object>)tmp;
                          }
                          else
                          {
                              it = new List<object>((object[])tmp);
                          }
                          if (it.Count != 4)
                          {
                              throw new GXDLMSException("Invalid structure format.");
                          }
                          int v = Convert.ToInt16(it[0]);
  
gt:                         if (Enum.GetName(typeof(ObjectType), v) == null)