#include <stdint.h>
#include <algorithm>

#include <QString>
#include <QDebug>
#include "tslib.h"
#include "shared_mem_buffer.h"

// ///////////////////////////////////////////////////////////////////////////////////
//          control serial interface   gui <--> serial
// ///////////////////////////////////////////////////////////////////////////////////
void epi_setSerial(int BaudNr,
                   QString BaudStr,
                   QString ComName,
                   uint8_t connect) {
    memset(&SharedMemBuffer::getData()->rs.comportName[0], 0x00,
           sizeof(SharedMemBuffer::getData()->rs.comportName));
    strncpy(SharedMemBuffer::getData()->rs.comportName,
            ComName.toStdString().c_str(),
            sizeof(SharedMemBuffer::getData()->rs.comportName)-1);

    memset(&SharedMemBuffer::getData()->rs.baudStr[0], 0x00,
           sizeof(SharedMemBuffer::getData()->rs.baudStr));
    strncpy(SharedMemBuffer::getData()->rs.baudStr,
            BaudStr.toStdString().c_str(),
            sizeof(SharedMemBuffer::getData()->rs.baudStr)-1);

    SharedMemBuffer::getData()->rs.baudNr = BaudNr;
    SharedMemBuffer::getData()->rs.connect = connect;
}

void epi_closeSerial(void) {
    SharedMemBuffer::getData()->rs.connect = 0;
}

void gpi_serialChanged(void) {
    // serial confirms that port was closed or opened
    // rs_connect=2;   // Flanke, nur 1x öffnen/schließen
    SharedMemBuffer::getData()->rs.connect = 2;
}

uint8_t gpi_getSerialConn(void) {
    return SharedMemBuffer::getDataConst()->rs.connect;
}

int gpi_getBaudNr(void) {
    return SharedMemBuffer::getDataConst()->rs.baudNr;
}

QString gpi_getComPortName(void) {
    return SharedMemBuffer::getDataConst()->rs.comportName;
}

void gpi_serialIsOpen(bool offen) {
    SharedMemBuffer::getData()->rs.portIsOpen = offen;
}

bool epi_isSerialPortOpen() {
    // true: port is open   false: port is closed
    return SharedMemBuffer::getDataConst()->rs.portIsOpen;
}

// ///////////////////////////////////////////////////////////////////////////////////
//          Control transfer   gui <--> serial
// ///////////////////////////////////////////////////////////////////////////////////

void epi_startEmmision(char start) {
    SharedMemBuffer::getData()->AutoEmissionOn = start;
}

bool gpi_isEmmisionOn(void) {
    return SharedMemBuffer::getDataConst()->AutoEmissionOn;
}

uint16_t gpi_getPeriodicSendTimeVal() {
    SharedMemBuffer::getData()->datif.sendingPer_changed = 0;
    if ((SharedMemBuffer::getDataConst()->datif.sendingPeriod < 3) ||
        (SharedMemBuffer::getDataConst()->datif.sendingPeriod > 10000)) {
        return 130;         // ms, default
    }
    return SharedMemBuffer::getDataConst()->datif.sendingPeriod;
}

void epi_setPeriodicSendTimeVal(uint16_t val) {
    if (val>=3 && val<10000) {
        SharedMemBuffer::getData()->datif.sendingPer_changed = 1;
        SharedMemBuffer::getData()->datif.sendingPeriod = val;
    }
}

bool gpi_PeriodicSendTimeHasChanged() {
    return SharedMemBuffer::getDataConst()->datif.sendingPer_changed;
}

// ///////////////////////////////////////////////////////////////////////////////////
//          Status Display    gui <--> serial
// ///////////////////////////////////////////////////////////////////////////////////

//              linke Spalte, über Connect Button
static QString txt4comStateLine;

QString epi_getTxt4comStateLine(void) {
    // GUI: get Text for serial Comport-State Line
    return txt4comStateLine;
}

void gpi_setTxt4comStateLine(QString txtline) {
    // serial: write Text to be displayed in serial Comport-State line (like "connected")
    txt4comStateLine.clear();
    if (txtline=="")
        txt4comStateLine.clear();
    else
        txt4comStateLine=txtline;
}

void epi_clrTxt4comStateLine() {
    txt4comStateLine.clear();
}

// rechte Spalte, oberste Statuszeile
// I) "Handshakes" (serial Control)   flow.cpp
// geht überhaupt was raus? kommt überhaupt was zurück?
static QString txt4HsStateLine;

QString epi_getTxt4HsStateLine(void) {
    return txt4HsStateLine;
}

void gpi_setTxt4HsStateLine(QString txtline) {
    txt4HsStateLine.clear();
    if (txtline=="")
        txt4HsStateLine.clear();
    else
        txt4HsStateLine=txtline;
}

void epi_clrTxt4HsStateLine() {
    txt4HsStateLine.clear();
}

// II) Master receive state (empfangenes Telgramm OK? crc? length?  )
// Statuszeile Auswertung der SlaveResponse (serial Frame, CRC usw)  (prot.cpp)
static QString txt4masterStateLine;

QString epi_getTxt4masterStateLine(void) {
    return txt4masterStateLine;
}

void gpi_setTxt4masterStateLine(QString txtline) {
    txt4masterStateLine.clear();
    if (txtline=="")
        txt4masterStateLine.clear();
    else
        txt4masterStateLine=txtline;
}

void epi_clrTxt4masterStateLine() {
    txt4masterStateLine.clear();
}

//---------------------------------------------------------------------------------------------

