#include "app/framework/include/af.h"
#include "app/framework/plugin/green-power-common/green-power-common.h"
#include "app/framework/plugin/green-power-server/green-power-server.h"

extern void emberGpSinkTableClearAll(void);

#define  GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ADDITIONAL_INFO_LEN  36
#ifndef EMBER_AF_GENERATE_CLI
#error The Green Power Client plugin is not compatible with the legacy CLI.
#endif
extern uint8_t newKey[EMBER_ENCRYPTION_KEY_SIZE];
#if 0
//XXXEZSP
void emberHmacAesHash(const uint8_t *key,
                      const uint8_t *data,
                      uint8_t dataLength,
                      uint8_t *result);

void hmacTest()
{
  uint8_t i;
  EmberKeyData linkKey = { {
                             0x01, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0d
                           } };

  EmberKeyData key2 = { {
                          0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
                        } };

  uint8_t id[] = { 0x21, 0x43, 0x65, 0x87 };

  uint8_t result[16];
  emberHmacAesHash(linkKey.contents, (uint8_t *)"ZGP", 3, result);
  emberHmacAesHash(key2.contents, id, 4, result);
  for (i = 0; i < 16; i++) {
    emberAfCorePrint("%x", result[i]);
  }
}
#endif

void emberAfPluginGreenPowerServerCryptoTest(void)
{
  uint8_t payload[] = { 0, // length
                        0, //deviceID,
                        EMBER_AF_GP_GPD_COMMISSIONING_OPTIONS_EXTENDED_OPTIONS_FIELD,
                        (EMBER_AF_GP_GPD_COMMISSIONING_EXTENDED_OPTIONS_GPD_KEY_PRESENT
                         | EMBER_AF_GP_GPD_COMMISSIONING_EXTENDED_OPTIONS_GPD_KEY_ENCRYPTION)
                        >> 8,
                        0x7D,
                        0x17,
                        0x7B,
                        0xD2,
                        0x9E,
                        0xA0,
                        0xFD,
                        0xA6, //key
                        0xB0,
                        0x17,
                        0x03,
                        0x65,
                        0x87,
                        0xDC,
                        0x26,
                        0x00, //key
  };

  emberAfGreenPowerClusterGpCommissioningNotificationCallback(0,
                                                              0x12345678,
                                                              NULL,
                                                              0, //endpoint
                                                              0,
                                                              0xF2, //GPD_COMMAND_COMMISSIONING,
                                                              payload,
                                                              0,
                                                              0,
                                                              0);

  emberAfCorePrint("key is:");
  //TODO fix this to make a real test
  //for(i=0;i<EMBER_ENCRYPTION_KEY_SIZE;i++)
  //  emberAfCorePrint("%x",newKey[i]);

  //hmacTest();
}

void emberAfPluginGreenPowerServerCommissioningMode(void)
{
  if (emberUnsignedCommandArgument(0)) {
    emberAfGreenPowerClusterGpSinkCommissioningModeCallback(0x09,    //options)
                                                            0xFFFF,    //addr
                                                            0xFFFF,    //addr
                                                            0xFF); //all endpoints
  } else {
    emberAfGreenPowerClusterGpSinkCommissioningModeCallback(0x00,    //options)
                                                            0xFFFF,    //addr
                                                            0xFFFF,    //addr
                                                            0xFF); //all endpoints
  }
}

void emberAfPluginGreenPowerServerCliClearAdditionalInfoBlockTable(void)
{
  embGpClearAdditionalInfoBlockTable();
}

void emberAfPluginGreenPowerServerCliClearCustomizedTable(void)
{
  emGpClearCustomizedTable();
}

void emberAfPluginGreenPowerServerCliClearTranslationTranslationTable(void)
{
  emGpTransTableClearTranslationTable();
}

void emberAfPluginGreenPowerServerCliClearAdditionalInfoBlockTableEntry()
{
  uint8_t index = emberUnsignedCommandArgument(0);
  EmberGpTranslationTableAdditionalInfoBlockField *additionalInfoTable = emGpGetAdditionalInfoTable();
  if (index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_ADDITIONALINFO_TABLE_SIZE
      && additionalInfoTable->validEntry[index]) {
    additionalInfoTable->validEntry[index]--;
    if (additionalInfoTable->validEntry[index] == 0) {
      MEMSET(&(additionalInfoTable->additionalInfoBlock[index]), 0x00, sizeof(EmberGpTranslationTableAdditionalInfoBlockOptionRecordField));
      additionalInfoTable->totlaNoOfEntries--;
    }
    emGpSetAdditionalInfoBlockTableEntry(index);
  }
}

