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 Gurux.DLMS.Enums;
  using Gurux.DLMS.Internal;
  using System.Diagnostics;
  using Gurux.DLMS.Objects;
  using Gurux.DLMS.Ecdsa;
  using Gurux.DLMS.Secure;
  using Gurux.DLMS.Objects.Enums;
  
  namespace Gurux.DLMS
  {
      /// <summary>
      /// this class is used to handle LN commands.
      /// </summary>
      internal sealed class GXDLMSLNCommandHandler
      {
          public static void HandleGetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml, Command cipheredCommand)
          {
              //Return error if connection is not established.
              if (xml == null && (settings.Connected & ConnectionState.Dlms) == 0 && cipheredCommand == Command.None)
              {
                  replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError,
                                ServiceError.Service, (byte)Service.Unsupported));
                  return;
              }
              byte invokeID = 0;
              GetCommandType type = GetCommandType.Normal;
              try
              {
                  //If GBT is used data is empty.
                  if (data.Size != 0)
                  {
                      type = (GetCommandType)data.GetUInt8();
                      // Get invoke ID and priority.
                      invokeID = data.GetUInt8();
                      settings.UpdateInvokeId(invokeID);
                      if (xml != null)
                      {
                          if (type <= GetCommandType.WithList)
                          {
                              GXDLMS.AddInvokeId(xml, Command.GetRequest, type, invokeID);
                          }
                          else
                          {
                              xml.AppendStartTag(Command.GetRequest);
                              xml.AppendComment("Unknown tag: " + type);
                              xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invokeID, 2));
                          }
                      }
                  }
                  // GetRequest normal
                  if (type == GetCommandType.Normal)
                  {
                      GetRequestNormal(settings, invokeID, server, data, replyData, xml, cipheredCommand);
                  }
                  else if (type == GetCommandType.NextDataBlock)
                  {
                      // Get request for next data block
                      GetRequestNextDataBlock(settings, invokeID, server, data, replyData, xml, false, cipheredCommand);
                  }
                  else if (type == GetCommandType.WithList)
                  {
                      // Get request with a list.
                      GetRequestWithList(settings, invokeID, server, data, replyData, xml, cipheredCommand);
                  }
                  else if (xml == null)
                  {
                      Debug.WriteLine("HandleGetRequest failed. Invalid command type.");
                      settings.ResetBlockIndex();
                      type = GetCommandType.Normal;
                      data.Clear();
                      GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, invokeID, Command.GetResponse, (byte)type, null, null, (byte)ErrorCode.ReadWriteDenied, cipheredCommand), replyData);
                  }
                  if (xml != null)
                  {
                      if (type <= GetCommandType.WithList)
                      {
                          xml.AppendEndTag(Command.GetRequest, type);
                      }
                      xml.AppendEndTag(Command.GetRequest);
                  }
              }
              catch (Exception ex)
              {
                  if (xml != null)
                  {
                      throw;
                  }
                  Debug.WriteLine("HandleGetRequest failed. " + ex.Message);
                  settings.ResetBlockIndex();
                  data.Clear();
                  GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, invokeID, Command.GetResponse, (byte)type, null, null, (byte)ErrorCode.ReadWriteDenied, cipheredCommand), replyData);
              }
          }
  
          ///<summary>
          ///Handle set request.
          ///</summary>
          ///<returns>
          ///Reply to the client.
          ///</returns>
          public static void HandleSetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml, Command cipheredCommand)
          {
              //Return error if connection is not established.
              if (xml == null && (settings.Connected & ConnectionState.Dlms) == 0 && cipheredCommand == Command.None)
              {
                  replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError,
                                ServiceError.Service, (byte)Service.Unsupported));
                  return;
              }
              // Get type.
              byte type = data.GetUInt8();
              GXDLMSLNParameters p = null;
              try
              {
                  // Get invoke ID and priority.
                  byte invoke = data.GetUInt8();
                  settings.UpdateInvokeId(invoke);
                  p = new GXDLMSLNParameters(settings, invoke, Command.SetResponse, (byte)type, null, null, 0xFF, cipheredCommand);
                  // SetRequest normal or Set Request With First Data Block
                  if (xml != null)
                  {
                      if (type < 6)
                      {
                          GXDLMS.AddInvokeId(xml, Command.SetRequest, (SetRequestType)type, invoke);
                      }
                      else
                      {
                          xml.AppendStartTag(Command.SetRequest);
                          xml.AppendComment("Unknown tag: " + type);
                          //InvokeIdAndPriority
                          xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invoke, 2));
                      }
                  }
                  switch (type)
                  {
                      case (byte)SetRequestType.Normal:
                      case (byte)SetRequestType.FirstDataBlock:
                          if (type == (byte)SetRequestType.Normal)
                          {
                              p.status = 0;
                          }
                          HandleSetRequestNormal(settings, server, data, (byte)type, p, replyData, xml);
                          break;
                      case (byte)SetRequestType.WithDataBlock:
                          HanleSetRequestWithDataBlock(settings, server, data, p, replyData, xml);
                          break;
                      case (byte)SetRequestType.WithList:
                          HanleSetRequestWithList(settings, invoke, server, data, p, replyData, xml);
                          break;
                      default:
                          System.Diagnostics.Debug.WriteLine("HandleSetRequest failed. Unknown command.");
                          data.Clear();
                          settings.ResetBlockIndex();
                          p.status = (byte)ErrorCode.ReadWriteDenied;
                          break;
                  }
                  if (xml != null)
                  {
                      if (type < 6)
                      {
                          xml.AppendEndTag(Command.SetRequest, (SetRequestType)type);
                      }
                      xml.AppendEndTag(Command.SetRequest);
                      return;
                  }
              }
              catch (Exception ex)
              {
                  if (xml != null)
                  {
                      throw ex;
                  }
                  Debug.WriteLine("HandleGetRequest failed. " + ex.Message);
                  data.Clear();
                  settings.ResetBlockIndex();
                  p.status = (byte)ErrorCode.ReadWriteDenied;
              }
              GXDLMS.GetLNPdu(p, replyData);
          }
  
          /// <summary>
          /// Handle method request next data block command.
          /// </summary>
          /// <param name="data">Received data.</param>
          internal static void MethodRequestNextDataBlock(
              GXDLMSSettings settings,
              byte invokeID,
              GXDLMSServer server,
              GXByteBuffer data,
              GXByteBuffer replyData,
              GXDLMSTranslatorStructure xml,
              bool streaming,
              Command cipheredCommand)
          {
              GXByteBuffer bb = new GXByteBuffer();
              byte lastBlock = 0;
              if (!streaming)
              {
                  lastBlock = data.GetUInt8();
                  // Get block index.
                  UInt32 index = data.GetUInt32();
                  if (xml != null)
                  {
                      xml.AppendLine(TranslatorTags.BlockNumber, null, xml.IntegerToHex(index, 8));
                      return;
                  }
                  if (index != settings.BlockIndex)
                  {
                      Debug.WriteLine("MethodRequestNextDataBlock failed. Invalid block number. " + settings.BlockIndex + "/" + index);
                      GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, 0, Command.MethodResponse, (byte)ActionResponseType.Normal, null,
                          bb, (byte)ErrorCode.DataBlockNumberInvalid, cipheredCommand), replyData);
                      return;
                  }
              }
              settings.IncreaseBlockIndex();
              GXDLMSLNParameters p = new GXDLMSLNParameters(settings, invokeID,
                  streaming ? Command.GeneralBlockTransfer : Command.MethodResponse, (byte)ActionResponseType.Normal,
                  null, bb, (byte)ErrorCode.Ok, cipheredCommand);
              p.Streaming = settings.GbtWindowSize != 1;
              p.GbtWindowSize = settings.GbtWindowSize;
              //If transaction is not in progress.
              if (server.transaction == null)
              {
  
gt:                 p.status = (byte)ErrorCode.NoLongGetOrReadInProgress;