#include "sysmgr.h"
#include <nrfx.h>
#include <nrf_delay.h>
#include <drv_rtc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "nrf_spi.h"
#include "nrf_drv_spi.h"
#include "nrf_pwr_mgmt.h"

#include "main.h"



stSystemTimer SystemTimer;
stSystemManager SystemManager;


extern const nrf_drv_spi_t spi;  /**< SPI instance. */
extern volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
uint8_t       m_tx_buf[64];           /**< TX buffer. */
uint8_t       m_rx_buf[64];    /**< RX buffer. */
uint8_t m_length;        /**< Transfer length. */


RegMacPool_t RegMacPool;

const char *fds_err_str(ret_code_t ret)
{
    /* Array to map FDS return values to strings. */
    static char const * err_str[] =
    {
        "FDS_ERR_OPERATION_TIMEOUT",
        "FDS_ERR_NOT_INITIALIZED",
        "FDS_ERR_UNALIGNED_ADDR",
        "FDS_ERR_INVALID_ARG",
        "FDS_ERR_NULL_ARG",
        "FDS_ERR_NO_OPEN_RECORDS",
        "FDS_ERR_NO_SPACE_IN_FLASH",
        "FDS_ERR_NO_SPACE_IN_QUEUES",
        "FDS_ERR_RECORD_TOO_LARGE",
        "FDS_ERR_NOT_FOUND",
        "FDS_ERR_NO_PAGES",
        "FDS_ERR_USER_LIMIT_REACHED",
        "FDS_ERR_CRC_CHECK_FAILED",
        "FDS_ERR_BUSY",
        "FDS_ERR_INTERNAL",
    };

    return err_str[ret - NRF_ERROR_FDS_ERR_BASE];
}


void ParkSysInit()
{
	SystemTimer.TMR_SYS_OFF = 3;
}

void ParkPowerOff()
{
  SystemTimer.TMR_SYS_OFF = 0;
}






/* Dummy configuration data. */
static configuration_t m_dummy_cfg =
{
    .config1_on  = false,
    .config2_on  = true,
    .boot_count  = 0x0,
    .device_name = "dummy",
};





static void record_write(uint32_t fid,
                         uint32_t key,
                         void const * p_data,
                         uint32_t len)
{
    fds_record_t const rec =
    {
        .file_id           = fid,
        .key               = key,
        .data.p_data       = p_data,
        .data.length_words = (len + 3) / sizeof(uint32_t)
    };

    NRF_LOG_INFO(
                    "writing record to flash...\n"
                    "file: 0x%x, key: 0x%x, \"%s\", len: %u bytes\n",
                    fid, key, p_data, len);

	   fds_record_desc_t desc	= {0};
	desc.record_id = 1;

    //ret_code_t rc = fds_record_write(NULL, &rec);
    ret_code_t rc = fds_record_write(&desc, &rec);
    if (rc != NRF_SUCCESS)
    {
        NRF_LOG_INFO(
                        "error: fds_record_write() returned %s.\n",
                        fds_err_str(rc));
    }
}





static void record_update( configuration_t const * p_cfg)
{
    fds_record_desc_t desc = {0};
    fds_find_token_t  ftok = {0};

    if (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &ftok) == NRF_SUCCESS)
    {
        fds_record_t const rec =
        {
            .file_id           = CONFIG_FILE,
            .key               = CONFIG_REC_KEY,
            .data.p_data       = p_cfg,
            .data.length_words = (sizeof(configuration_t) + 3) / sizeof(uint32_t)
        };

        ret_code_t rc = fds_record_update(&desc, &rec);
        if (rc != NRF_SUCCESS)
        {
            NRF_LOG_INFO( "error: fds_record_update() returned %s.\n",
                            fds_err_str(rc));
        }
    }
    else
    {
        NRF_LOG_INFO( "error: could not find config file.\n");
    }
}


