import Queue

import json
import time
import sys

from datetime import datetime, timedelta
from bitstruct import *
from pprint import pformat
import binascii
from pc_ble_driver_py.observers import *
from nordicsemi.ble_adapter import *

try:
    with open("Config_Files/Connection_Settings.json")as conn:
        config = json.load(conn)
except Exception as e:
    print str(e)
    print 'Could not open settings file'
    raw_input("Press ENTER to exit...")
    quit()


DEV_MAC = config['dev_mac']


REPEAT_COUNT = 25

RAW_TYPE = TEMP  # Temp sensor
RAW_COUNT = 10  # Sample count
RAW_RATE = 0  # Sampling freq

TARGET_DEV_NAME ="50:31:AD:C0:00:0A"
port_enter = "COM10"
device = "NRF52"
CONNECTIONS = 1
serial_port = "COM10"
dev_name = "50:31:AD:C0:00:0A"
# Creating command packet
temp = pack('u8u16f32', RAW_TYPE, RAW_COUNT, RAW_RATE)
pkt = byteswap('124', temp)

HEADER_SIZE = 3

_EOT_T = 'u1'
_TYPE_T = 'u3'
_TID_T = 'u4'
_SEQ_NUM_T = 'u16'

__BYTEALIGN = '12'

__DATA_FORMAT = _TID_T + _TYPE_T + _EOT_T + _SEQ_NUM_T

sensorType = RAW_TYPE
sampleCount = RAW_COUNT
samplingFreq = RAW_RATE
##
#Data saving part 
##

##### NRF PART ################

CCCD_UUID = '00002902-0000-1000-8000-00805f9b34fb'

DC_SERVICE_UUID = '00001111-0000-1000-8000-00805f9b34fb'

BASE_UUID = BLEUUIDBase([0x8E, 0xC9, 0x00, 0x00, 0xF3, 0x15, 0x4F, 0x60,
                         0x9F, 0xB8, 0x83, 0x88, 0x30, 0xDA, 0xEA, 0x50])

# Buttonless characteristics
BLE_DFU_BUTTONLESS_CHAR_UUID = BLEUUID(0x0003, BASE_UUID)
BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID = BLEUUID(0x0004, BASE_UUID)
SERVICE_CHANGED_UUID = BLEUUID(0x2A05)
def init(conn_ic_id):
    global BLEDriver, BLEAdvData, BLEEvtID, BLEAdapter, BLEEnableParams, BLEGapTimeoutSrc, BLEUUID
    from pc_ble_driver_py import config
    config.__conn_ic_id__ = conn_ic_id
    from pc_ble_driver_py.ble_driver import BLEDriver, BLEAdvData, BLEEvtID, BLEEnableParams, BLEGapTimeoutSrc, BLEUUID
    from pc_ble_driver_py.ble_adapter import BLEAdapter
    global nrf_sd_ble_api_ver
    nrf_sd_ble_api_ver = config.sd_api_ver_get()


class HRCollector(BLEDriverObserver, BLEAdapterObserver):
    def __init__(self, adapter):
        super(HRCollector, self).__init__()
        self.adapter = adapter
        self.conn_q = Queue.Queue()
        self.adapter.observer_register(self)
        self.adapter.driver.observer_register(self)

    def open(self):
        self.adapter.driver.open()

        ble_enable_params = BLEEnableParams(vs_uuid_count=1,
                                            service_changed=False,
                                            periph_conn_count=0,
                                            central_conn_count=CONNECTIONS,
                                            central_sec_count=CONNECTIONS)
        if nrf_sd_ble_api_ver >= 3:
            print("Enabling larger ATT MTUs")
            ble_enable_params.att_mtu = 50

        self.adapter.driver.ble_enable(ble_enable_params)

    def close(self):
        self.adapter.driver.close()

    @property
    def connect_and_discover(self):
        self.adapter.driver.ble_gap_scan_start()
        new_conn = self.conn_q.get(timeout=60)

        if nrf_sd_ble_api_ver >= 3:
            att_mtu = self.adapter.att_mtu_exchange(new_conn)

        self.adapter.service_discovery(new_conn)
        self.adapter.enable_notification(new_conn, BLEUUID(0x0003, DC_SERVICE_UUID))#BLEUUID(BLEUUID.Standard.battery_level))
        # self.adapter.enable_notification(new_conn, BLEUUID(BLEUUID.Standard.heart_rate))
        return new_conn

    def on_gap_evt_connected(self, ble_driver, conn_handle, peer_addr, role, conn_params):
        print('New connection: {}'.format(conn_handle))
        self.conn_q.put(conn_handle)

    def on_gap_evt_disconnected(self, ble_driver, conn_handle, reason):
        print('Disconnected: {} {}'.format(conn_handle, reason))

    def on_gap_evt_timeout(self, ble_driver, conn_handle, src):
        if src == BLEGapTimeoutSrc.scan:
            ble_driver.ble_gap_scan_start()

    def on_gap_evt_adv_report(self, ble_driver, conn_handle, peer_addr, rssi, adv_type, adv_data):
        dev_name_list = None
        if BLEAdvData.Types.complete_local_name in adv_data.records:
            dev_name_list = adv_data.records[BLEAdvData.Types.complete_local_name]

        elif BLEAdvData.Types.short_local_name in adv_data.records:
            dev_name_list = adv_data.records[BLEAdvData.Types.short_local_name]

        else:
            return

        dev_name = "".join(chr(e) for e in dev_name_list)
        address_string = "".join("{0:02X}".format(b) for b in peer_addr.addr)
        print('Received advertisment report, address: 0x{}, device_name: {}'.format(address_string,
                                                                                    dev_name))

        if (dev_name == TARGET_DEV_NAME):
            self.adapter.connect(peer_addr)

    def on_notification(self, ble_adapter, conn_handle, uuid, data):
        print('Connection: {}, {} = {}'.format(conn_handle, uuid, data))

    def on_att_mtu_exchanged(self, ble_driver, conn_handle, att_mtu):
        print('ATT MTU exchanged: conn_handle={} att_mtu={}'.format(conn_handle, att_mtu))

    def on_gattc_evt_exchange_mtu_rsp(self, ble_driver, conn_handle, **kwargs):
        print('ATT MTU exchange response: conn_handle={}'.format(conn_handle))


def main(serial_port):
    print('Serial port used: {}'.format(serial_port))
    driver = BLEDriver(serial_port=serial_port, auto_flash=True)
    adapter = BLEAdapter(driver)
    collector = HRCollector(adapter)
    collector.open()
    conn_handle = collector.connect_and_discover()
    # adapter.write_req(conn_handle, CCCD_UUID, [3])#RAW_TYPE)
    # collector.connect_and_discover()
   


if __name__ == "__main__":
    serial_port = None
    # if len(sys.argv) < 2:
    #     print("Please specify connectivity IC identifier (NRF51, NRF52)")
    #     exit(1)
    init("NRF52")
    if len(sys.argv) == 3:
        serial_port = sys.argv[2]
    else:
        descs = BLEDriver.enum_serial_ports()
        choices = ['{}: {}'.format(d.port, d.serial_number) for d in descs]
        choice = '0'  # item_choose(choices)
        serial_port = port_enter  # "COM12" #descs[choice].port
        main(serial_port)
        quit()

##### NRF PART ###### #########
