/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

// THIS FILE IS GENERATED BY ZAP

#include <cinttypes>
#include <cstdint>

#include <app-common/zap-generated/callback.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app-common/zap-generated/ids/Commands.h>
#include <app/CommandHandler.h>
#include <app/InteractionModelEngine.h>
#include <app/util/util.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/support/TypeTraits.h>

namespace chip {
namespace app {

// Cluster specific command parsing

namespace Clusters {

namespace GroupKeyManagement {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::KeySetWrite::Id: {
      Commands::KeySetWrite::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfGroupKeyManagementClusterKeySetWriteCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::KeySetRead::Id: {
      Commands::KeySetRead::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfGroupKeyManagementClusterKeySetReadCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::KeySetRemove::Id: {
      Commands::KeySetRemove::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfGroupKeyManagementClusterKeySetRemoveCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::KeySetReadAllIndices::Id: {
      Commands::KeySetReadAllIndices::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfGroupKeyManagementClusterKeySetReadAllIndicesCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace GroupKeyManagement

namespace Identify {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::Identify::Id: {
      Commands::Identify::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfIdentifyClusterIdentifyCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace Identify

namespace OtaSoftwareUpdateRequestor {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::AnnounceOTAProvider::Id: {
      Commands::AnnounceOTAProvider::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOtaSoftwareUpdateRequestorClusterAnnounceOTAProviderCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace OtaSoftwareUpdateRequestor

namespace OperationalCredentials {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::AttestationRequest::Id: {
      Commands::AttestationRequest::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterAttestationRequestCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::CertificateChainRequest::Id: {
      Commands::CertificateChainRequest::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterCertificateChainRequestCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::CSRRequest::Id: {
      Commands::CSRRequest::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfOperationalCredentialsClusterCSRRequestCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::AddNOC::Id: {
      Commands::AddNOC::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfOperationalCredentialsClusterAddNOCCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::UpdateNOC::Id: {
      Commands::UpdateNOC::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfOperationalCredentialsClusterUpdateNOCCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::UpdateFabricLabel::Id: {
      Commands::UpdateFabricLabel::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterUpdateFabricLabelCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::RemoveFabric::Id: {
      Commands::RemoveFabric::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfOperationalCredentialsClusterRemoveFabricCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::AddTrustedRootCertificate::Id: {
      Commands::AddTrustedRootCertificate::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SetVIDVerificationStatement::Id: {
      Commands::SetVIDVerificationStatement::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterSetVIDVerificationStatementCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SignVIDVerificationRequest::Id: {
      Commands::SignVIDVerificationRequest::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfOperationalCredentialsClusterSignVIDVerificationRequestCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace OperationalCredentials

namespace TimeSynchronization {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::SetUTCTime::Id: {
      Commands::SetUTCTime::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfTimeSynchronizationClusterSetUTCTimeCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SetTrustedTimeSource::Id: {
      Commands::SetTrustedTimeSource::DecodableType commandData;
      TLVError =
          commandData.Decode(aDataTlv, apCommandObj->GetAccessingFabricIndex());
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled =
            emberAfTimeSynchronizationClusterSetTrustedTimeSourceCallback(
                apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SetTimeZone::Id: {
      Commands::SetTimeZone::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfTimeSynchronizationClusterSetTimeZoneCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SetDSTOffset::Id: {
      Commands::SetDSTOffset::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfTimeSynchronizationClusterSetDSTOffsetCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::SetDefaultNTP::Id: {
      Commands::SetDefaultNTP::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfTimeSynchronizationClusterSetDefaultNTPCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace TimeSynchronization

namespace ValveConfigurationAndControl {

Protocols::InteractionModel::Status
DispatchServerCommand(CommandHandler *apCommandObj,
                      const ConcreteCommandPath &aCommandPath,
                      TLV::TLVReader &aDataTlv) {
  CHIP_ERROR TLVError = CHIP_NO_ERROR;
  bool wasHandled = false;
  {
    switch (aCommandPath.mCommandId) {
    case Commands::Open::Id: {
      Commands::Open::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfValveConfigurationAndControlClusterOpenCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    case Commands::Close::Id: {
      Commands::Close::DecodableType commandData;
      TLVError = DataModel::Decode(aDataTlv, commandData);
      if (TLVError == CHIP_NO_ERROR) {
        wasHandled = emberAfValveConfigurationAndControlClusterCloseCallback(
            apCommandObj, aCommandPath, commandData);
      }
      break;
    }
    default: {
      // Unrecognized command ID, error status will apply.
      ChipLogError(Zcl,
                   "Unknown command " ChipLogFormatMEI
                   " for cluster " ChipLogFormatMEI,
                   ChipLogValueMEI(aCommandPath.mCommandId),
                   ChipLogValueMEI(aCommandPath.mClusterId));
      return Protocols::InteractionModel::Status::UnsupportedCommand;
    }
    }
  }

  if (CHIP_NO_ERROR != TLVError || !wasHandled) {
    ChipLogProgress(Zcl,
                    "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT,
                    TLVError.Format());
    return Protocols::InteractionModel::Status::InvalidCommand;
  }

  // We use success as a marker that no special handling is required
  // This is to avoid having a std::optional which uses slightly more code.
  return Protocols::InteractionModel::Status::Success;
}

} // namespace ValveConfigurationAndControl

} // namespace Clusters

void DispatchSingleClusterCommand(const ConcreteCommandPath &aCommandPath,
                                  TLV::TLVReader &aReader,
                                  CommandHandler *apCommandObj) {
  Protocols::InteractionModel::Status errorStatus =
      Protocols::InteractionModel::Status::Success;

  switch (aCommandPath.mClusterId) {
  case Clusters::GroupKeyManagement::Id:
    errorStatus = Clusters::GroupKeyManagement::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  case Clusters::Identify::Id:
    errorStatus = Clusters::Identify::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  case Clusters::OtaSoftwareUpdateRequestor::Id:
    errorStatus = Clusters::OtaSoftwareUpdateRequestor::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  case Clusters::OperationalCredentials::Id:
    errorStatus = Clusters::OperationalCredentials::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  case Clusters::TimeSynchronization::Id:
    errorStatus = Clusters::TimeSynchronization::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  case Clusters::ValveConfigurationAndControl::Id:
    errorStatus = Clusters::ValveConfigurationAndControl::DispatchServerCommand(
        apCommandObj, aCommandPath, aReader);
    break;
  default:
    ChipLogError(Zcl, "Unknown cluster " ChipLogFormatMEI,
                 ChipLogValueMEI(aCommandPath.mClusterId));
    errorStatus = Protocols::InteractionModel::Status::UnsupportedCluster;
    break;
  }

  if (errorStatus != Protocols::InteractionModel::Status::Success) {
    apCommandObj->AddStatus(aCommandPath, errorStatus);
  }
}

} // namespace app
} // namespace chip
