#include "ble_action.h"
#include "_string.h"
#include "transcode.h"
#include "debug.h"
#include "tools.h"
#include "user_config.h"
#include "user_elect.h"
#include "user_server.h"
#include "user_led.h"
#include "user_nfc.h"

static void ble_action_set_rst(void);

/* Flash data temporary storage */
__attribute__((aligned(8))) uint8_t block_buf[256];

/*********************************************************************
 * @fn      Jump_OTA
 *
 * @brief   Jump to OTA upgrade
 *
 * @return  none
 */
void Jump_OTA(void)
{
    uint16_t i;
    uint32_t ver_flag;

    /* Read the first block */
    FLASH_read(OTA_DATAFLASH_ADDR, (uint8_t *)&block_buf[0], 4);

    FLASH_Unlock_Fast();
    /* Erase the first block */
    FLASH_ErasePage_Fast( OTA_DATAFLASH_ADDR );

    /* Update Image information */
    block_buf[0] = IMAGE_OTA_FLAG;
    block_buf[1] = IMAGE_FLAG_1;
    block_buf[2] = IMAGE_FLAG_2;
    block_buf[3] = IMAGE_FLAG_3;

    /* Programming DataFlash */
    FLASH_ProgramPage_Fast(OTA_DATAFLASH_ADDR, (uint32_t *)&block_buf[0]);
    FLASH_Lock_Fast();

    ble_action_set_rst();
}

static upload_ble_data_func upload_ble_data = NULL;
static ble_data_s last_test_data;
static bool ble_connected = false;
static uint32_t token = 0;
static uint32_t unixTime_delay = 0;
static uint32_t unixTime = 0;

static void unixTime_pro(void)
{
    if(unixTime_delay > 0)
    {
	    unixTime_delay--;
    }
    else{
        unixTime_delay = 1000 / BLE_ACTION_TICKS;
        unixTime++;
    }
}

uint32_t * get_unixTime(void)
{
    return &(unixTime);
}

void set_unixTime(uint32_t value)
{
    unixTime = value;
}

static void ble_owned_data_send(uint8_t *data, int len)
{
  if(upload_ble_data != NULL)
  {
      upload_ble_data(data, len);
  }
}

static void ble_Return_Stat_Send(bool stat)
{
  uint8_t data[4]={0};
  if(stat == true)
  {
      data[0]='O';
      data[1]='K';
      data[2]=0;
      data[3]=0;
  }
  else{
      data[0]='N';
      data[1]='O';
      data[2]='K';
      data[3]=0;
  }
  ble_owned_data_send(data,4);
}

static void Set_Ble_Encrypt_Data(uint8_t *data,uint8_t len)
{
  int pCipher_len = 0;
  PRINT("ble upload\n");
  uint8_t *paradata = device_encrypt(MacAddr,(ble_connected == true)?token:0,data,len,&pCipher_len);
  ble_owned_data_send(paradata,pCipher_len);
  free(paradata);
}

static bool Set_ble_data_s_sendData(ble_data_s *ble_data)
{
  uint8_t data[64]={0};

  if(ble_data->len >= 55)
  {
      return false;
  }

  data[0] = ble_data->ins;
  data[1] = ble_data->data_type;
  data[2] = ble_data->len + 1;
  data[3] = ble_data->cmd;
  memcpy(&data[4], ble_data->data, ble_data->len);
  memcpy(&data[4 + ble_data->len], get_unixTime(), 4);
  memcpy(&data[8 + ble_data->len], &token, 4);
#if AES_ENABLE == 1
  Set_Ble_Encrypt_Data(data, ble_data->len + 12);
#else
  ble_owned_data_send(data, ble_data->len + 12);
#endif
  return true;
}

static void set_token(void)
{
  token = Get_Rand();
  token = get_gb_token(token);
}

void ble_connect_act(bool stat)
{
  if(stat == false)
  {
      set_token();
      ble_connected = false;
      vUser_led_set_alarm_view(LED_ALL_ALARM_BLE, false);
    //   action_work.ble_conn_stat = false;
    //   net_led_stat_pro(NET_LED_DISCONNECT);
  }
  else{
    //   upgrade_succ();
    //   net_led_stat_pro(NET_LED_CONNECT);
  }
}

static bool Get_Token_Act(ble_data_s *test_data)
{
    if(test_data->len!=0x05 || test_data->data[0]!=0x00)
    {
        return false;
    }

    uint32_t unixtime = 0;

    memcpy(&unixtime, &(test_data->data[1]), 4);
    set_unixTime(unixtime);

    uint8_t data[16]={0};

    data[0]=INS_TOKEN;
    data[1]=BLE_UPLOAD_SLAVE;
    data[2]=0x04;
    memcpy(&data[3],&token,4);
    memcpy(&data[7],get_unixTime(),4);
    memcpy(&data[11],&token,4);

#if AES_ENABLE == 1
    Set_Ble_Encrypt_Data(data,15);
#else
    ble_owned_data_send(data, 15);
#endif
    ble_connected = true;
//   action_work.ble_conn_stat = true;
    vUser_led_set_alarm_view(LED_ALL_ALARM_BLE, true);

    return true;
}

