#include "terminal_sbs.h"
#include "common_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>

extern "C" {
#include "log.h"
#include "log_api.h"
#include "rtc.h"  
}

extern struct ringfs fs_archive;

SbsTerminal sbsTerminal;
Terminal* pTerminal; //Глобальный указатель на терминал

void vTerminal(void *params);


//
SbsTerminal::SbsTerminal() :
    Terminal()
{}

//
void SbsTerminal::configure()
{
    Terminal::configure();
    pTerminal = &sbsTerminal;
    
    m_dataQueue = xQueueCreate(20, 1);
    xTaskCreate(vTerminal, "terminal", 4*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);    
}

//
int SbsTerminal::execute(int argc, const char * const *argv)
{
    //char str[20];
  
    if (argc <= 0) {
        return -1;
    }
    if (strcmp(argv[0], "help") == 0) {
        return help(argc, argv);
    }
    if (strcmp(argv[0], "version") == 0) {
        return version(argc, argv);
    }
    if (strcmp(argv[0], "reset") == 0) {
        NVIC_SystemReset();
    }
    // ---------------------------------------------------------------------- //
    // Добавить N новых записей в журнал
    if (strcmp(argv[0], "add_lentry") == 0) {
        if (argc > 1)
            log_add_random_entry(0, atoi(argv[1]));
        else
            printf("No record counter\r\n");
        
        return 0;
    }
    // Добавить N новых записей в архив
    if (strcmp(argv[0], "add_aentry") == 0) {
        if (argc > 1)
            log_add_random_entry(1, atoi(argv[1]));
        else
            printf("No record counter\r\n");
        
        return 0;
    }
    // Информация о журнале
    if (strcmp(argv[0], "linfo") == 0) {
        log_info(0);
        return 0;
    }
    // Информация об архиве
    if (strcmp(argv[0], "ainfo") == 0) {
        log_info(1);
        return 0;
    }
    // Fetch archive entry
    if (strcmp(argv[0], "afetch") == 0) {
        test_fetch();
        return 0;
    }
    // Format log FS
    if (strcmp(argv[0], "lformat") == 0) {
        log_format(0);  
        return 0;
    }
    // Format archive FS
    if (strcmp(argv[0], "aformat") == 0) {
        log_format(1);  
        return 0;
    }
    // 
    if (strcmp(argv[0], "get") == 0) {
        archive_entry_t entry;
        log_get_entry(atoi(argv[1]), &fs_archive, &entry);
        return 0;
    }
    // ---------------------------------------------------------------------- //
    if (strcmp(argv[0], "mstime") == 0) {
        printf("\r\n%" PRId64 " [ms]\r\n", rtc_get_ms());
        return 0;
    }
    
    // ---------------------------------------------------------------------- //
    else {
        printeol();
        printll("Uncknown command [oO]");
        return -1;
    }
    
}

void SbsTerminal::sigint() {
}

//Колбэк, который может быть вызван при подключении
void SbsTerminal::connectCallback() 
{
    clearScreen();
    printll("SBS terminal.");
  
    //Тут выводим полезную при подключении информацию
    printeol();
    printll("For help type 'help'.");
    insert('\r');    
}
    

//
int SbsTerminal::help(int argc, const char * const *argv)
{
    printeol();
    printeol();
    printl ("You can use the following commands:");
    printl ("  version        Print software version");
    printl ("  reset          Reset");
    printl ("  add_lentry     Add N log entries");
    printl ("  add_aentry     Add N archive entries");
    printl ("  linfo          Print log info");
    printl ("  ainfo          Print archive info");
    printl ("  afetch         Fetch archive entry");
    printl ("  aentry         Get archive entry [position] [sector] [slot]");
    printll("  lformat        Format log partition");
    printll("  aformat        Format archive partition");
    
    printeol();

    return 0;
}

//
int SbsTerminal::version(int argc, const char * const *argv) 
{
    printeol();
    print(VERSION);
    printeol();
    return 0;
}

//
int SbsTerminal::clear(int argc, const char * const *argv)
{
    if ((argc > 1) && (strcmp(argv[1], "help") == 0))  
    {
        printeol();
        printl("Clear terminal screen");      
        printeol();
        printeol();
        return 0;
    }
    clearScreen();
    return 0;
}

//
void SbsTerminal::put_byte(char byte)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(m_dataQueue, &byte, &xHigherPriorityTaskWoken);
}

//
void vTerminal(void *params)
{
    char val;
    
    for (;;)
    {
        if (xQueueReceive(sbsTerminal.m_dataQueue, &val, 1000 ) == pdPASS)
        {
            sbsTerminal.insert(val);
        }
    }  
}