void emberAfPluginGreenPowerServerCliClearCustomizedTableEntry()
{
  uint8_t index = emberUnsignedCommandArgument(0);
  EmberAfGreenPowerServerGpdSubTranslationTableEntry* customizedTable = emGpGetCustomizedTable();
  if (index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_CUSTOMIZED_GPD_TRANSLATION_TABLE_SIZE) {
    MEMSET(&(customizedTable[index]),
           0x00,
           sizeof(EmberAfGreenPowerServerGpdSubTranslationTableEntry));
    emGpSetCustomizedTableEntry(index);
  }
}

void emberAfPluginGreenPowerServerCliClearTranslationTableEntry(void)
{
  uint8_t index = emberUnsignedCommandArgument(0);
  EmGpCommandTranslationTable * translationtable = emGpTransTableGetTranslationTable();
  if ((index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_TRANSLATION_TABLE_SIZE) && (translationtable->totalNoOfEntries > 0)) {
    MEMSET(&translationtable->TableEntry[index], 0x00, sizeof(EmGpCommandTranslationTableEntry));
    translationtable->TableEntry[index].entry = NO_ENTRY;
    translationtable->TableEntry[index].offset = 0xFF;
    translationtable->totalNoOfEntries--;
    emGpSetTranslationTableEntry(index);
  }
}

void emberAfPluginGreenPowerServerCliSetAdditionalInfoBlockTableEntry(void)
{
  EmberGpTranslationTableAdditionalInfoBlockField *additionalInfoTable = emGpGetAdditionalInfoTable();
  uint8_t index = emberUnsignedCommandArgument(0);
  uint8_t gpdCommandId = emberUnsignedCommandArgument(1);
  uint8_t additionalInfoLength = emberUnsignedCommandArgument(2);
  uint8_t additionalInfoBlockIn[GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ADDITIONAL_INFO_LEN];
  EmberGpTranslationTableAdditionalInfoBlockOptionRecordField additionalInfoBlockOut;

  if (additionalInfoLength < GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ADDITIONAL_INFO_LEN) {
    emberCopyStringArgument(3,
                            additionalInfoBlockIn,
                            additionalInfoLength,
                            false);
  }
  if (index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_ADDITIONALINFO_TABLE_SIZE) {
    emGpCopyAdditionalInfoBlockArrayToStructure(additionalInfoBlockIn, &additionalInfoBlockOut, gpdCommandId);
    MEMCOPY(&additionalInfoTable->additionalInfoBlock[index],
            &additionalInfoBlockOut,
            sizeof(EmberGpTranslationTableAdditionalInfoBlockOptionRecordField));
    additionalInfoTable->validEntry[index]++;
    additionalInfoTable->totlaNoOfEntries++;
    emGpSetAdditionalInfoBlockTableEntry(index);
  }
}

void emberAfPluginGreenPowerServerCliSetCustomizedTableEntry(void)
{
  EmberAfGreenPowerServerGpdSubTranslationTableEntry customizedTableEntryIn;
  uint8_t index = emberUnsignedCommandArgument(0);
  customizedTableEntryIn.validEntry = true;
  customizedTableEntryIn.gpdCommand    = emberUnsignedCommandArgument(1);
  customizedTableEntryIn.endpoint    = emberUnsignedCommandArgument(2);
  customizedTableEntryIn.zigbeeProfile = emberUnsignedCommandArgument(3);
  customizedTableEntryIn.zigbeeCluster = emberUnsignedCommandArgument(4);
  customizedTableEntryIn.serverClient  = emberUnsignedCommandArgument(5);
  customizedTableEntryIn.zigbeeCommandId = emberUnsignedCommandArgument(6);
  customizedTableEntryIn.payloadSrc    = emberUnsignedCommandArgument(7);
  uint8_t payloadLength = emberUnsignedCommandArgument(8);
  if (payloadLength < EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN) {
    emberCopyStringArgument(9,
                            customizedTableEntryIn.zclPayloadDefault,
                            EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN,
                            false);
  }
  if (index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_CUSTOMIZED_GPD_TRANSLATION_TABLE_SIZE) {
    EmberAfGreenPowerServerGpdSubTranslationTableEntry* customizedTable = emGpGetCustomizedTable();
    MEMCOPY(&(customizedTable[index]),
            &customizedTableEntryIn,
            sizeof(EmberAfGreenPowerServerGpdSubTranslationTableEntry));
    emGpSetCustomizedTableEntry(index);
  }
}

