/*
 * Copyright (c) 2019 - 2024 Stefan Strobel <stefan.strobel@shimatta.net>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

/**
 * @file    test_integration_busy.cpp
 * @brief   integration test implementation for the cmd busy function
 * @author  Stefan Strobel <stefan.strobel@shimatta.net>
 */

#include "test/framework/catch.hpp"
extern "C" {
#include "shellmatta.h"
}
#include <string.h>

static uint32_t write_callCnt = 0u;
static char write_data[1024];
static uint32_t write_length;
static uint32_t contCallCnt;
static uint32_t busyCallCnt;

static shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
    write_callCnt ++;
    while((length > 0) && (write_length < sizeof(write_data)))
    {
        write_data[write_length] = *data;
        data ++;
        length --;
        write_length ++;
    }

    return SHELLMATTA_OK;
}

static shellmatta_retCode_t continueCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
    (void)      handle;
    (void)      arguments;
    (void)      length;
    shellmatta_retCode_t ret        = SHELLMATTA_CONTINUE;
    char *stdinData;
    uint32_t stdinLength = 0u;

    shellmatta_read(handle, &stdinData, &stdinLength);
    if(NULL == stdinData)
    {
        stdinData = (char *)"";
    }
    
    shellmatta_printf(handle, "arguments: %s length: %u\r\n", stdinData, stdinLength);

    /** change to busy mode when k is pressed */
    if('k' == stdinData[0])
    {
        ret = SHELLMATTA_BUSY;
        busyCallCnt ++;
    }

    if(busyCallCnt > 1u)
    {
        ret = SHELLMATTA_CONTINUE;
    }

    if(contCallCnt >= 9u)
    {
        ret = SHELLMATTA_OK;
    }

    /* -# the arguments shall stay the same on every call - data is transferred per stdin */
    CHECK(length == 28u);
    CHECK_THAT(arguments, Catch::Matchers::Equals("continue some arguments meow"));

    contCallCnt ++;

    return ret;
}
shellmatta_cmd_t continueCmd = {(char*)"continue", (char*)"c", NULL, NULL, continueCmdFct, NULL};


TEST_CASE( "shellmatta continue 1" ) {

    shellmatta_retCode_t ret;
    shellmatta_instance_t inst;
    shellmatta_handle_t handle;
    char buffer[1024];
    char historyBuffer[1024];
    char *dummyData =   (char*) "continue some arguments meow\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments: a length: 1\r\n"
                                "arguments: b length: 1\r\n"
                                "arguments: c length: 1\r\n"
                                "arguments: 8 length: 1\r\n"
                                "arguments: 7 length: 1\r\n"
                                "arguments: 6 length: 1\r\n"
                                "arguments: 5 length: 1\r\n"
                                "arguments:  length: 0\r\n"
                                "\r\n"
                                "shellmatta->\r\n"
                                "shellmatta->";

    shellmatta_doInit(  &inst,
                        &handle,
                        buffer,
                        sizeof(buffer),
                        historyBuffer,
                        sizeof(historyBuffer),
                        "shellmatta->",
                        NULL,
                        writeFct);

    contCallCnt = 0u;
    busyCallCnt = 0u;
    write_callCnt = 0u;
    memset(write_data, 0, sizeof(write_data));
    write_length = 0u;

    shellmatta_addCmd(handle, &continueCmd);

    ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# call without any argument */
    ret = shellmatta_processData(handle, NULL, 0);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# pass some argument */
    ret = shellmatta_processData(handle, (char*)"abc", 3);
    CHECK(SHELLMATTA_CONTINUE == ret);

    ret = shellmatta_processData(handle, (char*)"8765", 4);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# call without any argument */
    ret = shellmatta_processData(handle, NULL, 0);
    CHECK(SHELLMATTA_OK == ret);

    /** -# continue session should be over */
    ret = shellmatta_processData(handle, (char*)"\r", 1);
    CHECK(SHELLMATTA_OK == ret);

    CHECK( 0u  == busyCallCnt);
    CHECK( 10u  == contCallCnt);
    CHECK( write_length == strlen(dummyData));
    REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData));
}

