/**
 * Destroys the given buffer.  Note that the given pointer will no longer
 * be valid.
 */
void ring_buffer_destroy(struct ring_buff *rb)
{
        if (rb->buff)
                portFree(rb->buff);

        portFree(rb);
}
void ShowTaskInfo(Serial *serial, unsigned int argc, char **argv)
{
    putHeader(serial, "Task Info");

    serial->put_s("Status\tPri\tStackHR\tTask#\tName");
    put_crlf(serial);

    /*
     * Memory info from vTaskList can be misleading.  See
     * http://www.freertos.org/uxTaskGetSystemState.html for
     * more detail about how it works and value meanings.
     */
    char *taskList = (char *) portMalloc(1024);
    if (NULL != taskList) {
        vTaskList(taskList);
        serial->put_s(taskList);
        portFree(taskList);
    } else {
        serial->put_s("Out of Memory!");
    }
    put_crlf(serial);

    put_crlf(serial);
    serial->put_s("[Note] StackHR: If StackHR < 0; then stack smash");
    put_crlf(serial);
}
enum script_add_result flashScriptPage(const unsigned int page,
                                       const char *data,
                                       const enum script_add_mode mode)
{
        if (page >= MAX_SCRIPT_PAGES) {
                pr_error("lua: invalid script index\r\n");
                return SCRIPT_ADD_RESULT_FAIL;
        }

        switch (mode) {
        case SCRIPT_ADD_MODE_IN_PROGRESS:
        case SCRIPT_ADD_MODE_COMPLETE:
                /* Valid cases.  Carry on */
                break;
        default:
                pr_error_int_msg("lua: Unknown script_add_mode: ", mode);
                return SCRIPT_ADD_RESULT_FAIL;
        }

        static ScriptConfig *g_scriptBuffer;
        if (NULL == g_scriptBuffer) {
                terminate_lua();

                pr_debug("lua: Allocating new script buffer\r\n");
                g_scriptBuffer =
                        (ScriptConfig *) portMalloc(sizeof(ScriptConfig));
                memcpy((void *)g_scriptBuffer, (void *)&g_scriptConfig,
                       sizeof(ScriptConfig));
        }

        if (NULL == g_scriptBuffer) {
                pr_error("lua: Failed to allocate memory for script "
                         "buffer.\r\n");
                return SCRIPT_ADD_RESULT_FAIL;
        }

        char *pageToAdd = g_scriptBuffer->script + page * SCRIPT_PAGE_SIZE;
        strncpy(pageToAdd, data, SCRIPT_PAGE_SIZE);

        if (SCRIPT_ADD_MODE_IN_PROGRESS == mode)
                return SCRIPT_ADD_RESULT_OK;

        pr_info("lua: Completed updating LUA. Flashing... ");
        const int rc = memory_flash_region((void*) &g_scriptConfig,
                                           (void*) g_scriptBuffer,
                                           sizeof(ScriptConfig));
        portFree(g_scriptBuffer);
        g_scriptBuffer = NULL;

        if (0 != rc) {
                pr_info_int_msg("failed with code ", rc);
                return SCRIPT_ADD_RESULT_FAIL;
        }

        pr_info("win!\r\n");
        initialize_lua();
        return SCRIPT_ADD_RESULT_OK;
}
int api_getMeta(Serial *serial, const jsmntok_t *json){
	json_messageStart(serial);
	SampleRecord * sr = (SampleRecord *)portMalloc(sizeof(SampleRecord));
	if (sr == 0) return API_ERROR_SEVERE;

	initSampleRecord(getWorkingLoggerConfig(), sr);
	writeSampleMeta(serial, sr, getConnectivitySampleRateLimit(), 0);

	portFree(sr);
	json_blockEnd(serial, 0);
	return API_SUCCESS_NO_RETURN;
}
void * myAlloc (void *ud, void *ptr, size_t osize,size_t nsize) {
	
#ifdef ALLOC_DEBUG
	if (g_allocDebug){
		SendString("myAlloc- ptr:");
		SendUint((unsigned int)ptr);
		SendString(" osize:");
		SendInt(osize);
		SendString(" nsize:");
		SendInt(nsize);
	}
#endif

   if (nsize == 0) {
     portFree(ptr);
#ifdef ALLOC_DEBUG
     if (g_allocDebug){
    	 SendString(" (free)");
    	 SendCrlf();
     }
#endif
     return NULL;
   }
   else{
	 void *newPtr;
	 if (osize != nsize){
		 newPtr = portRealloc(ptr, nsize);
	 }
	 else{
		 newPtr = ptr;
	 }
#ifdef ALLOC_DEBUG
   	 if (g_allocDebug){
   		 if (ptr != newPtr){
   			 SendString(" newPtr:");
   			 SendUint((unsigned int)newPtr);
   		 }
   		 else{
   			 SendString(" (same)");
   		 }
		 SendCrlf();
   	 }
#endif
   	 lastPointer = (unsigned int)newPtr;
   	 return newPtr;
   }
}
void ShowTaskInfo(Serial *serial, unsigned int argc, char **argv){

	serial->put_s("Task Info");
	put_crlf(serial);
	serial->put_s("Status\tPri\tStack\tTask#\tName");
	put_crlf(serial);
	char *taskList = (char *)portMalloc(1024);
	if (NULL != taskList){
		vTaskList(taskList);
		serial->put_s(taskList);
		portFree(taskList);
	}
	else{
		serial->put_s("Out of Memory!");
	}
	put_crlf(serial);
}
int flash_default_script()
{
    int result = -1;
    pr_info("flashing default script...");

    /*
     * Stop LUA if we are flashing its data.  This is mainly done to recover
     * RAM since our flashing operation is a heavy bugger
     */
    terminate_lua();

    ScriptConfig *defaultScriptConfig = (ScriptConfig *)portMalloc(sizeof(ScriptConfig));
    if (defaultScriptConfig != NULL) {
        defaultScriptConfig->magicInit = MAGIC_NUMBER_SCRIPT_INIT;
        strncpy(defaultScriptConfig->script, DEFAULT_SCRIPT, sizeof(DEFAULT_SCRIPT));
        result = memory_flash_region((void *)&g_scriptConfig, (void *)defaultScriptConfig, sizeof (ScriptConfig));
        portFree(defaultScriptConfig);
    }
    if (result == 0) pr_info("win\r\n");
    else pr_info("fail\r\n");
    return result;
}
int api_sampleData(Serial *serial, const jsmntok_t *json){

	int sendMeta = 0;
	if (json->type == JSMN_OBJECT && json->size == 2){
		const jsmntok_t * meta = json + 1;
		const jsmntok_t * value = json + 2;

		jsmn_trimData(meta);
		jsmn_trimData(value);

		if (NAME_EQU("meta",meta->data)){
			sendMeta = modp_atoi(value->data);
		}
	}
	SampleRecord * sr = (SampleRecord *)portMalloc(sizeof(SampleRecord));
	if (sr == 0) return API_ERROR_SEVERE;

	LoggerConfig * config = getWorkingLoggerConfig();
	initSampleRecord(config, sr);
	populateSampleRecord(sr,0, config);
	api_sendSampleRecord(serial, sr, 0, sendMeta);
	portFree(sr);
	return API_SUCCESS_NO_RETURN;
}
void free_sample_buffer(struct sample *s)
{
        portFree(s->channel_samples);
        s->channel_samples = NULL;
}
void freeSampleRecordBuffer(SampleRecord ** sampleRecordBuffer){
	portFree(sampleRecordBuffer);
}
void free_ring_buffer(struct ring_buff *rb)
{
        portFree(rb->buf);
        rb->size = 0;
        rb->buf = rb->head = rb->tail = NULL;
}
enum track_add_result add_track(const Track *track, const size_t index,
                                const enum track_add_mode mode)
{
        if (index >= MAX_TRACK_COUNT) {
                pr_error("tracks: Invalid track index\r\n");
                return TRACK_ADD_RESULT_FAIL;
        }

        switch (mode) {
        case TRACK_ADD_MODE_IN_PROGRESS:
        case TRACK_ADD_MODE_COMPLETE:
                /* Valid cases.  Carry on */
                break;
        default:
                pr_error_int_msg("tracks: Unknown track_add_mode: ", mode);
                return TRACK_ADD_RESULT_FAIL;
        }

        static Tracks *g_tracksBuffer;
        if (NULL == g_tracksBuffer) {

#if LUA_SUPPORT
                lua_task_stop();
#endif /* LUA_SUPPORT */

                pr_debug("tracks: Allocating new tracks buffer\r\n");
                g_tracksBuffer = (Tracks *) portMalloc(sizeof(Tracks));
                memcpy(g_tracksBuffer, (void*) &g_tracks, sizeof(Tracks));
        }

        if (NULL == g_tracksBuffer) {
                pr_error("tracks: Failed to allocate memory for track buffer.\r\n");
                return TRACK_ADD_RESULT_FAIL;
        }

        Track *trackToAdd = g_tracksBuffer->tracks + index;
        memcpy(trackToAdd, track, sizeof(Track));
        g_tracksBuffer->count = index + 1;

        /* If we made it here and are still in progress, then we are done */
        if (TRACK_ADD_MODE_IN_PROGRESS == mode)
                return TRACK_ADD_RESULT_OK;

        /* If here, time to flash and tidy up */
        pr_info("tracks: Completed updating tracks. Flashing... ");
        const int rc = flash_tracks(g_tracksBuffer, sizeof(Tracks));
        portFree(g_tracksBuffer);
        g_tracksBuffer = NULL;

        if (0 != rc) {
                pr_info_int_msg("failed with code ", rc);
                return TRACK_ADD_RESULT_FAIL;
        }

        pr_info("win!\r\n");

#if LUA_SUPPORT
        lua_task_start();
#endif /* LUA_SUPPORT */

        return TRACK_ADD_RESULT_OK;
}