#ifndef __APP_CURTAIN_MOTOR_H_
#define __APP_CURTAIN_MOTOR_H_


#include <stdint.h>
#include "generic_onoff_server.h"
#include "generic_level_server.h"
#include "generic_dtt_server.h"
#include "app_transition.h"
#include "app_timer.h"
#if (SCENE_SETUP_SERVER_INSTANCES_MAX > 0)
#include "app_scene.h"
#endif
#include "list.h"



#define CURTAIN_MOTOR_LEVEL_LAST_MIN    (1)
#define REMAINING_TIME_UNKNOWN          MIN_TO_MS(2)



/* macro to create application level app_curtain_motor_server_t context */
#define APP_CURTAIN_MOTOR_SERVER_DEF(_name, _force_segmented, _mic_size, _set_cb, _get_cb, _transition_cb)  \
    APP_TIMER_DEF(_name ## _timer); \
    static app_curtain_motor_server_t _name =  \
    {  \
        .onoff_server.settings.force_segmented = _force_segmented,  \
        .onoff_server.settings.transmic_size = _mic_size,  \
        .level_server.settings.force_segmented = _force_segmented,  \
        .level_server.settings.transmic_size = _mic_size,  \
        .dtt_server.settings.force_segmented = _force_segmented,  \
        .dtt_server.settings.transmic_size = _mic_size,  \
        .state.transition.timer.p_timer_id = &_name ## _timer,  \
        .set_cb = _set_cb,  \
        .get_cb = _get_cb,  \
        .transition_cb = _transition_cb,  \
    };



/* internal structure to hold state and timing information. */
typedef struct app_curtain_motor_state_s {
    bool initialized;

    uint16_t present_level;
    uint16_t target_level;
    uint16_t initial_present_level;

    uint16_t init_present_snapshot;
    uint16_t target_snapshot;

    bool new_tid;

    uint32_t published_ms;

    app_transition_t transition;
} app_curtain_motor_state_t;


/* forward declaration */
typedef struct app_curtain_motor_server_s app_curtain_motor_server_t;


/* application state set callback prototype */
typedef void (*app_curtain_motor_set_cb_t)(const app_curtain_motor_server_t *p_app, uint16_t level);
typedef void (*app_curtain_motor_get_cb_t)(const app_curtain_motor_server_t *p_app, uint16_t *p_present_level);
typedef void (*app_curtain_motor_transition_cb_t)(const app_curtain_motor_server_t *p_app,
                                                  uint32_t transition_time_ms, uint16_t target_level);


/* application level structure holding the Level server model context and Level state representation */
struct app_curtain_motor_server_s {
    generic_onoff_server_t onoff_server;
    generic_level_server_t level_server;
    generic_dtt_server_t dtt_server;

    app_curtain_motor_set_cb_t set_cb;
    app_curtain_motor_get_cb_t get_cb;
    app_curtain_motor_transition_cb_t transition_cb;

    app_curtain_motor_state_t state;
    uint8_t element_index;

#if (SCENE_SETUP_SERVER_INSTANCES_MAX > 0)
    app_scene_model_interface_t scene_if;
    app_scene_setup_server_t  *p_app_scene;
#endif

    bool abort_move;
    list_node_t node;
};



uint32_t app_curtain_motor_init(app_curtain_motor_server_t *p_app, uint8_t element_index);
uint32_t app_curtain_motor_binding_setup(app_curtain_motor_server_t *p_app);
uint32_t app_curtain_motor_direct_actual_set(app_curtain_motor_server_t *p_app, uint16_t level_value);
uint32_t app_curtain_motor_current_value_publish(app_curtain_motor_server_t *p_app);

#if SCENE_SETUP_SERVER_INSTANCES_MAX > 0
uint32_t app_curtain_motor_scene_context_set(app_curtain_motor_server_t *p_app,
                                             app_scene_setup_server_t *p_app_scene);
#endif



#endif /* __APP_CURTAIN_MOTOR_H_ */