static void record_delete( uint32_t fid, uint32_t key)
{
    fds_find_token_t tok   = {0};
    fds_record_desc_t desc = {0};

    NRF_LOG_INFO( 
                    "deleting record...\n"
                    "file: 0x%x, key: 0x%x\n",
                    fid,
                    key);

    if (fds_record_find(fid, key, &desc, &tok) == NRF_SUCCESS)
    {
        ret_code_t rc = fds_record_delete(&desc);
        if (rc != NRF_SUCCESS)
        {
            NRF_LOG_INFO( 
                            "error: fds_record_delete() returned %s.\n", fds_err_str(rc));

            return;
        }

        NRF_LOG_INFO(  "record id: 0x%x\n", desc.record_id);
    }
    else
    {
        NRF_LOG_INFO(  "error: record not found!\n");
    }
}


bool record_delete_next(void)
{
    fds_find_token_t  tok   = {0};
    fds_record_desc_t desc  = {0};

    if (fds_record_iterate(&desc, &tok) == NRF_SUCCESS)
    {
        ret_code_t rc = fds_record_delete(&desc);
        if (rc != NRF_SUCCESS)
        {
            return false;
        }

        return true;
    }
    else
    {
        /* No records left to delete. */
        return false;
    }
}




static void print_cfg_cmd( size_t argc, char ** argv)
{
    fds_record_desc_t desc = {0};
    fds_find_token_t  tok  = {0};

    while (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok) == NRF_SUCCESS)
    {
        ret_code_t rc;
        fds_flash_record_t frec = {0};

        rc = fds_record_open(&desc, &frec);
        switch (rc)
        {
            case NRF_SUCCESS:
                break;

            case FDS_ERR_CRC_CHECK_FAILED:
                NRF_LOG_INFO( "error: CRC check failed!\n");
                continue;

            case FDS_ERR_NOT_FOUND:
                NRF_LOG_INFO( "error: record not found!\n");
                continue;

            default:
            {
                NRF_LOG_INFO(
                                "error: unexpecte error %s.\n",
                                fds_err_str(rc));

                continue;
            }
        }

        configuration_t * p_cfg = (configuration_t *)(frec.p_data);

        NRF_LOG_INFO(
                        "config1:\t%s\n"
                        "config2:\t%s\n"
                        "boot count:\t%u\n"
                        "device name:\t%s\n",
                        p_cfg->config1_on ? "on" : "off",
                        p_cfg->config2_on ? "on" : "off",
                        p_cfg->boot_count,
                        p_cfg->device_name);

        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);
    }
}





static void print_all_cmd( )
{
    fds_find_token_t tok   = {0};
    fds_record_desc_t desc = {0};
    uint8_t *data;

    NRF_LOG_INFO("rec. id \t file id \t rec. key \t length");

    while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
    {
        ret_code_t rc;
        fds_flash_record_t frec = {0};

        rc = fds_record_open(&desc, &frec);
        switch (rc)
        {
            case NRF_SUCCESS:
                break;

            case FDS_ERR_CRC_CHECK_FAILED:
                NRF_LOG_INFO(  "error: CRC check failed!\n");
                continue;

            case FDS_ERR_NOT_FOUND:
                NRF_LOG_INFO(  "error: record not found!\n");
                continue;

            default:
            {
                NRF_LOG_INFO("error: unexpecte error %s.\n", fds_err_str(rc));

                continue;
            }
        }

        uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);

        NRF_LOG_INFO(   " 0x%04x"
                        "\t 0x%04x"
                        "\t 0x%04x"
                        "\t %4u bytes\t",
                        frec.p_header->record_id,
                        frec.p_header->file_id,
                        frec.p_header->record_key,
                        len);

        data = (uint8_t *) frec.p_data;
        for (uint8_t i=0;i<len;i++)
        {
                NRF_LOG_RAW_INFO( "%c",data[i]);
        }
        NRF_LOG_INFO("\n");



        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);
    }
}







void RegMac(char* str)
{

  print_all_cmd();
  NRF_LOG_RAW_INFO("Registration MAC : %s\n", str);
  
  RegMacPool.Count++;
  record_write(1, RegMacPool.Count, str, 12);

  print_all_cmd();

}



void RegMacDelteAll()
{
    bool next;

#if 1
  while(1)
  {  
       next = record_delete_next();
        if (!next)
        {
            NRF_LOG_INFO("No records left to delete.");
            break;
        } 

		nrf_delay_ms(20);
  }

#endif

  memset( &RegMacPool, 0, sizeof(RegMacPool));


}