static bool Check_UnixTime_Token(uint8_t *data)
{
  uint32_t master_token;
  uint32_t unixtime = 0;

  memcpy(&unixtime, data, 4);
  set_unixTime(unixtime);

  memcpy(&master_token, &data[4], 4);

  if(master_token!=token)
  {
      return false;
  }
  return true;
}

static void ble_devRst_set_stat_send(bool stat)
{
    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_PARAM_SET;
    ble_data.len = 1;
    uint8_t data[1] = {0};
    ble_data.cmd = PARAM_SET_RST;
    data[0] = (stat == true)?SET_PARAM_SUCCESS:SET_PARAM_FAILURE;
    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
}

static bool DevRst_Set_Act(uint8_t *data)
{
    if(*data == 0xEE)
    {
	ble_devRst_set_stat_send(true);
	return true;
    }
    ble_devRst_set_stat_send(false);
    return false;
}

static void ble_devcan_baud_set_stat_send(bool stat)
{
    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_PARAM_SET;
    ble_data.len = 1;
    uint8_t data[4] = {0};
    ble_data.cmd = PARAM_SET_CAN;
    uint32_t baud = (uint32_t)user_config_param.can_baud;
    memcpy(data, &baud, 4);
    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
}

static bool Can_baud_Set_Act(ble_data_s *test_data)
{
    uint32_t baud = 0;
    if(test_data->len == 5)
    {
        memcpy(&baud, &(test_data->data[1]), 4);
        if(true == user_config_save_can_baud(baud))
        {
            return true;
        }
    }

    ble_devRst_set_stat_send(false);
    return false;
}

static bool Set_Param_Set_Act(ble_data_s *test_data)
{
    bool stat = false;
    if(false == Check_UnixTime_Token(&test_data->data[test_data->len]))
    {
	    return false;
    }

    switch(test_data->data[0])
    {
        case PARAM_SET_CAN:stat = Can_baud_Set_Act(test_data);break;
        case PARAM_SET_RST: stat = DevRst_Set_Act(&(test_data->data[1]));break;					//设备重启
        default:return false;
    }

    return stat;
}

static void ble_get_canbaud_set_send(void)
{
    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_PARAM_GET;
    ble_data.len = 5;
    uint8_t data[4] = {0};
    ble_data.cmd = PARAM_GET_CAN;
    uint32_t baud = (uint32_t)user_config_param.can_baud;
    memcpy(data, &baud, 4);
    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
}

static bool Get_Param_Set_Act(ble_data_s *test_data)
{
    if(false == Check_UnixTime_Token(&test_data->data[test_data->len]))
    {
	    return false;
    }

    switch(test_data->data[0])
    {
        case PARAM_GET_CAN: ble_get_canbaud_set_send();break;			//CAN参数设置
        default:return false;
    }

    return true;
}

void ble_get_nfc_send(ble_data_s *test_data)
{
    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_DATA_GET;
    ble_data.len = 5;
    uint8_t data[5] = {0};
    ble_data.cmd = DATA_GET_NFC;

    if(test_data->len != 2)
    {
        data[0] = 0xFF;
    }
    else{
      uint8_t idx = test_data->data[1];
      if(idx >= USER_NFC_MAX_COUNT)
      {
          data[0] = 0xFE;
      }
      else{
          lock_data_s *lock = vUser_server_get_lock_data();
          data[0] = (lock->lock_stat >> idx) & 0x01;
          memcpy(&data[1], lock->lock_id[idx], 4);
      }
    }

    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
}

static bool Get_Data_Act(ble_data_s *test_data)
{
    if(false == Check_UnixTime_Token(&test_data->data[test_data->len]))
    {
	    return false;
    }

    switch(test_data->data[0])
    {
        case DATA_GET_NFC:ble_get_nfc_send(test_data);break;			//获取挂锁NFC号
        default:return false;
    }

    return true;
}

static bool Control_Data_Act(ble_data_s *test_data)
{
    bool stat = false;

    if(false == Check_UnixTime_Token(&test_data->data[test_data->len]))
    {
	    return false;
    }

    switch(test_data->data[0])
    {
        case CONTROL_LOCK:break;				//电磁锁控制
        default:return false;
    }

    return stat;
}

static bool Get_Firmware_Act(uint8_t *test_data)
{
    if(*test_data != 0x01)
    {
	return false;
    }

    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_FIRMWARE;
    ble_data.len = 2;
    uint8_t data[2] = {SOFTWARE_VERSION, HARDWARE_VERSION};
    ble_data.cmd = FIRMWARE_GET;
    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
    return true;
}

