#include "scene_switch_4_mc.h"
#include "nrf_mesh_config_app.h"
#include "mesh_config_entry.h"
#include "mesh_config.h"
#include "mesh_opt.h"



typedef struct
{
    uint16_t scene_number[SCENE_SWITCH_4_SCENES_MAX];
    uint32_t transition_time_ms;
    uint32_t delay_ms;
} scene_switch_4_storage_cfg_t;



/* setter and getter declarations */
static uint32_t scene_switch_4_setter(mesh_config_entry_id_t id, const void *p_entry);
static void scene_switch_4_getter(mesh_config_entry_id_t id, void *p_entry);



MESH_CONFIG_ENTRY(scene_switch_4_state_entry,
                  SCENE_SWITCH_4_STATE_EID,                     /* base entry id */
                  SCENE_SWITCH_4_INSTANCES_MAX,                 /* number of instances */
                  sizeof(scene_switch_4_storage_cfg_t),         /* size of an instance */
                  scene_switch_4_setter,                        /* stores a value in primary memory */
                  scene_switch_4_getter,                        /* retrieve a value from primary memory */
                  NULL,                                         /* no need for a delete callback */
                  true);                                        /* there is a default value */

/* array for mapping from a handle to a state pointer */
static scene_switch_4_storage_cfg_t m_state_contexts[SCENE_SWITCH_4_INSTANCES_MAX];
static uint8_t m_next_handle;

static scene_switch_4_storage_cfg_t *context_get(uint8_t i)
{
    NRF_MESH_ASSERT(i < m_next_handle);
    return &m_state_contexts[i];
}

static void state_contexts_default_set(uint8_t handle)
{
    uint16_t default_scene_num[SCENE_SWITCH_4_INSTANCES_MAX][SCENE_SWITCH_4_SCENES_MAX] = SCENE_SWITCH_4_DEFAULT_SCENE_NUMBER;

    for (int i = 0; i < SCENE_SWITCH_4_SCENES_MAX; i++) {
        m_state_contexts[handle].scene_number[i] = default_scene_num[handle][i];
    }
    m_state_contexts[handle].transition_time_ms = SCENE_SWITCH_4_TRANSITION_TIME_MS;
    m_state_contexts[handle].delay_ms = SCENE_SWITCH_4_DELAY_MS;
}

static void state_contexts_all_default_set()
{
    for (int i = 0; i < ARRAY_SIZE(m_state_contexts); i++) {
        state_contexts_default_set(i);
    }
}

static void scene_switch_4_flash_storage_config_clear()
{
    const struct {
        const mesh_config_entry_id_t * const id;
    } entries[] = {
        { &SCENE_SWITCH_4_STATE_EID }
    };

    state_contexts_all_default_set();

    for (uint16_t j = 0; j < ARRAY_SIZE(entries); j++) {
        mesh_config_entry_id_t id = *entries[j].id;
        for (uint8_t i = 0; i < m_next_handle; i++) {
            (void) mesh_config_entry_delete(id);
            id.record++;
        }
    }
}



/* setter and getter definitions */

static uint32_t scene_switch_4_setter(mesh_config_entry_id_t id, const void *p_entry)
{
    uint16_t instance_index = id.record - SCENE_SWITCH_4_EID_START;
    scene_switch_4_storage_cfg_t *ctx = context_get(instance_index);
    const scene_switch_4_cfg_t *p_value = (const scene_switch_4_cfg_t *)p_entry;

    for (int i = 0; i < SCENE_SWITCH_4_SCENES_MAX; i++) {
        ctx->scene_number[i] = p_value->scene_number[i];
    }
    ctx->transition_time_ms = p_value->transition_time_ms;
    ctx->delay_ms = p_value->delay_ms;

    return NRF_SUCCESS;
}

static void scene_switch_4_getter(mesh_config_entry_id_t id, void *p_entry)
{
    uint16_t instance_index = id.record - SCENE_SWITCH_4_EID_START;
    scene_switch_4_storage_cfg_t *ctx = context_get(instance_index);
    scene_switch_4_cfg_t *p_value = (scene_switch_4_cfg_t *)p_entry;

    for (int i = 0; i < SCENE_SWITCH_4_SCENES_MAX; i++) {
        p_value->scene_number[i] = ctx->scene_number[i];
    }
    p_value->transition_time_ms = ctx->transition_time_ms;
    p_value->delay_ms = ctx->delay_ms;
}



/* API functions to set and get flash states */

uint32_t scene_switch_4_mc_state_set(uint8_t index, const scene_switch_4_cfg_t *p_value)
{
    mesh_config_entry_id_t id = SCENE_SWITCH_4_STATE_EID;

    id.record += index;
    return mesh_config_entry_set(id, p_value);
}


uint32_t scene_switch_4_mc_state_get(uint8_t index, scene_switch_4_cfg_t *p_value)
{
    mesh_config_entry_id_t id = SCENE_SWITCH_4_STATE_EID;

    id.record += index;
    return mesh_config_entry_get(id, p_value);
}


void scene_switch_4_mc_clear(void)
{
    scene_switch_4_flash_storage_config_clear();
    const struct {
        const mesh_config_entry_id_t * const id;
        const uint16_t start;
    } entries[] = {
        { &SCENE_SWITCH_4_STATE_EID, SCENE_SWITCH_4_EID_START }
    };

    state_contexts_all_default_set();

    for (uint16_t j = 0; j < ARRAY_SIZE(entries); j++) {
        mesh_config_entry_id_t id = *entries[j].id;
        for (uint8_t i = 0; i < m_next_handle; i++) {
            id.record = entries[j].start + i;
            (void) mesh_config_entry_delete(id);
        }
    }
}


uint32_t scene_switch_4_mc_open(uint8_t *p_handle)
{
    if (p_handle == NULL) {
        return NRF_ERROR_NULL;
    }

    if (SCENE_SWITCH_4_INSTANCES_MAX <= m_next_handle) {
        return NRF_ERROR_RESOURCES;
    }

    *p_handle = m_next_handle++;
    return NRF_SUCCESS;
}


void scene_switch_4_mc_init(void)
{
    state_contexts_all_default_set();
}