void LoadRegMac()
{
    fds_find_token_t tok   = {0};
    fds_record_desc_t desc = {0};
    uint8_t *data;
    char tmpBuf[15];

    NRF_LOG_INFO( 
                    "\nrec. id\t"
                    "\tfile id\t"
                    "\trec. key"
                    "\tlength\tmac\n");

    while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
    {
        ret_code_t rc;
        fds_flash_record_t frec = {0};

        rc = fds_record_open(&desc, &frec);
		
        switch (rc)
        {
            case NRF_SUCCESS:
                break;

            case FDS_ERR_CRC_CHECK_FAILED:
                NRF_LOG_INFO("error: CRC check failed!\n");
                continue;

            case FDS_ERR_NOT_FOUND:
                NRF_LOG_INFO("error: record not found!\n");
                continue;

            default:
            {
                NRF_LOG_INFO("error: unexpecte error %s.\n", fds_err_str(rc));
                continue;
            }
        }

        uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);

        NRF_LOG_RAW_INFO( 
                        " 0x%04x\t"
                        "\t 0x%04x\t"
                        "\t 0x%04x\t"
                        "\t %4u bytes\t",
                        frec.p_header->record_id,
                        frec.p_header->file_id,
                        frec.p_header->record_key,
                        len);

        data = (uint8_t *) frec.p_data;


        if( RegMacPool.Count >= 5 )
        {
            NRF_LOG_RAW_INFO( "Mac Pool Over\n");

            return;
        }
        
        RegMacPool.Mac[RegMacPool.Count][12] = 0;
        strncpy( RegMacPool.Mac[RegMacPool.Count++], data, 12);
        //for (uint8_t i=0;i<len;i++)
        {
        //        NRF_LOG_RAW_INFO( "%c",data[i]);
        }
        //NRF_LOG_RAW_INFO( "\n");
         NRF_LOG_RAW_INFO( "%s\n",RegMacPool.Mac[RegMacPool.Count-1]);

        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);
    }
}






void LoadReceiverMac()
{
    fds_find_token_t tok   = {0};
    fds_record_desc_t desc = {0};
    uint8_t *data;
    char tmpBuf[15];

    NRF_LOG_INFO( 
                    "\nrec. id\t"
                    "\tfile id\t"
                    "\trec. key"
                    "\tlength\tmac\n");

    while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
    {
        ret_code_t rc;
        fds_flash_record_t frec = {0};

        rc = fds_record_open(&desc, &frec);
		
        switch (rc)
        {
            case NRF_SUCCESS:
                break;

            case FDS_ERR_CRC_CHECK_FAILED:
                NRF_LOG_INFO("error: CRC check failed!\n");
                continue;

            case FDS_ERR_NOT_FOUND:
                NRF_LOG_INFO("error: record not found!\n");
                continue;

            default:
            {
                NRF_LOG_INFO("error: unexpecte error %s.\n", fds_err_str(rc));
                continue;
            }
        }

        uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);

        NRF_LOG_RAW_INFO( 
                        " 0x%04x\t"
                        "\t 0x%04x\t"
                        "\t 0x%04x\t"
                        "\t %4u bytes\t",
                        frec.p_header->record_id,
                        frec.p_header->file_id,
                        frec.p_header->record_key,
                        len);

        data = (uint8_t *) frec.p_data;
		strncpy( SystemManager.StrRegPeerAddr, data, 12);
		strncpy( tmpBuf, SystemManager.StrRegPeerAddr, 12);
		
		SystemManager.StrRegPeerAddr[12] = 0;
		tmpBuf[12] = 0;
		 NRF_LOG_RAW_INFO( "%s\n",SystemManager.StrRegPeerAddr);

		SystemManager.RegPeerAddr[5] = (uint8_t)strtol(&tmpBuf[10], NULL, 16); tmpBuf[10] = 0;
		SystemManager.RegPeerAddr[4] = (uint8_t)strtol(&tmpBuf[8], NULL, 16); tmpBuf[8] = 0;
		SystemManager.RegPeerAddr[3] = (uint8_t)strtol(&tmpBuf[6], NULL, 16); tmpBuf[6] = 0;
		SystemManager.RegPeerAddr[2] = (uint8_t)strtol(&tmpBuf[4], NULL, 16); tmpBuf[4] = 0;
		SystemManager.RegPeerAddr[1] = (uint8_t)strtol(&tmpBuf[2], NULL, 16); tmpBuf[2] = 0;
		SystemManager.RegPeerAddr[0] = (uint8_t)strtol(&tmpBuf[0], NULL, 16); 

		 

        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);
    }
}




