/*
 * The MIT License (MIT)
 * Copyright (c) 2018 Novel Bits
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 */

#include <string.h>

#include "nrf_log.h"
#include "led_service.h"

#define AUTHORIZATION_ENABLED 1

static const uint8_t LED2CharName[] = "LED 2";

int authorization_counter =0;
static uint8_t authorization_data[4] = {0x00,0x00,0x20,0x00};
static uint8_t authorization_test_data[4] = {0x00,0x00,0x20,0x00};
/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_led_service  LED service structure.
 * @param[in]   p_ble_evt      Event received from the BLE stack.
 */
static void on_connect(ble_led_service_t * p_led_service, ble_evt_t const * p_ble_evt)
{
    p_led_service->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}

/**@brief Function for handling the Disconnect event.
 *
 * @param[in]   p_bas       LED service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_disconnect(ble_led_service_t * p_led_service, ble_evt_t const * p_ble_evt)
{
    UNUSED_PARAMETER(p_ble_evt);
    p_led_service->conn_handle = BLE_CONN_HANDLE_INVALID;
}

#if 0  // this was replaced by  on_rw_authorize_request(p_led_service,  p_ble_evt);
/**@brief Function for handling the Write event.
 *
 * @param[in] p_led_service   LED Service structure.
 * @param[in] p_ble_evt       Event received from the BLE stack.
 */

 
static void on_write(ble_led_service_t * p_led_service, ble_evt_t const * p_ble_evt)
{
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

    if (   (p_evt_write->handle == p_led_service->led_2_char_handles.value_handle)
        && (p_evt_write->len == 4 ) //phil 1)
        && (p_led_service->led_write_handler != NULL))
    {
authorization_test_data[0] = p_evt_write->data[0];
authorization_test_data[1] = p_evt_write->data[1];
authorization_test_data[2] = p_evt_write->data[2];
authorization_test_data[3] = p_evt_write->data[3];
        p_led_service->led_write_handler(p_ble_evt->evt.gap_evt.conn_handle, p_led_service, p_evt_write->data[0]);
    }
}

#endif


/**@brief Function for adding the LED 2 characteristic.
 *
 */
static uint32_t led_2_char_add(ble_led_service_t * p_led_service)
{
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_t    attr_char_value;
    ble_gatts_attr_md_t attr_md;
    ble_uuid_t          ble_uuid;

    memset(&char_md, 0, sizeof(char_md));
    memset(&attr_md, 0, sizeof(attr_md));
    memset(&attr_char_value, 0, sizeof(attr_char_value));

    char_md.char_props.read          = 1;
    char_md.char_props.write         = 1;
    char_md.p_char_user_desc         = LED2CharName;
    char_md.char_user_desc_size      = sizeof(LED2CharName);
    char_md.char_user_desc_max_size  = sizeof(LED2CharName);
    char_md.p_char_pf                = NULL;
    char_md.p_user_desc_md           = NULL;
    char_md.p_cccd_md                = NULL;
    char_md.p_sccd_md                = NULL;

    // Define the LED 2 Characteristic UUID
    ble_uuid.type = p_led_service->uuid_type;
    ble_uuid.uuid = BLE_UUID_LED_2_CHAR_UUID;

    // Set permissions on the Characteristic value
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);

    // Attribute Metadata settings
    attr_md.vloc       = BLE_GATTS_VLOC_USER;
    attr_md.rd_auth    = 0;
#if AUTHORIZATION_ENABLED == 0
    attr_md.wr_auth    = 0;
#else
    attr_md.wr_auth    = 1;
#endif
    attr_md.vlen       = 0;


    // Attribute Value settings
    attr_char_value.p_uuid       = &ble_uuid;
    attr_char_value.p_attr_md    = &attr_md;
    attr_char_value.init_len     = sizeof(authorization_data); //phil sizeof(uint8_t);
    attr_char_value.init_offs    = 0;
    attr_char_value.max_len      =  sizeof(authorization_data); //philsizeof(uint8_t);
    attr_char_value.p_value      = &authorization_data[0];





   
    return sd_ble_gatts_characteristic_add(p_led_service->service_handle, &char_md,
                                           &attr_char_value,
                                           &p_led_service->led_2_char_handles);
}

uint32_t ble_led_service_init(ble_led_service_t * p_led_service, const ble_led_service_init_t * p_led_service_init)
{
    uint32_t   err_code;
    ble_uuid_t ble_uuid;

    // Initialize service structure
    p_led_service->conn_handle = BLE_CONN_HANDLE_INVALID;

    // Initialize service structure.
    p_led_service->led_write_handler = p_led_service_init->led_write_handler;

    // Add service UUID
    ble_uuid128_t base_uuid = {BLE_UUID_LED_SERVICE_BASE_UUID};
    err_code = sd_ble_uuid_vs_add(&base_uuid, &p_led_service->uuid_type);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Set up the UUID for the service (base + service-specific)
    ble_uuid.type = p_led_service->uuid_type;
    ble_uuid.uuid = BLE_UUID_LED_SERVICE_UUID;

    // Set up and add the service
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_led_service->service_handle);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Add the different characteristics in the service:
    //   Button press characteristic:   E54B0002-67F5-479E-8711-B3B99198CE6C
    err_code = led_2_char_add(p_led_service);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}


