/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* 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.
*/
/**
  ******************************************************************************
  * @file    BlueNRGGattClient.cpp 
  * @author  STMicroelectronics
  * @brief   Header file for BLE_API GattClient Class
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
  */
 
#ifndef __BLUENRG_GATT_CLIENT_H__
#define __BLUENRG_GATT_CLIENT_H__

#ifdef YOTTA_CFG_MBED_OS
    #include "mbed-drivers/mbed.h"
#else
    #include "mbed.h"
#endif 
#include "ble/blecommon.h"
#include "btle.h"
#include "ble/GattClient.h"
#include "ble/DiscoveredService.h"
#include "ble/CharacteristicDescriptorDiscovery.h"
#include "BlueNRGDiscoveredCharacteristic.h"

using namespace std;

#define BLE_TOTAL_DISCOVERED_SERVICES 10
#define BLE_TOTAL_DISCOVERED_CHARS 10

class BlueNRGGattClient : public GattClient
{
public:
    static BlueNRGGattClient &getInstance() {
        static BlueNRGGattClient m_instance;
        return m_instance;
    }
    
    enum {
      GATT_IDLE,
      GATT_SERVICE_DISCOVERY,
      GATT_CHAR_DESC_DISCOVERY,
      //GATT_CHARS_DISCOVERY_COMPLETE,
      //GATT_DISCOVERY_TERMINATED,
      GATT_READ_CHAR,
      GATT_WRITE_CHAR
    };
    
    /* Functions that must be implemented from GattClient */
    virtual ble_error_t launchServiceDiscovery(Gap::Handle_t                               connectionHandle,
                                               ServiceDiscovery::ServiceCallback_t         sc                           = NULL,
                                               ServiceDiscovery::CharacteristicCallback_t  cc                           = NULL,
                                               const UUID                                 &matchingServiceUUID          = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN),
                                               const UUID                                 &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN));

    virtual ble_error_t discoverServices(Gap::Handle_t                        connectionHandle,
                                         ServiceDiscovery::ServiceCallback_t  callback,
                                         const UUID                          &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN));

    virtual ble_error_t discoverServices(Gap::Handle_t                        connectionHandle,
                                         ServiceDiscovery::ServiceCallback_t  callback,
                                         GattAttribute::Handle_t              startHandle,
                                         GattAttribute::Handle_t              endHandle);

    virtual bool isServiceDiscoveryActive(void) const;
    virtual void terminateServiceDiscovery(void);
    virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) {
      terminationCallback = callback;
    }
    virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const;
    virtual ble_error_t write(GattClient::WriteOp_t    cmd,
                              Gap::Handle_t            connHandle,
                              GattAttribute::Handle_t  attributeHandle,
                              size_t                   length,
                              const uint8_t           *value) const;
    virtual ble_error_t discoverCharacteristicDescriptors(
        const DiscoveredCharacteristic& characteristic,
        const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
        const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback);

    virtual ble_error_t reset(void);

    void gattProcedureCompleteCB(Gap::Handle_t connectionHandle, uint8_t error_code);

    void primaryServicesCB(Gap::Handle_t connectionHandle,
                           uint8_t event_data_length,
                           uint8_t attribute_data_length,
                           uint8_t *attribute_data_list);
    
    void primaryServiceCB(Gap::Handle_t connectionHandle,
                          uint8_t event_data_length,
                          uint8_t *handles_info_list);
    
    ble_error_t findServiceChars(Gap::Handle_t connectionHandle);
    
    void serviceCharsCB(Gap::Handle_t connectionHandle,
                        uint8_t event_data_length,
                        uint8_t handle_value_pair_length,
                        uint8_t *handle_value_pair);
    
    void  serviceCharByUUIDCB(Gap::Handle_t connectionHandle,
                              uint8_t event_data_length,
                              uint16_t attr_handle,
                              uint8_t *attr_value);

    void discAllCharacDescCB(Gap::Handle_t connHandle,
                             uint8_t event_data_length,
                             uint8_t format,
                             uint8_t *handle_uuid_pair);

    void charReadCB(Gap::Handle_t connHandle,
                    uint8_t event_data_length,
                    uint8_t* attribute_value);

    void charWritePrepareCB(Gap::Handle_t connHandle,
                            uint8_t event_data_length,
                            uint16_t attribute_handle,
                            uint16_t offset,
                            uint8_t *part_attr_value);
    
    void charWriteExecCB(Gap::Handle_t connHandle,
                         uint8_t event_data_length);

protected:

    BlueNRGGattClient() {
      _currentState = GATT_IDLE;
      _matchingServiceUUID = BLE_UUID_UNKNOWN;
      _matchingCharacteristicUUIDIn = BLE_UUID_UNKNOWN;
    }

    ServiceDiscovery::ServiceCallback_t  serviceDiscoveryCallback;
    ServiceDiscovery::CharacteristicCallback_t characteristicDiscoveryCallback;
    ServiceDiscovery::TerminationCallback_t terminationCallback;
    CharacteristicDescriptorDiscovery::DiscoveryCallback_t charDescDiscoveryCallback;
    CharacteristicDescriptorDiscovery::TerminationCallback_t charDescTerminationCallback;

private:

  BlueNRGGattClient(BlueNRGGattClient const &);
  void operator=(BlueNRGGattClient const &);

  Gap::Handle_t _connectionHandle;
  DiscoveredService discoveredService[BLE_TOTAL_DISCOVERED_SERVICES];
  BlueNRGDiscoveredCharacteristic discoveredChar[BLE_TOTAL_DISCOVERED_CHARS];
  
  GattReadCallbackParams readCBParams;
  GattWriteCallbackParams writeCBParams;

  // The char for which the descriptor discovery has been launched  
  DiscoveredCharacteristic _characteristic;

  UUID _matchingServiceUUID;
  UUID _matchingCharacteristicUUIDIn;
  uint8_t _currentState;
  uint8_t _numServices, _servIndex;
  uint8_t _numChars;
  uint8_t _numCharDesc;
  
};

#endif /* __BLUENRG_GATT_CLIENT_H__ */