void SaveRegMac(char* mac)
{
  int i;

  if( RegMacPool.Count>= 5 )
      return;
  

  for( i=0; i<RegMacPool.Count; i++)
  {
      if( strncmp( RegMacPool.Mac[i], mac, 12) == 0 )
      {
           NRF_LOG_RAW_INFO( "Allready Registrated\n");
          return;
      }
  
  }
  
  
  RegMacPool.Mac[RegMacPool.Count][12] = 0;
  strncpy( RegMacPool.Mac[RegMacPool.Count], mac, 12);

   record_write(1, RegMacPool.Count+1, mac, 12);

    RegMacPool.Count++;
}




void FlashTest()
{


    static uint8_t m_data[256];
    int len;

    sprintf(m_data, "hello-%d", 1);

    len = strlen(m_data);
    

    record_write( 1, 1, m_data, len);
    sprintf(m_data, "hello-%d", 2);
    record_write( 1, 2, m_data, len);

    print_all_cmd();
}


void SaveReceiverMac(char* mac)
{
	static uint8_t m_data[256];

	mac[12] = 0;

	 sprintf(m_data, "%s", mac);
	 
   NRF_LOG_RAW_INFO( "===> SaveReceiverMac : %s\n", m_data);



	
   record_write(1,1, m_data, 12);
   print_all_cmd();

  //FlashTest();

}




int FindRegMac(char* mac)
{

  int i;

 

  for( i=0; i<RegMacPool.Count; i++)
  {
      if( strncmp( RegMacPool.Mac[i], mac, 12) == 0 )
      {
           NRF_LOG_RAW_INFO( "Valid Mac\n");
          return 1;
      }  
  }
  

  return 0;

}

void DisplayRegMac()
{

  print_all_cmd( );
}





void SetMacAddress(uint8_t* addr)
{

	sd_ble_gap_addr_get(&old_ble_addr);
	ble_gap_addr_t dd;
	dd.addr_id_peer = 0;
	dd.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
	dd.addr[0] = addr[0];
	dd.addr[1] = addr[1];
	//dd.addr[2] = addr[2];
        dd.addr[2] = 0x57;
	dd.addr[3] = addr[3];
	dd.addr[4] = addr[4];
	dd.addr[5] = addr[5];	
    sd_ble_gap_addr_set(&dd);

	
	sd_ble_gap_addr_get(&new_ble_addr);
	
}












HSKey Key[4];


void KeyInit(void)
{


	Key[KEY_SELECT].longPressTimeOne = 2;

	Key[KEY_UP].longPressTimeOne = 2;



	//Key[KEY_COUNTER].longPressTimeKeep = 4;

}




//50ms key polling
void ReadKEY(void)
{	  

	static int key_poll_count = 0;

	if( SystemTimer.TIM_KEY < 100 )
		return;

	SystemTimer.TIM_KEY = 0;

	

	if( Key[KEY_SELECT].softRelease == 1 )
		return;

	if( key_poll_count == 2 )
	{
		if( nrf_gpio_pin_read(BSP_BUTTON_1) == true )
		{
			if( SystemManager.EmgSendButton == 10 )
			{
				SystemManager.EmgSendButton = BUTTON_TEST;
				Key[KEY_SELECT].softRelease = 1;

			}
			
		}

	}

	key_poll_count++;

	if( nrf_gpio_pin_read(BSP_BUTTON_1) == false  )
	{
		Key[KEY_SELECT].pressTime++;
		nrf_pwr_mgmt_feed();


		if( Key[KEY_SELECT].pressTime>20)
		{
			Key[KEY_SELECT].softRelease = 1;
			KeySelectLongPressedOne();
		}
	}




}