void emberAfPluginGreenPowerServerCliSetTranslationTable(void)
{
  //assign default values wherever possible since CLI has a limitation on number of arguments
  uint8_t retval;
  uint8_t index = emberUnsignedCommandArgument(0);
  uint16_t options = emberUnsignedCommandArgument(1);
  bool infoBlockPresent = ((options >> 0x03) & 0x01);
  uint8_t gpApplicationId = (options & 0x07);
  uint32_t  gpdSrcId = 0;
  EmberEUI64 gpdIeeeAddr;
  uint8_t gpdEndpoint = 1;
  uint8_t zbEndpoint = emberUnsignedCommandArgument(5);
  uint8_t gpdCommandId = emberUnsignedCommandArgument(6);
  uint16_t zigbeeProfile = emberUnsignedCommandArgument(7);
  uint16_t zigbeeCluster = emberUnsignedCommandArgument(8);
  uint8_t  zigbeeCommandId = emberUnsignedCommandArgument(9);
  uint8_t payloadSrc  = EMBER_AF_GREEN_POWER_ZCL_PAYLOAD_SRC_PRECONFIGURED;//emberUnsignedCommandArgument(10);
  uint8_t payloadLength = emberUnsignedCommandArgument(10);
  uint8_t payload[EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN];
  uint8_t additionalInfoLength = emberUnsignedCommandArgument(12);
  uint8_t additionalInfoBlockIn[GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ADDITIONAL_INFO_LEN];
  EmberGpTranslationTableAdditionalInfoBlockOptionRecordField additionalInfoBlockOut;

  if (index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_TRANSLATION_TABLE_SIZE) {
    if (gpApplicationId == EMBER_GP_APPLICATION_IEEE_ADDRESS) {
      emberCopyBigEndianEui64Argument(2, gpdIeeeAddr);
      gpdEndpoint = emberUnsignedCommandArgument(3);
    } else if (gpApplicationId == EMBER_GP_APPLICATION_SOURCE_ID) {
      gpdSrcId = emberUnsignedCommandArgument(4);
    }
    if (payloadLength < EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN) {
      emberCopyStringArgument(11,
                              payload,
                              EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN,
                              false);
    }

    if ( infoBlockPresent) {
      if (additionalInfoLength < GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ADDITIONAL_INFO_LEN) {
        emberCopyStringArgument(13,
                                additionalInfoBlockIn,
                                additionalInfoLength,
                                false);
      }
      emGpCopyAdditionalInfoBlockArrayToStructure(additionalInfoBlockIn, &additionalInfoBlockOut, gpdCommandId);
    }
    retval = emGpTransTableAddTranslationTableEntryUpdateCommand(index,
                                                                 infoBlockPresent,
                                                                 gpApplicationId,
                                                                 gpdSrcId,
                                                                 gpdIeeeAddr,
                                                                 gpdCommandId,
                                                                 gpdEndpoint,
                                                                 zbEndpoint,
                                                                 zigbeeProfile,
                                                                 zigbeeCluster,
                                                                 zigbeeCommandId,
                                                                 payloadLength,
                                                                 payload,
                                                                 payloadSrc,
                                                                 additionalInfoLength,
                                                                 &additionalInfoBlockOut);
    if (retval != GP_TRANSLATION_TABLE_STATUS_SUCCESS) {
      if ( retval == GP_TRANSLATION_TABLE_STATUS_ENTRY_NOT_EMPTY ) {
        emberAfGreenPowerClusterPrintln("Entry @Index [%d] is not empty, trying replace", index);
        retval = emGpTransTableReplaceTranslationTableEntryUpdateCommand(index,
                                                                         infoBlockPresent,
                                                                         gpApplicationId,
                                                                         gpdSrcId,
                                                                         gpdIeeeAddr,
                                                                         gpdCommandId,
                                                                         gpdEndpoint,
                                                                         zbEndpoint,
                                                                         zigbeeProfile,
                                                                         zigbeeCluster,
                                                                         zigbeeCommandId,
                                                                         payloadLength,
                                                                         payload,
                                                                         payloadSrc,
                                                                         additionalInfoLength,
                                                                         &additionalInfoBlockOut);
        emberAfGreenPowerClusterPrintln("Replace Ststus  = %d ", retval);
      } else if ( retval == GP_TRANSLATION_TABLE_STATUS_PARAM_DOES_NOT_MATCH) {
        emberAfGreenPowerClusterPrintln("Parameter does not match @Index [%d]", index);
        emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); //send failure notification immediately
      }
    }
  } else {
    emberAfGreenPowerClusterPrintln("invalid Translation Table index!");
  }
}

