#include <stdio.h>
#include <unistd.h> 

#include "ip_connection.h"
#include "bricklet_rotary_poti.h"

#define HOST "localhost"
#define PORT 4223

#define UID_LEN (8)

static IPConnection ipcon;
static RotaryPoti rp;
static int rotary_poti_is_valid;
static char rotary_poti_uid[UID_LEN];

void cb_position_has_changed(int16_t position, void *user_data)
{
    printf("->%s\n", __FUNCTION__);
    printf("Position %s: %hd\n", (char * ) user_data, position);
}

static void cb_connect(uint8_t connect_reason, void *user_data)
{
    printf("->%s\n", __FUNCTION__);
    ipcon_enumerate(&ipcon);
}

static void cb_disconnect(uint8_t connect_reason, void *user_data)
{
    printf("->%s\n", __FUNCTION__);
    if (rotary_poti_is_valid)
    {
        rotary_poti_destroy(&rp);
    }
    rotary_poti_is_valid = 0;
}

static void cb_enumerate(const char *uid, const char *connected_uid,
        char position, uint8_t hardware_version[3],
        uint8_t firmware_version[3], uint16_t device_identifier,
        uint8_t enumeration_type, void *user_data)
{
    if (device_identifier == ROTARY_POTI_DEVICE_IDENTIFIER)
    {
        printf("->%s %s ", __FUNCTION__, uid);
        switch (enumeration_type) {
            case IPCON_ENUMERATION_TYPE_DISCONNECTED:
                /* 
                 * unreachable: device_identifier is always 0 on disconnect
                 */
                printf("disconnected, ");
                rotary_poti_is_valid = 0;
                rotary_poti_destroy(&rp);
                *rotary_poti_uid = 0;
                printf("NOW invalid\n");
                break;
            case IPCON_ENUMERATION_TYPE_CONNECTED:
            case IPCON_ENUMERATION_TYPE_AVAILABLE:
                printf(" %s, ", (enumeration_type == IPCON_ENUMERATION_TYPE_CONNECTED ? "connected" : "available"));
                if (rotary_poti_is_valid)
                {
                    printf("ALREADY valid\n");
                }
                else
                {
                    rotary_poti_is_valid = 1;
                    strcpy(rotary_poti_uid, uid);
                    rotary_poti_create(&rp, uid, &ipcon);
                    rotary_poti_register_callback(&rp,
                            ROTARY_POTI_CALLBACK_POSITION,
                            cb_position_has_changed,
                            (void *) rotary_poti_uid);
                    rotary_poti_set_position_callback_period(&rp, 50);
                    printf("NOW valid, callback set\n");
                }
                break;

            default:
                printf("Error: unknown enumeration type %hhu", enumeration_type);
                break;
        }
    }
    if (enumeration_type == IPCON_ENUMERATION_TYPE_DISCONNECTED)
    {
        /*
         * on disconnect you have to check for disconnected UID
         */
        if (rotary_poti_is_valid)
        {
            if (!strcmp(uid, rotary_poti_uid))
            {
                printf("->%s %s (device_identifier %hu) ", __FUNCTION__, uid, device_identifier);
                printf("disconnected, ");
                rotary_poti_is_valid = 0;
                rotary_poti_destroy(&rp);
                printf("NOW invalid\n");
            }
        }
    }
}

int main(void)
{
    rotary_poti_is_valid = 0;

    ipcon_create(&ipcon);
    if (ipcon_connect(&ipcon, HOST, PORT) < 0)
    {
        fprintf(stderr, "Error: Could not connect to brickd. Exit.\n");
        exit(EXIT_FAILURE);
    }

    ipcon_register_callback(&ipcon, IPCON_CALLBACK_ENUMERATE, (void *) cb_enumerate, NULL);
/*
    ipcon_register_callback(&ipcon, IPCON_CALLBACK_CONNECTED, (void *) cb_connect, NULL);
    ipcon_register_callback(&ipcon, IPCON_CALLBACK_DISCONNECTED, (void *) cb_disconnect, NULL);
*/
    ipcon_enumerate(&ipcon);
    while (1)
    {
        sleep(1);
    }
    return 0;
}