void KeySelectLongPressedOne(void)
{
	NRF_LOG_INFO("KeySelectLongPressedOne\r\n" );	
	SystemManager.EmgSendButton = BUTTON_REG;
}




void PortInputCfg(void)
{

#if 1
    uint32_t i;
    for (i = 17; i <= 20; ++i)
    {
        nrf_gpio_cfg_input(i, NRF_GPIO_PIN_PULLDOWN);
        //nrf_gpio_cfg_input(i, NRF_GPIO_PIN_PULLUP);
    }


	for (i = 12; i <= 15; ++i)
    {
        //nrf_gpio_cfg_input(i, NRF_GPIO_PIN_PULLDOWN);
        //nrf_gpio_cfg_input(i, NRF_GPIO_PIN_PULLUP);
    }

	nrf_gpio_cfg_input(7, NRF_GPIO_PIN_PULLDOWN);
#endif


}






#if 0
//uint8_t AesBuffer[16];

void CarEncryptEcb(int mode)
{
  uint8_t key[] = {0x53, 0x6D, 0x61, 0x72, 0x74, 0x42, 0x61, 0x6E, 0x64, 0x50, 0x41, 0x52, 0x54, 0x52, 0x4F, 0x4E}; // SmartBandPARTRON
  uint8_t in[]  = {'C', 'A', 'R', 1,2,3,4,5,6,7,8,9,10,11,12,13 };

  uint16_t tempVal;


  if( mode == AES_ENC_CAR )
  {
  	in[0] = 'C';
	in[1] = 'A';
	in[2] = 'R';
  }else if( mode == AES_ENC_EMG )
  {
  	in[0] = 'E';
	in[1] = 'M';
	in[2] = 'G';
  }else if( mode == AES_ENC_WES_EMG )
  {
  	in[0] = 'E';
	in[1] = 'M';
	in[2] = 'G';
  }

  

  tempVal = rand();

  in[3] = tempVal&0xff;
  in[4] = (tempVal>>8)&0xff;

  AES128_ECB_encrypt(in, key, SystemManager.AesEncData);

  NRF_LOG_RAW_INFO("ECB encrypt: %x\n", tempVal);

}
#endif




void WesDecryptEcb(char* in, char* out)
{
	uint8_t key[] = {0x53, 0x6D, 0x61, 0x72, 0x74, 0x42, 0x61, 0x6E, 0x64, 0x50, 0x41, 0x52, 0x54, 0x52, 0x4F, 0x4E}; // IES-200B PARTRON

	NRF_LOG_INFO("WesDecryptEcb AES128");

	AES128_ECB_decrypt(in, key, out);

}





void WesEncryptEcb(uint8_t* in)
{
	int i;

	uint8_t* inOrg = in;

	uint8_t key[] = {0x53, 0x6D, 0x61, 0x72, 0x74, 0x42, 0x61, 0x6E, 0x64, 0x50, 0x41, 0x52, 0x54, 0x52, 0x4F, 0x4E}; // IES-200B PARTRON
  
  
   AES128_ECB_encrypt(in, key, SystemManager.AesEncData);

   memcpy( inOrg, SystemManager.AesEncData, 16 );

}






#if 0	// Not Used
void CarEncryptEcbACK(char type)
{

	uint8_t key[] = {0x53, 0x6D, 0x61, 0x72, 0x74, 0x42, 0x61, 0x6E, 0x64, 0x50, 0x41, 0x52, 0x54, 0x52, 0x4F, 0x4E}; // SmartBandPARTRON
	uint8_t in[]  = {'C', 'A', 'R', 'A','C','K',1,2,3,4,5,6,7,8,9,0x0A };

	switch(type){
		// BAND EMG
		case 0x72:
			in[3] = 'E';
			in[4] = 'M';
			in[5] = 'G';	
		break;

		// NEW iOS APP
		case 0x75:
			in[3] = 'P';
			in[4] = 'C';
			in[5] = 'A';	
		break;
	}


	AES128_ECB_encrypt(in, key, SystemManager.AesEncData);

	NRF_LOG_RAW_INFO("ECB ACK\n");
}
#endif