void emberAfPluginGreenPowerServerCliAdditionalInfoBlockTablePrint(uint8_t addInfoOffset)
{
  uint8_t gpdCommandId = EMBER_ZCL_GP_GPDF_8BITS_VECTOR_PRESS;
  EmberGpTranslationTableAdditionalInfoBlockField *additionalInfoTable = emGpGetAdditionalInfoTable();
  EmberGpTranslationTableAdditionalInfoBlockOptionRecordField * addInfo = &(additionalInfoTable->additionalInfoBlock[addInfoOffset]);
  if (addInfo->totalLengthOfAddInfoBlock > 4) {
    gpdCommandId = EMBER_ZCL_GP_GPDF_COMPACT_ATTRIBUTE_REPORTING;
  }
  emGpPrintAdditionalInfoBlock(gpdCommandId, addInfoOffset);
}
void emberAfPluginGreenPowerServerCliCustomizedTablePrint(void)
{
  EmberAfGreenPowerServerGpdSubTranslationTableEntry  * entry = NULL;
  // print customized table.
  emberAfGreenPowerClusterPrintln("Print Sink Proxy Server Customized Translation Table:");
  emberAfGreenPowerClusterPrintln("index:\tvalid\topt\tgpEp\tieee\t\t\tsrcId\t\tep\tgpdCommandId\tprofile\tcluster\tcmdId\tpayloadType\tpayload");
  uint8_t index;
  uint8_t len;
  EmberAfGreenPowerServerGpdSubTranslationTableEntry* customizedTable = emGpGetCustomizedTable();
  for (index = 0; index < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_CUSTOMIZED_GPD_TRANSLATION_TABLE_SIZE; index++) {
    entry = &customizedTable[index];
    emberAfGreenPowerClusterPrint("%d\t0x%X\t\t0x%2X\t0x%2X\t0x%X\t",
                                  entry->endpoint,
                                  entry->gpdCommand,
                                  entry->zigbeeProfile,
                                  entry->zigbeeCluster,
                                  entry->zigbeeCommandId);
    emberAfGreenPowerClusterPrint("%X\t\t0x", entry->payloadSrc);

    len = emberAfStringLength(entry->zclPayloadDefault);
    if (len >= EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN) {
      len = EMBER_AF_GREEN_POWER_SERVER_TRANSLATION_TABLE_ENTRY_ZCL_PAYLOAD_LEN - 1;
    }
    emberAfPrintBuffer(EMBER_AF_PRINT_APP, entry->zclPayloadDefault, len + 1, false);

    emberAfGreenPowerClusterPrint(" \t");
    emberAfGreenPowerClusterPrintln("");
  }
}

