/* ----------------------------------------------------------------------
* Copyright (c) 2020 SensiML Coproration
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------- */

#ifndef __KB_H__
#define __KB_H__
#include "kb_typedefs.h"
#include "kb_defines.h"

//Total Models in this Knowledge Pack
#define SENSIML_NUMBER_OF_MODELS 1

//Model Indexes to use for calls
#define KB_MODEL_window_size_2048_f1_score_rank_0_INDEX 0

#define MAX_VECTOR_SIZE 30

//FILL_SENSIML_SENSOR_USAGES

// clang-format off
#ifdef __cplusplus
extern "C"
{
#endif


/**
* @brief Initialize the parameters of all the models, must be run first.
*/
void kb_model_init();

/**
* @brief Main Pipeline entry point.
*
* This is the main entry point into the pipeline. It takes a single
* timepoint of data as an array. Adds that sample to the internal ring buffer
* checks for a segment, generates features if there is a segment,
* produces a classification and returns the result.
* Classification results will be 0 if unkown through the classification numbers
* you have. This function returns -1 when a segment hasn't yet been identified.
* returns -2 when a segment has been filtered
*
*
* @param[in] pSample Pointer to a single time point of data accross senseors (ie. ax,ay,az)
* @param[in] nsesnors (unused currently)
* @param[in] model_index Model index to use.
*/
int kb_run_model(SENSOR_DATA_T *pSample, int nsensors, int model_index);

/**
* @brief Advance the model so it is ready for new sample data
* This should be used once you have recieved a
* classification and are done with the data in the buffer
*
* Inputs:
*		model index - index of the model to retrain
*/
int kb_reset_model(int model_index);

/**
* @brief Flush the internal data buffer of a model
*
* Inputs:
*		model index - index of the model to flush the buffer
*/
int kb_flush_model_buffer(int model_index);

/**
* @brief Run model with cascade feature resets.
*
* This performs the same as kb_run_model, but is meant for models using cascade
* feature generation where it will only classify after all of the feature banks
* in the cascade have been filled, then reset the number of feature banks to 0.
* This is different from run model, which treats the feature banks as a circular
* buffer and constantly classifiers
* Classification results will be 0 if unkown through the classification numbers
* you have. This function returns -1 when it is wainting for more data to create
* a classification.* returns -2 when features were generated for a feature bank
*
*
* @param[in] pSample Pointer to a single time point of data accross senseors (ie. ax,ay,az)
* @param[in] nsesnors (unused currently)
* @param[in] model_index Model index to use.
*/

int kb_run_model_with_cascade_reset(SENSOR_DATA_T *pSample, int nsensors, int model_index);

/**
* @brief Add a custom segment to the pipeline for classification.
*
* Setup the model ring buffer with the user provided
* buffer to be used as well as its size.
*
* @param[in] pSample Pointer to a buffer to use.
* @param[in] len length of the ring buffer.
* @param[in] nbuffs Number of buffers of length len to create in pBuffer pointer.
* @param[in] model_index Model index to use.
*/
void kb_add_segment(uint16_t *pBuffer, int len, int nbuffs, int model_index);

/**
* Runs the pipeline starting a segmentation through classification.
*
* @param[in] model_index Model index to use.
*/
int kb_run_segment(int model_index);

/**
* @brief This performs the same as kb_run_segment, but is meant for models using cascade
* feature generation where the user desires classifications only after all of the feature banks
* in the cascade have been filled. After classification all of the feature banks are emptied.
* This is different from run model, which treats the feature banks as a circular
* buffer and constantly classifiers popping the oldest and adding the newest.
* Classification results will be 0 if unkown through the classification numbers
* you have. This function returns -1 when it is wainting for more data to create
* returns -2 when features were generated for a feature bank
* a classification
*
* @param[in] model_index Model index to use.
*/
int kb_run_segment_with_cascade_reset(int model_index);

/**
* @brief Print the model name to map relationship
*
*/
void kb_print_model_map();

void kb_print_model_class_map(int model_index, char *output);

/**
* @brief Prints the current information for the model
*
* @param[in] model_index Model index to use.
* @param[in] result result from most recent classification
*/
void sml_print_model_result(int model_index, int result);
#define kb_print_model_result sml_print_model_result

/**
* @brief Prints the model  score for specified index
*
* @param[in] model_index Model index to use.
*/
int sml_print_model_score(int model_index);
#define kb_print_model_score sml_print_model_score

/**
* @brief Get the model header information for model index
*
* @param[in] model_index Model index to use.
* @param[in] pointer struct for the particular type of classifier (defined in kb_typdefs.h).
*
*  Returns:
*      1 if successful
*      0 if not supported for this classifier
*/

int get_model_header(int model_index, void *model_header);

/**
* @brief Prints the model class map
*
* @param[in] model_index Model index to use.
* @param[in] pattern_index Pattern index in the classifier to retrieve.
* @param[in] pointer struct for the particular type of classifier pattern (defined in kb_typdefs.h).
*
* Returns:
*      1 if successful
*      0 if not supported for this classifier, or pattern index is out of bounds
*/
int get_model_pattern(int model_index, int pattern_index, void *pattern);

/**
* @brief Set the number of stored patterns in a model to 0
*
* Inputs:
*		model index -index of the model to reset
*/
int flush_model(int model_index);

/**
* @brief Expand model with most recent pattern.
*
* After recieving a classification, you can tell the model to add this classifiaction as
*  a pattern with a specific category as well as an influence field. The larger the field
* the larger the area this pattern can be activiated in. This can be used to add
*
*/
int kb_add_last_pattern_to_model(int model_index, uint16_t category, uint16_t influence);

/**
* @brief Retrains the model by adding the a custom feature vector with a new label
*
*
* Inputs:
*		model index - number of axes in the data stream
*      category - category of the vector to add
*      influence - amount of weight we should give to this new feature vector when training the model
*
* Returns:
* 		0 if model does not support dynamic updates
* 		-1 if model can not be updated anymore
* 		1 if model was succesfully updated
*/
int kb_add_custom_pattern_to_model(int model_index, uint8_t *feature_vector, uint16_t category, uint16_t influence);

/***
* @brief scores the current model based on the input category
*
*
* Inputs:
*		model index - number of axes in the data stream
*      category - category of the vector to add
*
* Returns:
* 		0 if model does not support scoring
* 		-1 if model can not be scored anymore
* 		1 if model was succesfully scored
*/
int kb_score_model(int model_index, uint16_t category);

/***
* @brief retrain model based on scores
*
*
* Inputs:
*		model index - number of axes in the data stream
*
* Returns:
* 		0 if model does not support retraining
* 		1 if model was succesfully retrained
*/
int kb_retrain_model(int model_index);

/**
* @brief Gets the pointer to 16-byte UUID of model
*
* @param[in] model_index Model index to get UUID from
* @return uint8_t* Pointer to 16-byte UUID for model
*/
const uint8_t *sml_get_model_uuid_ptr(int model_index);

/**
* @brief Gets the Segment for debug printing, saving.
*
* @param[in] model_index Model index to use.
* @param[out] p_seg_len pointer to segment length
*/
void sml_get_segment_length(int model_index, int *p_seg_len);

/**
* @brief Gets segment sample data
*
* @param[in] model_index Model Index to use
* @param[in] sample_num Sample number to retrieve
* @param[out] p_sample_len pointer to sample length
* @param[out] p_sample_data pointer to use for sample data array
*/
void sml_get_segment_sample(int model_index, int sample_num, int *p_sample_len, SENSOR_DATA_T *p_sample_data);

/**
* @brief Get Debug logging level, if enabled
*
* @return int 1-4, or 0 if disabled.
*/
int sml_get_log_level();

/**
* @brief Gets feature vector for debug.
*
* @param[in] model_index Model index to use.
* @param[out] fv_arr Feature Vector to copy into
* @param[out] p_fv_len Feature vector length to copy
*/
void kb_get_feature_vector(int model_index, uint8_t *fv_arr, uint8_t *p_fv_len);
#define sml_get_feature_vector kb_get_feature_vector

#if SML_ADD_SEGMENT_DATA
/**
* @brief Gets the Segment for debug.
*
* @param[in] model_index Model index to use.
* @param[out] fv_arr Feature Vector to copy into
* @param[out] p_fv_len Feature vector length to copy
*/
void sml_get_segment_data(int model_index, SENSOR_DATA_T *seg_arr, uint16_t *p_seg_len);
#define kb_get_segment_data sml_get_segment_data
#endif



int print_sml_classification_result_info(char *pbuf, int model_index);


/**
* @brief Set the feature vector for a model
*
* @param[int] model_index Model index to use.
* @param[uint8_t *] feature_vector to set the model input to
*
* @returns[int] the count of features that were set
*/
int sml_set_feature_vector(int model_index, uint8_t * feature_vector);

/**
* @brief Recognize a feature vector that is in the model buffer
*
* @param[int] model_index Model index to use.
*
* @returns[uint16_t] classification result
*/
uint16_t sml_recognize_feature_vector(int model_index);

/**
* @brief Gets the Segment for debug.
*
* @param[int] model_index Model index to use.
* @param[void *] model result object, specific to the model you are getting results for
*
* @returns[int] 1 if success, 0 if not applicatbale to this model type
*/
int sml_classification_result_info(int model_index, void * model_results);


#ifdef __cplusplus
}
#endif

// clang-format on

#endif //__KB_H__
