/*
 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#ifndef DEVICE_POLICY_H
#define DEVICE_POLICY_H

#include <ctype.h>
#include "iotcs_device.h"
#include "iotcs/iotcs_private.h"
#include "device_model/device_model_private.h"
#include "util/util_thread_private.h"

#ifdef __cplusplus
extern "C" {
#endif
#define WINDOWS_COUNT 32
#define IOTCS_USE_PERSISTENCE 1
iotcs_result dm_get_policy(const char* endpoint_id, const char* device_model_urn);

double calculateDouble(char** line, iotcs_virtual_device_handle_t* device_handle, char *attribute_name, double offered_value);
int calculateInteger(char** line, iotcs_virtual_device_handle_t* device_handle, char *attribute_name, int offered_value);

typedef struct mean_function_t {
    int64_t window;
    int64_t slide;
} mean_function_t, max_function_t, min_function_t, eliminate_dubl_function_t, standard_deviation_function_t;

typedef struct alert_condition_t {
    char *condition;
    char *format;
    int fields_len;
    char *severity;
    iotcs_bool filter;
    iotcs_key_value *fields;
} alert_condition_t;

typedef struct detect_dubl_function_t {
    int64_t window;
    char *format;
    int fields_len;
    char *severity;
    iotcs_key_value *fields;
} detect_dubl_function_t;

typedef struct action_condition_t {
    char *condition;
    char *action;
    iotcs_key_value *arguments;
    int fields_len;
    iotcs_bool filter;
} action_condition_t;

typedef struct filter_condition_t {
    char *condition;
} filter_condition_t;

typedef struct computed_metric_t {
    char *formula;
} computed_metric_t;

typedef struct batch_time_t {
    char *severity;
    int64_t delay;
} batch_time_t;

typedef struct batch_size_t {
    char *severity;
    int64_t size;
} batch_size_t;

typedef struct sample_quality_t {
    int64_t rate;
    int64_t counter;
} sample_quality_t;

typedef union iotcs_pipeline_function_t {
    mean_function_t mean_function;
    max_function_t max_function;
    min_function_t min_function;
    eliminate_dubl_function_t eliminate_dubl_function;
    detect_dubl_function_t detect_dubl_function;
    standard_deviation_function_t standard_deviation_function;
    alert_condition_t alert_condition;
    sample_quality_t sample_quality;
    action_condition_t action_condition;
    filter_condition_t filter_condition;
    computed_metric_t computed_metric;
    batch_size_t batch_size;
    batch_time_t batch_time;
} iotcs_pipeline_function;

#define IOTCS_SAMPLE_QUALITY_RANDOM -1
#define IOTCS_SAMPLE_QUALITY_ALL 0
#define IOTCS_SAMPLE_QUALITY_NONE -2

typedef enum {
    IOTCS_FUNCTION_TYPE_MEAN = 0,
    IOTCS_FUNCTION_TYPE_MAX = 1,
    IOTCS_FUNCTION_TYPE_MIN = 2,
    IOTCS_FUNCTION_TYPE_ELIMINATE_DUBL = 3,
    IOTCS_FUNCTION_TYPE_DETECT_DUBL = 4,
    IOTCS_FUNCTION_TYPE_STANDARD_DEVIATION = 5,
    IOTCS_FUNCTION_TYPE_ALERT_CONDITION = 6,
    IOTCS_FUNCTION_TYPE_ACTION_CONDITION = 7,
    IOTCS_FUNCTION_TYPE_FILTER_CONDITION = 8,
    IOTCS_FUNCTION_TYPE_BATCH_TIME = 9,
    IOTCS_FUNCTION_TYPE_BATCH_SIZE = 10,
    IOTCS_FUNCTION_TYPE_COMPUTED_METRIC = 11,
    IOTCS_FUNCTION_TYPE_SAMPLE_QUALITY = 12,
    IOTCS_FUNCTION_TYPE_NONE = 64
} iotcs_pipeline_function_type;

typedef struct iotcs_pipeline_function_list_t {
    iotcs_pipeline_function function;
    iotcs_pipeline_function_type type;
    struct iotcs_pipeline_function_list_t *next;
} iotcs_pipeline_function_list_t;

typedef struct iotcs_pipeline_t {
    char *name;
    char *attribute;
    struct iotcs_pipeline_function_list_t *function_list;
    struct iotcs_pipeline_t *next;
} iotcs_pipeline_t;

typedef struct iotcs_policy_handle_t {
    char *name;
    char *urn;
    char *endpoint_id;
    struct iotcs_pipeline_t *pipe_list;
    struct iotcs_policy_handle_t* next;
} iotcs_policy_handle_t;

typedef struct iotcs_window_handle_t {
    iotcs_virtual_device_handle_t * device_handle;
    char *endpoint_id;
    char *attribute_name;
    int64_t last_offer_time;

    int value_index;
    int size;
    iotcs_typed_value *typed_value;
    int *count;
    int counter; // Used only for deviation

    void* args;
    iotcs_pipeline_function_type type;
    iotcs_pipeline_function_list_t *cur_function;
    int64_t sheduled_time;
    int64_t time_delta;
    int64_t time_last;
    iotcs_message *message;
} iotcs_window_handle_t;

void dm_release_policy(iotcs_policy_handle_t* policy);
void dm_remove_policy(char* urn, char* name);
iotcs_result dm_parse_policy_fromJSON(char *device_model, json_tokens_t* tok, iotcs_policy_handle_t** policy);
iotcs_result dm_add_policy_fromJSON(char *endpoint_id, char *device_model, json_tokens_t* tok);
iotcs_result dm_policy_from_server(const char* endpoint_id, const char* device_model_urn, char** device_policy_json);
iotcs_bool find_and_put_attribute_value(iotcs_pipeline_function_list_t *cur_policy, iotcs_virtual_device_handle_t* virtual_device_handle,
                                        char *attribute_name, iotcs_message *message);
iotcs_bool detect_dublicates(iotcs_pipeline_function_list_t *cur_pipe, iotcs_virtual_device_handle_t* virtual_device_handle,
                                        char *attribute_name, iotcs_message *message);
iotcs_result dm_load_local_policy(const char* endpoint_id, iotcs_request_message *request, iotcs_bool overwrite);
iotcs_result dm_load_local_policy_unsafe(const char* endpoint_id, iotcs_request_message *request, iotcs_bool overwrite);
iotcs_result dm_init_policy();
void proceed_policy(int i);
iotcs_bool apply_policy(iotcs_virtual_device_handle_t* virtual_device_handle, iotcs_message *message);
iotcs_result dm_get_policy_unsafe(const char* endpoint_id, const char* device_model_urn);

extern iotcs_policy_handle_t* g_policy_list;
UTIL_DECL_POLICY_LOCK();
#ifdef __cplusplus
}
#endif

#endif /* DEVICE_POLICY_H */