// III   Slave receive (from Master) OK? if then show results, if not then show errors
// entweder Empfangsfehler anzeigen (crc? length?) oder result OUT-OK, OUT_ERR, IN_OK, IN_ERR
// Hintergrund: wenn der Slave Fehler im Master-Telegramm gefunden hat, dann kann er es auch
// nicht verwenden und nichts ausgeben oder einlesen

static QString txt4resultStateLine;

QString epi_getTxt4resultStateLine(void) {
    return txt4resultStateLine;
}

void gpi_setTxt4resultStateLine(QString txtline) {
    txt4resultStateLine.clear();
    if (txtline=="")
        txt4resultStateLine.clear();
    else
        txt4resultStateLine=txtline;
}

void epi_clrTxt4resultStateLine() {
    txt4resultStateLine.clear();
}

//---------------------------------------------------------------------------------------------

// IV  Statuszeile Empfangsdaten
static QString txt4dataLine;

QString epi_getTxt4dataStateLine(void) {
    // GUI: get Text for serial Comport-State Line
    return txt4dataLine;

}

void gpi_setTxt4dataStateLine(QString txtline) {
    // serial: write Text to be displayed in serial Comport-State line (like "connected")
    txt4dataLine.clear();
    if (txtline=="")
        txt4dataLine.clear();
    else
        txt4dataLine=txtline;
}

void epi_clrTxt4dataStateLine() {
    txt4dataLine.clear();
}

//---------------------------------------------------------------------------------------------

// 5. Zeile: Datif Ergebnis, Daten brauchbar?

static QString txt4datifReceive;

QString epi_getTxt4datifLine(void) {
    return txt4datifReceive;
}

void gpi_setTxt4datifLine(QString txtline) {
    txt4datifReceive.clear();
    if (txtline=="")
        txt4datifReceive.clear();
    else
        txt4datifReceive=txtline;
}

void epi_clrTxt4datifLine() {
    txt4datifReceive.clear();
}

//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------

static QString txt4diagWindow;

QString epi_getTxt4RsDiagWin(void) {
    return txt4diagWindow;
}

void gpi_setTxt4RsDiagWin(QString txtline) {
    txt4diagWindow.clear();
    if (txtline=="")
        txt4diagWindow.clear();
    else
        txt4diagWindow=txtline;
}

void epi_clrTxt4RsDiagWin() {
    txt4diagWindow.clear();
}

//---------------------------------------------------------------------------------------------

static QString sndTxt4diagWindow;

QString epi_get2ndTxt4RsDiagWin(void) {
    return sndTxt4diagWindow;
}

void gpi_set2ndTxt4RsDiagWin(QString txtline) {
    sndTxt4diagWindow.clear();
    if (txtline=="")
        sndTxt4diagWindow.clear();
    else
        sndTxt4diagWindow=txtline;
}

void epi_clr2ndTxt4RsDiagWin() {
    sndTxt4diagWindow.clear();
}

// ///////////////////////////////////////////////////////////////////////////////////
//          Memory for Slave responses, common data
// ///////////////////////////////////////////////////////////////////////////////////
void gpi_storeResult_serialTestOK(bool wasOk) {
    SharedMemBuffer::getData()->Sdata.serialTestResult = wasOk;
}

bool epi_getResult_serialTestOK() {
    // retval: true: test was successful, got right response
    return SharedMemBuffer::getDataConst()->Sdata.serialTestResult;
}

// ///////////////////////////////////////////////////////////////////////////////////
//          Store received data for hwapi
// ///////////////////////////////////////////////////////////////////////////////////
void gpi_startNewRequest() {
    SharedMemBuffer::getData()->Sdata.pProtResultOk = 0;
}

void gpi_storeResultOfLastRequest(bool answisok) {
    SharedMemBuffer::getData()->Sdata.pProtResultOk = answisok ? 1 : 2;
}

uint8_t epi_getResultOfLastRequest() {
    // retval: 0: in progress  1: OK  2: error
    return SharedMemBuffer::getDataConst()->Sdata.pProtResultOk;
}

void gpi_storeRecPayLoad(uint8_t RdDlen, uint8_t const *receivedData) {
    SharedMemBuffer::getData()->Sdata.receivedDataLength
        = std::min(RdDlen, (uint8_t)(64));
    memset((char *)(&SharedMemBuffer::getData()->Sdata.receivedDataBlock[0]),
           0x00, sizeof(SharedMemBuffer::getData()->Sdata.receivedDataBlock));
    strncpy((char *)(&SharedMemBuffer::getData()->Sdata.receivedDataBlock[0]),
            (char const *)receivedData,
            sizeof(SharedMemBuffer::getData()->Sdata.receivedDataBlock)-1);
}

uint16_t epi_getLastPayLoad(uint16_t plBufSiz, uint8_t *payLoad) {
    // get data back in *pl, max 64 byte
    // retval = nr of bytes received. If host buffer too small then
    // only plBufSíz bytes are copied to pl
    // plBufSíz=size of host buffer

    uint16_t ml = std::min(plBufSiz, (uint16_t)(64));
    if (SharedMemBuffer::getDataConst()->Sdata.receivedDataLength < ml) {
        ml = SharedMemBuffer::getDataConst()->Sdata.receivedDataLength;
    }
    strncpy((char *)payLoad,
            (char const *)(&SharedMemBuffer::getData()->Sdata.receivedDataBlock[0]),
            ml);

    return SharedMemBuffer::getDataConst()->Sdata.receivedDataLength;
}
