/*
 * File      : sensors.cpp
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2014, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date           Author       Notes
 * 2014-08-03     Bernard      the first version
 */

#include <stddef.h>
#include <string.h>

#include "sensor.h"

/**
 * SensorBase
 */
SensorBase::SensorBase(int type)
{
    memset(&(this->config), 0x0, sizeof(SensorConfig));

    this->type = type;
    this->next = this->prev = NULL;
    subscribe(NULL, NULL);
}

SensorBase::~SensorBase()
{
}

int SensorBase::getType(void)
{
    return this->type;
}

int SensorBase::setConfig(SensorConfig *config)
{
    int result;

    /* configure to the low level sensor */
    result = this->configure(config);
    if (result == 0)
    {
        this->config = *config;
    }

    return result;
}

int SensorBase::getConfig(SensorConfig *config)
{
    *config = this->config;
    return 0;
}

int SensorBase::subscribe(SensorEventHandler_t *handler, void *user_data)
{
    this->evtHandler = handler;
    this->userData = user_data;

    return 0;
}

int SensorBase::publish(sensors_event_t *event)
{
    if (this->evtHandler != NULL)
    {
        /* invoke subscribed handler */
        (*evtHandler)(event, this->userData);
    }

    return 0;
}

/**
 * Sensor Manager
 */
/* sensors list */
static SensorBase *sensor_list = NULL;

SensorManager::SensorManager()
{
}

SensorManager::~SensorManager()
{
}

int SensorManager::registerSensor(SensorBase *sensor)
{
    RT_ASSERT(sensor != RT_NULL);

    /* add sensor into the list */
    if (sensor_list == NULL)
    {
        sensor->prev = sensor->next = sensor;
    }
    else
    {
        sensor_list->prev->next = sensor;
        sensor->prev = sensor_list->prev;

        sensor_list->prev = sensor;
        sensor->next = sensor_list;
    }

    /* point the sensorList to this sensor */
    sensor_list = sensor;

    return 0;
}

int SensorManager::unregisterSensor(SensorBase *sensor)
{
    /* disconnect sensor list */
    sensor->next->prev = sensor->prev;
    sensor->prev->next = sensor->next;

    /* check the sensorList */
    if (sensor == sensor_list)
    {
        if (sensor->next == sensor) sensor_list = NULL; /* empty list */
        else sensor_list = sensor->next;
    }

    /* re-initialize sensor node */
    sensor->next = sensor->prev = sensor;

    return 0;
}

SensorBase *SensorManager::getDefaultSensor(int type)
{
    SensorBase *sensor = sensor_list;

    if (sensor == NULL) return NULL;

    do
    {
        /* find the same type */
        if (sensor->getType() == type) return sensor;

        sensor = sensor->next;
    }while (sensor != sensor_list);

    return NULL;
}

int SensorManager::subscribe(int type, SensorEventHandler_t *handler, void *user_data)
{
    SensorBase *sensor;

    sensor = SensorManager::getDefaultSensor(type);
    if (sensor != NULL)
    {
        sensor->subscribe(handler, user_data);
        return 0;
    }

    return -1;
}

int SensorManager::sensorEventReady(SensorBase *sensor)
{
    return 0;
}

int SensorManager::pollSensor(SensorBase *sensor, sensors_event_t *events, int number, int duration)
{
    rt_tick_t tick;
    int result, index;

    if (sensor == NULL) return -1;

    tick = rt_tick_get();
    for (index = 0; index < number; index ++)
    {
        result = sensor->poll(&events[index]);
        if (result < 0) break;

        if (rt_tick_get() - tick > duration) break;
    }

    return index;
}

rt_sensor_t rt_sensor_get_default(int type)
{
    return (rt_sensor_t)SensorManager::getDefaultSensor(type);
}

int rt_sensor_subscribe(rt_sensor_t sensor, SensorEventHandler_t *handler, void *user_data)
{
    SensorBase *sensor_base;
    if (sensor == NULL) return -1;

    sensor_base = (SensorBase*)sensor;

    return sensor_base->subscribe(handler, user_data);
}

int rt_sensor_poll(rt_sensor_t sensor, sensors_event_t *event)
{
    SensorBase *sensor_base;
    if (sensor == NULL || event == NULL) return -1;

    sensor_base = (SensorBase*)sensor;
    return sensor_base->poll(event);
}

int rt_sensor_configure(rt_sensor_t sensor, SensorConfig *config)
{
    SensorBase *sensor_base;
    if (sensor == NULL || config == NULL) return -1;

    sensor_base = (SensorBase*)sensor;
    return sensor_base->setConfig(config);
}

int rt_sensor_activate(rt_sensor_t sensor, int enable)
{
    SensorBase *sensor_base;
    if (sensor == NULL) return -1;
    
    sensor_base = (SensorBase*)sensor;
    return sensor_base->activate(enable);
}