void emberAfPluginGreenPowerServerCliTranslationTablePrint(void)
{
  uint8_t status;
  EmberAfGreenPowerServerGpdSubTranslationTableEntry TranslationTableEntry;
  EmGpCommandTranslationTable * emGptranslationtable = emGpTransTableGetTranslationTable();
  if (!(emGptranslationtable->totalNoOfEntries)) {
    emberAfGreenPowerClusterPrintln("translation table is Empty");
  } else {
    emberAfGreenPowerClusterPrintln("\nIndex Valid AppId Ieee                Ep gpdSrc   gdpCmd zEp zProf zCluster zCmd EType Info ");
    for (uint8_t entryIndex = 0; entryIndex < EMBER_AF_PLUGIN_GREEN_POWER_SERVER_TRANSLATION_TABLE_SIZE; entryIndex++ ) {
      if (emGptranslationtable->TableEntry[entryIndex].entry == NO_ENTRY) {
        continue;
      }
      status = emGpTransTableGetTranslationTableEntry(entryIndex, &TranslationTableEntry);
      if (status == GP_TRANSLATION_TABLE_STATUS_SUCCESS) {
        emberAfGreenPowerClusterPrint("%x    ", entryIndex);
        emberAfGreenPowerClusterPrint("%x    ", TranslationTableEntry.validEntry);
        emberAfGreenPowerClusterPrint("%x    ", emGptranslationtable->TableEntry[entryIndex].gpAddr.applicationId);
        if ((emGptranslationtable->TableEntry[entryIndex].gpAddr.applicationId & EMBER_AF_GP_NOTIFICATION_OPTION_APPLICATION_ID) == EMBER_GP_APPLICATION_IEEE_ADDRESS) {
          emberAfPrintBigEndianEui64(emGptranslationtable->TableEntry[entryIndex].gpAddr.id.gpdIeeeAddress);
          emberAfGreenPowerClusterPrint(" ");
          emberAfGreenPowerClusterPrint("%x ", emGptranslationtable->TableEntry[entryIndex].gpAddr.endpoint);
          emberAfGreenPowerClusterPrint("         ");
        } else {
          emberAfGreenPowerClusterPrint("                       ");
          emberAfGreenPowerClusterPrint("%4x ", emGptranslationtable->TableEntry[entryIndex].gpAddr.id.sourceId);
        }
        emberAfGreenPowerClusterPrint("%x     ", TranslationTableEntry.gpdCommand);
        emberAfGreenPowerClusterPrint("%x  ", TranslationTableEntry.endpoint);
        emberAfGreenPowerClusterPrint("%2x  ", TranslationTableEntry.zigbeeProfile);
        emberAfGreenPowerClusterPrint("%2x     ", TranslationTableEntry.zigbeeCluster);
        emberAfGreenPowerClusterPrint("%x   ", TranslationTableEntry.zigbeeCommandId);
        emberAfGreenPowerClusterPrint("%x    ", emGptranslationtable->TableEntry[entryIndex].entry);
        emberAfGreenPowerClusterPrint("%x   ", emGptranslationtable->TableEntry[entryIndex].infoBlockPresent);
        if (emGptranslationtable->TableEntry[entryIndex].infoBlockPresent == true) {
          emGpPrintAdditionalInfoBlock(TranslationTableEntry.gpdCommand, emGptranslationtable->TableEntry[entryIndex].additionalInfoOffset);
        }
        emberAfGreenPowerClusterPrint("\n");
      } else {
        emberAfGreenPowerClusterPrintln("[%s] emGpTransTableGetTranslationTable FAILED", __FUNCTION__);
      }
    }
    emberAfGreenPowerClusterPrint("\n");
  }
}

void emberAfPluginGreenPowerServerCliClearSinkTable(void)
{
  emberGpSinkTableClearAll();
}

void emberAfPluginGreenPowerServerSinkTablePrint(void)
{
  emberAfGreenPowerClusterPrintln("\n\rSt Optn Ap SourceId Ep Dv Alis Gr So FrameCtr");
  for (uint8_t index = 0; index < EMBER_GP_SINK_TABLE_SIZE; index++) {
    EmberGpSinkTableEntry entry = { 0 };
    //EmberStatus status =
    emberGpSinkTableGetEntry(index, &entry);
    emberAfGreenPowerClusterPrintln("%x %2x %x %4x %x %x %2x %x %x %4x",
                                    entry.status,
                                    entry.options,
                                    entry.gpd.applicationId,
                                    entry.gpd.id.sourceId,
                                    entry.gpd.endpoint,
                                    entry.deviceId,
                                    entry.assignedAlias,
                                    entry.groupcastRadius,
                                    entry.securityOptions,
                                    entry.gpdSecurityFrameCounter);
  }
}
void emberAfPluginGreenPowerServerCliSinkTablePrint(void)
{
  emberAfPluginGreenPowerServerSinkTablePrint();
}