/**@brief Read/write authorize request event handler.
 *
 * @param[in]   p_led_service      Les Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_rw_authorize_request(ble_led_service_t * p_led_service, ble_evt_t const * p_ble_evt)
{
    ble_gatts_evt_rw_authorize_request_t const * evt_rw_auth =
        &p_ble_evt->evt.gatts_evt.params.authorize_request;

//I really do not need this
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

   
    if (evt_rw_auth->type != BLE_GATTS_AUTHORIZE_TYPE_WRITE)
    {
        // Unexpected operation
        return;
    }


   

    /* Update SD GATTS values of appropriate host before SD sends the write Response */
    if (evt_rw_auth->request.write.handle == p_led_service->led_2_char_handles.value_handle)
    {
         // Prepare the response.
         ret_code_t                                   err_code;
         ble_gatts_rw_authorize_reply_params_t        auth_write_params;
         ble_gatts_evt_rw_authorize_request_t const * p_write_auth =
             &p_ble_evt->evt.gatts_evt.params.authorize_request;

/********************* this code fails  *************
         memset(&auth_write_params, 0, sizeof(auth_write_params));
         auth_write_params.type                    =  BLE_GATTS_AUTHORIZE_TYPE_WRITE;
         auth_write_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
         auth_write_params.params.write.offset      = p_write_auth->request.write.offset;
         auth_write_params.params.write.len         = sizeof(authorization_data);
         auth_write_params.params.write.p_data      = &authorization_data[0]; //phil this fails
         auth_write_params.params.write.update      = 1;
         ********************/


//********************* this code works ****************/
         memset(&auth_write_params, 0, sizeof(auth_write_params));
         auth_write_params.type                    =  BLE_GATTS_AUTHORIZE_TYPE_WRITE;
         auth_write_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
          auth_write_params.params.write.offset      = p_write_auth->request.write.offset;
         auth_write_params.params.write.len         = p_write_auth->request.write.len;
//         auth_write_params.params.write.p_data      = p_write_auth->request.write.data;//phil this works
         auth_write_params.params.write.p_data      = &authorization_data[0];//phil this fail
         auth_write_params.params.write.update      = 1;





authorization_counter++;
//authorization_data[3]++;
         // copy data from ble stack to VlCO_User locaion

// i am very curious as to why this does not work
// but i really do not care.
         authorization_test_data [0]=p_evt_write->data[0];
         authorization_test_data [1]=p_evt_write->data[1];
         authorization_test_data [2]=p_evt_write->data[2];
         authorization_test_data [3]=p_evt_write->data[3];
         err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle,
                                                   &auth_write_params);
         if (err_code != NRF_SUCCESS)
            {
            return;//  figure this out later
            }
       
    }
    else
    {
    //not led characteristic
    NRF_LOG_INFO("not led characteristic.");
    }
   

}



void ble_led_service_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_led_service_t * p_led_service = (ble_led_service_t *)p_context;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_led_service, p_ble_evt);
            break;

        case BLE_GATTS_EVT_WRITE:
 //           on_write(p_led_service, p_ble_evt);

            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_led_service, p_ble_evt);
            break;
#if AUTHORIZATION_ENABLED == 1
        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            on_rw_authorize_request(p_led_service,  p_ble_evt);
            break;

#endif

        default:
            // No implementation needed.
            break;
    }
}


/***************************


                     ble_led_service_t * p_led_service, ble_evt_t const * p_ble_evt
static void on_write(ble_sens_t * p_sens, ble_evt_t * p_ble_evt)
{		
   ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; 
	 if(p_evt_write->handle == p_sens->config_handle.value_handle || p_evt_write->handle == p_sens->step_data_handle.value_handle)
	 {
			p_sens->evt_handler(p_sens, p_evt_write);
	 }    
}

static void evt_handler(ble_sens_t * p_sens, ble_gatts_evt_write_t  * p_evt_write)
{	
 if (p_evt_write->handle == p_sens->config_handle.value_handle )
   {			  
			m_config.toggle_settings = p_evt_write->data[0];
		 	m_config.seconds = p_evt_write->data[1];
		 	m_config.minutes = p_evt_write->data[2];
		 	m_config.hours = p_evt_write->data[3];
		 	m_config.day = p_evt_write->data[4];
		 	m_config.month = p_evt_write->data[5];
		 	m_config.year = p_evt_write->data[6];	    
	 }
}


typedef void (*ble_sens_evt_handler_t) (ble_sens_t * p_sens, ble_gatts_evt_write_t * evt_write);



*******************************/