static bool Rst_Firmware_Act(uint8_t *test_data)
{
    if(*test_data == 0x01)
    {
	    Jump_OTA();
    }
    else{
	    return false;
    }

    ble_data_s ble_data;
    ble_data.data_type = BLE_UPLOAD_SLAVE;
    ble_data.ins = INS_FIRMWARE;
    ble_data.len = 1;
    uint8_t data[1] = {0};
    ble_data.cmd = FIRMWARE_RST;
    data[0] = *test_data;
    ble_data.data = data;
    Set_ble_data_s_sendData(&ble_data);
    return true;
}

static bool Firmware_Data_Act(ble_data_s *test_data)
{
    bool stat = false;

    if(false == Check_UnixTime_Token(&test_data->data[test_data->len]))
    {
	    return false;
    }

    switch(test_data->data[0])
    {
        case FIRMWARE_GET:stat = Get_Firmware_Act(&(test_data->data[1]));break;		//获取固件版本号
        case FIRMWARE_RST:stat = Rst_Firmware_Act(&(test_data->data[1]));break;			//设备重启
        default:return false;
    }

    return stat;
}

bool download_ble_data_callback(uint8_t *data, int len)
{
    if(_strstr((char *)data,"rst=1")==0)
    {
        PRINT("SOFT RST!\n");
        ble_action_set_rst();
        ble_Return_Stat_Send(true);
        return true;
    }
    else if(_strstr((char *)data,"ENTER OTA")==0)
    {
        PRINT("ENTER OTA!\n");
        Jump_OTA();
        ble_Return_Stat_Send(true);
        return true;
    }
    else if(_strstr((char *)data,"configInit")==0)
    {
    	PRINT("CONFIG INIT!\n");
    	set_user_config_param_init(&user_config_param);
    	User_Config_Write_Config();
    	ble_Return_Stat_Send(true);
    	return true;
    }
    else if(_strstr((char *)data, "open=") == 0)
    {
    	int value = -1;
    	if(1 == sscanf((char *)data, "open=%d", &value))
    	{
    	    if(value < ELECT_COUNT)
            {
                set_elect_work_stat(value, true);
            }
    	}

    	ble_Return_Stat_Send(true);
    	return true;
    }
    else if(_strstr((char *)data, "close=") == 0)
    {
    	int value = -1;
    	if(1 == sscanf((char *)data, "close=%d", &value))
    	{
    	    if(value < ELECT_COUNT)
            {
                set_elect_work_stat(value, false);
            }
    	}

    	ble_Return_Stat_Send(true);
    	return true;
    }
    
#if AES_ENABLE == 1
    uint8_t *paradata = device_decrypt(MacAddr, (ble_connected == true)?token:0, data, len);
    PRINT("Decrypt:\n");
    print_hex(paradata, len);
#else
    uint8_t *paradata = data;
#endif
    ble_data_s test_data;

    test_data.ins = (ble_dev_ins_e)paradata[0];
    test_data.data_type = (ble_dev_data_type_e)paradata[1];
    if(test_data.data_type == BLE_UPLOAD_SLAVE)
    {
        #if AES_ENABLE == 1
        free(paradata);
        #endif
        return false;
    }

    test_data.len = paradata[2];
    test_data.data = &paradata[3];
    bool stat = false;
    switch(test_data.ins)
    {
        case INS_TOKEN: stat = Get_Token_Act(&test_data);break;				//获取token
        case INS_PARAM_SET: stat = Set_Param_Set_Act(&test_data);break;			//参数设置指令
        case INS_PARAM_GET: stat = Get_Param_Set_Act(&test_data);break;			//获取设置参数指令
        case INS_DATA_GET: stat = Get_Data_Act(&test_data);break;			//获取数据指令
        case INS_CONTROL: stat = Control_Data_Act(&test_data);break;			//控制指令
        case INS_FIRMWARE:stat = Firmware_Data_Act(&test_data);break;			//固件获取指令
        default:{
            #if AES_ENABLE == 1
            free(paradata);
            #endif
        }return false;
    }

    memcpy((uint8_t *)&last_test_data,(uint8_t *)&test_data,sizeof(ble_data_s));
#if AES_ENABLE == 1
    free(paradata);
#endif
    // if(stat == true)
    // {
    //     net_led_stat_pro(NET_LED_DATA_OK);
    //     Set_User_Work_Queue(USER_WORK_QUEUE_ONLINE);
    // }
    // else{
	//     net_led_stat_pro(NET_LED_DATA_NOK);
    // }
    return stat;
}

static void ble_action_set_rst(void)
{
  vUser_led_set_alarm_view(LED_ALL_ALARM_RST, true);
  bStatus_t stat = tmos_start_reload_task(user_server_task_id, (1 << SERVER_BLE_RST), MS1_TO_SYSTEM_TIME(1000));

}

/*******************************************************************************
  * @函数名称   vBle_action_init
  * @函数说明   初始化
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vBle_action_init(void)
{
    set_token();
}

bool download_ble_file_callback(uint8_t *data, int len)
{
  return download_ble_data_callback(data, len);
}

void set_upload_ble_data_func(upload_ble_data_func func)
{
  upload_ble_data = func;
}
