#include "StreamParser_C.h"

#include <vector>

#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
    #include <Windows.h>
#else
    #include <unistd.h>
#endif

bool checkErrorCode(slsp_stream_parser_error_code Code, const char* ErrorMessage)
{
    if (Code != slsp_stream_parser_error_code::slsp_error_code_OK)
    {
        printf(ErrorMessage);
        printf("\n");

        if (Code == slsp_stream_parser_error_code::slsp_error_code_ESTABLISH_CONNECTION_FAILED)
        {
            printf("Establish connection failed.");
        }
        else if (Code == slsp_stream_parser_error_code::slsp_error_code_RECEIVE_PACKAGE_FAILED)
        {
            printf("Receive package failed.");
        }
        else if (Code == slsp_stream_parser_error_code::slsp_error_code_RTC_VERSION_ERROR)
        {
            printf("Rtc6 Version missmatch.");
        }
        else if (Code == slsp_stream_parser_error_code::slsp_error_code_UNKNOWN_ERROR)
        {
            printf("Unknown error occurred.");
        }

        printf("\n");
        return true;
    }
    return false;
}

void my_callback(slsp_rtc_data_stream* Stream, void* Context)
{
    std::vector<slsp_rtc_data_package*>* OutputBuffer = (std::vector<slsp_rtc_data_package*>*)(Context);

    slsp_stream_parser_error_code Error;
    auto Size = slsp_rtc_data_stream_get_size(Stream, &Error);
    if (checkErrorCode(Error, "Error in slsp_rtc_data_stream_get_size"))
    {
        return;
    }

    for (size_t I = 0; I < Size; ++I)
    {
        slsp_rtc_data_package* Package = slsp_rtc_data_stream_pop(Stream, &Error);
        if (checkErrorCode(Error, "Error in slsp_rtc_data_stream_pop"))
        {
            return;
        }
        OutputBuffer->push_back(Package);
    }
}

int main()
{
    // Init stream client == start streaming
    std::vector<slsp_rtc_data_package*> OutputBuffer;
    slsp_stream_parser_error_code Error;
    printf("Init stream client...\n");
    slsp_stream_parser* Client = slsp_stream_parser_create("127.0.0.1", (slsp_stream_callback)my_callback,
                                                           &OutputBuffer, &Error);
    if (checkErrorCode(Error, "Error in stream_parser_create"))
    {
        return 1;
    }

    printf("Connect to client. Start streaming ...\n");
    slsp_stream_parser_connect(Client, &Error);
    if (checkErrorCode(Error, "Error in stream_parser_connect"))
    {
        return 1;
    }

    // Check for connection being established
    while (!slsp_stream_parser_is_connected(Client, &Error))
    {
        if (checkErrorCode(Error, "Error in stream_parser_is_connected"))
        {
            return 1;
        }
        slsp_stream_parser_get_async_error(Client, &Error);
        if (checkErrorCode(Error, "Asynchronous error happened"))
        {
            return 1;
        }
        const uint32_t PeriodMilliSeconds = 10;
        Sleep(PeriodMilliSeconds);
    }

    // Stream as long as data is received
    const uint32_t DurationMilliSecond = 1;
    while (slsp_stream_parser_get_state(Client, &Error) == slsp_stream_parser_state::slsp_STREAM_RECEIVING)
    {
        if (checkErrorCode(Error, "Error in slsp_stream_parser_get_state"))
        {
            return 1;
        }
        Sleep(DurationMilliSecond);
    }

    printf("Disconnect from client.\n");
    slsp_stream_parser_disconnect(Client, &Error);
    if (checkErrorCode(Error, "Error in stream_parser_disconnect"))
    {
        return 1;
    }

    // check for any asynchronous error
    slsp_stream_parser_get_async_error(Client, &Error);
    if (checkErrorCode(Error, "Asynchronous error happened"))
    {
        return 1;
    }

    // Delete stream client == stop streaming
    printf("Delete client, stop streaming.\n");
    slsp_stream_parser_delete(Client, &Error);
    if (checkErrorCode(Error, "Error in stream_parser_delete"))
    {
        return 1;
    }

    // Process stream data, write Log
    printf("Process collected stream data ...\n");
    FILE* Log = fopen("SimulationLog_C.txt", "w");
    fprintf(Log, "Channel 1; Channel 2; Channel 3; Channel 4\n");

    for (size_t I = 0; I < OutputBuffer.size(); ++I)
    {
        slsp_rtc_data_package* Package = OutputBuffer[I];
        size_t PackageSize = slsp_rtc_data_package_get_size(Package, &Error);
        if (checkErrorCode(Error, "Error in data_stream_get_size"))
        {
            return 1;
        }

        uint32_t NumChannels = slsp_rtc_data_package_get_channel_count(Package, &Error);
        if (checkErrorCode(Error, "Error in data_point_get_channel_count"))
        {
            return 1;
        }

        std::vector<std::vector<int32_t>> DataMatrix;
        for (uint32_t C = 0; C < NumChannels; ++C)
        {
            std::vector<int32_t> Data(PackageSize);

            size_t DataSize = slsp_rtc_data_package_get_waveform(Package, Data.data(), Data.size(), C, &Error);
            if (checkErrorCode(Error, "Error in data_stream_get_data_point"))
            {
                return 1;
            }
            DataMatrix.push_back(Data);
        }

        for (uint32_t E = 0; E < DataMatrix[0].size(); ++E)
        {
            for (uint32_t C = 0; C < NumChannels; ++C)
            {
                char ValBuf[50];
                sprintf(ValBuf, "%d", DataMatrix[C][E]);
                fprintf(Log, ValBuf);
                fprintf(Log, ";");
            }
            fprintf(Log, "\n");
        }

        fprintf(Log, "\n");
        slsp_rtc_data_package_delete(Package, &Error);
        if (checkErrorCode(Error, "Error in slsp_rtc_data_package_delete"))
        {
            return 1;
        }
    }
    printf("Processing finished.\n");
    return 0;
}