TEST_CASE( "shellmatta continue cancel" ) {

    shellmatta_retCode_t ret;
    shellmatta_instance_t inst;
    shellmatta_handle_t handle;
    char buffer[1024];
    char historyBuffer[1024];
    char *dummyData =   (char*) "continue some arguments meow\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments: a length: 1\r\n"
                                "arguments: b length: 1\r\n"
                                "arguments: \x03 length: 1\r\n"
                                "\r\n"
                                "shellmatta->\r\n"
                                "shellmatta->";

    shellmatta_doInit(  &inst,
                        &handle,
                        buffer,
                        sizeof(buffer),
                        historyBuffer,
                        sizeof(historyBuffer),
                        "shellmatta->",
                        NULL,
                        writeFct);

    contCallCnt = 0u;
    busyCallCnt = 0u;
    write_callCnt = 0u;
    memset(write_data, 0, sizeof(write_data));
    write_length = 0u;

    shellmatta_addCmd(handle, &continueCmd);

    ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# call without any argument */
    ret = shellmatta_processData(handle, NULL, 0);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# pass some argument */
    ret = shellmatta_processData(handle, (char*)"ab", 2);
    CHECK(SHELLMATTA_CONTINUE == ret);

    ret = shellmatta_processData(handle, (char*)"\x03", 1);
    CHECK(SHELLMATTA_OK == ret);

    /** -# continue session should be over */
    ret = shellmatta_processData(handle, (char*)"\r", 1);
    CHECK(SHELLMATTA_OK == ret);

    CHECK( 0u  == busyCallCnt);
    CHECK( 5u  == contCallCnt);
    CHECK( write_length == strlen(dummyData));
    REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData));
}

TEST_CASE( "shellmatta continue suspend with busy mode" ) {

    shellmatta_retCode_t ret;
    shellmatta_instance_t inst;
    shellmatta_handle_t handle;
    char buffer[1024];
    char historyBuffer[1024];
    char *dummyData =   (char*) "continue some arguments meow\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments: a length: 1\r\n"
                                "arguments: b length: 1\r\n"
                                "arguments: k length: 1\r\n"
                                "arguments: k length: 1\r\n"
                                "arguments:  length: 0\r\n"
                                "arguments: a length: 1\r\n"
                                "arguments: b length: 1\r\n"
                                "arguments: c length: 1\r\n"
                                "\r\n"
                                "shellmatta->\r\n"
                                "shellmatta->";

    shellmatta_doInit(  &inst,
                        &handle,
                        buffer,
                        sizeof(buffer),
                        historyBuffer,
                        sizeof(historyBuffer),
                        "shellmatta->",
                        NULL,
                        writeFct);

    contCallCnt = 0u;
    busyCallCnt = 0u;
    write_callCnt = 0u;
    memset(write_data, 0, sizeof(write_data));
    write_length = 0u;

    shellmatta_addCmd(handle, &continueCmd);

    ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# call without any argument */
    ret = shellmatta_processData(handle, NULL, 0);
    CHECK(SHELLMATTA_CONTINUE == ret);

    /** -# pass some argument */
    ret = shellmatta_processData(handle, (char*)"ab", 2);
    CHECK(SHELLMATTA_CONTINUE == ret);

    ret = shellmatta_processData(handle, (char*)"k", 1);
    CHECK(SHELLMATTA_BUSY == ret);

    ret = shellmatta_processData(handle, (char*)"k", 1);
    CHECK(SHELLMATTA_CONTINUE == ret);

    ret = shellmatta_processData(handle, (char*)"", 0);
    CHECK(SHELLMATTA_CONTINUE == ret);

    ret = shellmatta_processData(handle, (char*)"abc", 3);
    CHECK(SHELLMATTA_OK == ret);

    /** -# continue session should be over */
    ret = shellmatta_processData(handle, (char*)"\r", 1);
    CHECK(SHELLMATTA_OK == ret);

    CHECK( 10u  == contCallCnt);
    CHECK( 2u  == busyCallCnt);
    CHECK( write_length == strlen(dummyData));
    REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData));
}