function cfg = GroupsFrameDecoder(commandType, zclPayload)
%GROUPSFRAMEDECODER Decode frames of the Groups ZigBee cluster
% CFG = GROUPSFRAMEDECODER(ZCLCONFIG, ZCLPAYLOAD) decodes the ZigBee Groups
% Cluster payload ZCLPAYLOAD for the command type COMMANDTYPE and outputs
% the corresponding Group cluster frame configuration to the object CFG.
%
%   See also zigbee.GroupsFrameConfig, zigbee.GroupsFrameGenerator.

% Copyright 2017-2023 The MathWorks, Inc.

% 0. Initializing configuration object
cfg = zigbee.GroupsFrameConfig('CommandType', commandType);

% convert bytes to bits
if ~isempty(zclPayload)
  zclPayloadBin = zigbee.internal.bytes2bits(zclPayload);
end

currPos = 1;
switch commandType
  % Add group commands
  case {'Add group', 'Add group if identifying'}
   
    cfg = decodeGroupIDName(cfg, zclPayloadBin, currPos);
    
  % View/Remove group commands
  case {'View group', 'Remove group'}
    % 1. Group ID (2 octets)
    cfg.GroupID = dec2hex(bit2int(zclPayloadBin(currPos:currPos+15)', 16, false), 4);

  % Get group membership command
  case 'Get group membership'
   
    cfg = decodeGroupCountList(cfg, zclPayloadBin, currPos);
    
  % Add/remove group response command
  case {'Add group response', 'Remove group response'}
    % 1. Status (1 octet)
    cfg = decodeStatus(cfg, zclPayloadBin(currPos:currPos+7));
    currPos = currPos+8;

    % 2. Group ID (2 octets)
    cfg.GroupID = dec2hex(bit2int(zclPayloadBin(currPos:currPos+15)', 16, false), 4);

  % View group response command
  case 'View group response'
    % 1. Status (1 octet)
    cfg = decodeStatus(cfg, zclPayloadBin(currPos:currPos+7));
    currPos = currPos+8;

    cfg = decodeGroupIDName(cfg, zclPayloadBin, currPos);

  % Get group membership response command
  case 'Get group membership response'
    % 1. Capacity (1 octet)
    cfg.Capacity = bit2int(zclPayloadBin(currPos:currPos+7)', 8, false);
    currPos = currPos+8;

    cfg = decodeGroupCountList(cfg, zclPayloadBin, currPos);
end

function cfg = decodeGroupIDName(cfg, zclPayloadBin, currPos)

	% 1. Group ID (2 octets)
  cfg.GroupID = dec2hex(bit2int(zclPayloadBin(currPos:currPos+15)', 16, false), 4);
  currPos = currPos+16;

  % 2. Group Name String length (1 octet)
  groupNameStrLen = bit2int(zclPayloadBin(currPos:currPos+7)', 8, false);
  currPos = currPos+8;

  % 3. Group Name (groupNameStrLen octets)
  groupName = zeros(1, groupNameStrLen);
  for i = 1:groupNameStrLen
    groupName(i) = bit2int(zclPayloadBin(currPos:currPos+7)', 8, false);
    currPos = currPos+8;
  end
  cfg.GroupName = char(groupName);
  

function cfg = decodeGroupCountList(cfg, zclPayloadBin, currPos)

  % 1. Group count (1 octet)
  groupCount = bit2int(zclPayloadBin(currPos:currPos+7)', 8, false);
  currPos = currPos+8;

  % 2. Group list ((groupCount * 2) octets)
  groupList = zeros(groupCount, 1);
  i = 1;
  while (currPos < numel(zclPayloadBin))
    groupList(i) = bit2int(zclPayloadBin(currPos:currPos+15)', 16, false);
    currPos = currPos+16;
    i = i+1;
  end
  if(groupCount > 0)
    cfg.GroupList = dec2hex(groupList, 4);
  end


function cfg = decodeStatus(cfg, status)
switch dec2hex(bit2int(status(:)', length(status), false), 2)
  case '00'
    cfg.Status = 'Success';
  case {'8a', '8A'}
    cfg.Status = 'Duplicate exists';
  case '89'
    cfg.Status = 'No space';
  case {'8b', '8B'}
    cfg.Status = 'Not found';
  otherwise
    warning(getString(message('lrwpan:ZigBee:ZCLInvalidValue', 'Status')));
end
