#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"
#include "settings_api.h"
#include "utility.h"
}

extern struct ringfs fs_log;
extern struct ringfs fs_ch_arch[];

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)
{
    log_entry_t log_entry;
    archive_entry_t archive_entry;
  
    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();
    }
    if (strcmp(argv[0], "os") == 0) {
        print_os_stat();
    }
    // ---------------------------------------------------------------------- //
    // Добавить N новых записей в журнал
    if (strcmp(argv[0], "add_lentry") == 0) {
        if (argc > 1)
            log_add_random_entry(0, atoi(argv[1]), 0);
        else
            printf("No record counter\r\n");
        
        return 0;
    }
    // Добавить N новых записей в архив
    if (strcmp(argv[0], "add_aentry") == 0) {
        if (argc > 2)
            log_add_random_entry(1, atoi(argv[1]), atoi(argv[2]));
        else
            printf("No record counter\r\n");
        
        return 0;
    }
    // Информация о журнале
    if (strcmp(argv[0], "linfo") == 0) {
        log_info(0, 0);
        return 0;
    }
    // Информация об архиве
    if (strcmp(argv[0], "ainfo") == 0) {
        if (argc > 1) {
            log_info(1, atoi(argv[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) {
        if (argc > 1) {
            log_format(0, 0);  
        }
        return 0;
    }
    // Format archive FS
    if (strcmp(argv[0], "aformat") == 0) {
        if (argc > 1) {
            log_format(1, atoi(argv[1]));  
        }
        return 0;
    }
    // 
    if (strcmp(argv[0], "lget") == 0) {
        log_get_log_entry(atoi(argv[1]), &fs_log, &log_entry);
        return 0;
    }
    // 
#if defined (MDIO_88) || (MAI_12)                 
    if (strcmp(argv[0], "aget") == 0) {

        if (argc > 2)
            log_get_archive_entry(atoi(argv[1]), &fs_ch_arch[atoi(argv[2])], &archive_entry);
        return 0;
    }
#endif    
    //
    if (strcmp(argv[0], "lstate") == 0) {
        if (argc > 1)
            log_log_state(atoi(argv[1]));
        return 0;
    }
    //
    if (strcmp(argv[0], "astate") == 0) {
        if (argc > 1)
            log_archive_state(atoi(argv[1]));
        return 0;
    }
    // ---------------------------------------------------------------------- //
    if (strcmp(argv[0], "mstime") == 0) {
        TM_RTC_PrintTime();
        printf("\r\n%" PRId64 " [ms]\r\n", rtc_get_ms());
        return 0;
    }
    // 
    if (strcmp(argv[0], "settings") == 0) {
        settings_print();
        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 ("  os                               Print os statistic");
    printl ("  add_lentry                       Add N log entries");
    printl ("  add_aentry [entries] [channel]   Add N archive entries to channel");
    printl ("  linfo                            Print log info");
    printl ("  ainfo [channel]                  Print archive info");
    printl ("  afetch                           Fetch archive entry");
    printl ("  lformat                          Format log partition");
    printl ("  aformat [channel 0..7]           Format archive partition");
    printl ("  aget [entry index] [channel]     Get archive entry");
    printl ("  lget [entry index]               Get log entry");
    printl ("  lstate                           log enable/disable");
    printl ("  astate                           archive enable/disable");
    printl ("  mstime                           gurrnet rtc in ms");
    printl ("  settings                         Print settings structure");
    
    printeol();

    return 0;
}

//
int SbsTerminal::version(int argc, const char * const *argv) 
{
    printeol();
    print(FW_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);
        }
    }  
}
