#include "mainwindow.h"

char MainWindow::loadPlugIn(char lade1_entlade2)
{
    plugInDir.cd("plugins");
    QPluginLoader *pluginLoader = new QPluginLoader();

// select system:
    //pluginLoader->setFileName("../MasterPlug/libCAmaster.so");   // for suse
    //pluginLoader->setFileName("../SlavePlug/libCAslave.so");  // for ptu5
    //pluginLoader->setFileName("../../MasterPlug/CAmaster.dll"); // for windows
    //pluginLoader->setFileName("CAmaster.dll"); // for windows
    pluginLoader->setFileName("/usr/lib/libCAmaster.so"); // for ptu5

    if (lade1_entlade2==2)
    {
        pluginLoader->unload();
        return 0;
    }

    if (!pluginLoader->load())
    {
        qDebug()<<"cannot load plugin";
    } else
        qDebug() <<"loaded plugin: " << pluginLoader->fileName();

    if (!pluginLoader->isLoaded())
    {
        qDebug()<<pluginLoader->errorString();
        return 0;
    }

    QObject *plugin = pluginLoader->instance();
    if ( plugin == nullptr)
    {
        // make instance of the root component (which can hold more then one clases)
        // also loads the lib if not yet done
        qDebug()<<"cannot start instance";
        return 0;
    }

    //int rr=hwapi->giveVal(2);                 funktioniert :))
    //qDebug()<<"got value from plugin"<<rr;    funktioniert :))
    // aber besser globaler pointer:
    // im h-file
    // hwinf *hwapi=nullptr;     // pointer to plugin-class

    HWaccess= qobject_cast<hwinf *>(plugin);
    // make instance to class "hwinf" in dll_HWapi.h over "interfaces.h"

    qDebug()<<"loadPlugIn, HWAccess: " << HWaccess;
    return 0;

}




#define         WINCTRMIN      0
    // 0 is always the home screen

#define         WINCTRMAX      30
    // number of needed application screens, up to 255
    // All screens must be defined below in mainwindow-class first before increasing the nr
    // numbers must be consecutively from 0 always, 0 is the home screen always

#define        FORMWIDTH        725
//#define        FORMWIDTH        690
    // this width is the same for ALL windows

#define        FORMHEIGHT       440
// this height is the same for ALL windows

#define         NAVIBUTTONHEIGHT        70
#define         NAVIBUTTONWIDHT        50

#define         HOMEPAGE_BACKGROUND_COLOR   "background-color: lightgrey"

#define         BUTTON_COLOR                "background-color: rgb(160,250,190)"

#define         ACTIVE_NAVI_COLOR                "background-color: rgb(160,250,190)"
#define         DISABL_NAVI_COLOR                "background-color: grey"

#define         APPPAGE_BACKGROUND_COLOR   "background-color: lightgrey"

#define         UPDATE_PERIOD_MS        100
    // period to call chain steps

#define         VENDINGTIMEOUT_MS       30000
    // after this time without any operation the program returns to idle state
    // time in ms, that means 30.000 gives 30seconds

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    loadPlugIn(1);

    // define all working moduls (besides gui) here, call ini and working in chainControl() (~Line 1000)
    //mifCard = new T_Mifare(HWaccess);   // ganz wichtig: HWaccess an sub-Konstruktor übergeben
                                        // sonst crash bei HW-Zugriff!!!!
    //diary = new T_lib_diary(); absturz!!!!!!
    //conf = new T_lib_config(HWaccess);

    timerChainCtrl = new QTimer(this);
    connect(timerChainCtrl, SIGNAL(timeout()), this, SLOT(chainControl()));
    timerChainCtrl->setSingleShot(0);
    timerChainCtrl->start(UPDATE_PERIOD_MS);     // 1000: call every 1000ms

    timerVendingTimeout = new QTimer(this);
    connect(timerVendingTimeout, SIGNAL(timeout()), this, SLOT(vendingTimeout()));
    timerVendingTimeout->setSingleShot(true);
    timerVendingTimeout->start(VENDINGTIMEOUT_MS);     // in ms

    // ##########################################################################################
    // für jedes anzuzeigende Fenster eine eigene Groupbox mit eigenem Grid anlegen:

    frame01 = new QGroupBox;
    frame01->setStyleSheet(APPPAGE_BACKGROUND_COLOR);
    frame01->setMinimumSize(FORMWIDTH,FORMHEIGHT);
    QVBoxLayout *smallLay01 = new QVBoxLayout;
    frame01->setLayout(smallLay01);
    // Fensterinhalt aus externer Klasse einfügen:
    myFenster01 = new T_winComPort(HWaccess);        // HWaccess damit auf das HW-Plugin zugegriffen werden kann, sonst crash
    smallLay01->addWidget(myFenster01);

    // ##########################################################################################
    // draw Mainwindow:
    bigGroupbox = new QGroupBox;
    bigGroupbox->setStyleSheet("background-color: grey");
    bigGroupbox->setMinimumSize(800,480);
//    bigLayout = new QVBoxLayout;      // navi buttons on bottom side
    bigLayout = new QHBoxLayout;        // navi buttons right hand

    // ##########################################################################################
    // add all windows (but display only one)
    // display only one: then all windows are shown at the same place
    // display more then one: the windows are listed in vertical order

    bigLayout->addWidget(frame01);

    bigGroupbox->setLayout(bigLayout);
    switchScreen(1);
    //HideAllWindows();

    // ##########################################################################################
    // Steuer Leiste

    //QHBoxLayout *ButtonLayout = new QHBoxLayout();
    QVBoxLayout *ButtonLayout = new QVBoxLayout();
    QFont myTabFont;
    myTabFont.setPixelSize(26);

    pBback = new QPushButton("<");        //b\na\nc\nk");
    pBback->setFont(myTabFont);
    pBback->setStyleSheet(ACTIVE_NAVI_COLOR);    
    pBback->setMinimumHeight(NAVIBUTTONHEIGHT);
    pBback->setMaximumWidth(NAVIBUTTONWIDHT);
    connect(pBback, SIGNAL( clicked() ), myFenster01, SLOT( Nav_back()));

    myTabFont.setPixelSize(22);
    pBhome = new QPushButton("<<");      //h\no\nm\ne");
    pBhome->setFont(myTabFont);
    pBhome->setStyleSheet(ACTIVE_NAVI_COLOR);
    pBhome->setMinimumHeight(NAVIBUTTONHEIGHT);
    pBhome->setMaximumWidth(NAVIBUTTONWIDHT);
    connect(pBhome, SIGNAL( clicked() ), myFenster01, SLOT( Nav_home()));

    myTabFont.setPixelSize(26);
    pBforward = new QPushButton(">"); //n\ne\nx\nt");
    pBforward->setFont(myTabFont);
    pBforward->setStyleSheet(ACTIVE_NAVI_COLOR);
    pBforward->setMinimumHeight(NAVIBUTTONHEIGHT);
    pBforward->setMaximumWidth(NAVIBUTTONWIDHT);
    connect(pBforward, SIGNAL( clicked() ), myFenster01, SLOT( Nav_next()));

    QLabel *buttonSpace = new QLabel(" ");
    ButtonLayout->addWidget(pBback);
    ButtonLayout->addWidget(buttonSpace);
    //ButtonLayout->addWidget(buttonSpace);
    ButtonLayout->addWidget(pBhome);
    ButtonLayout->addWidget(buttonSpace);
    //ButtonLayout->addWidget(buttonSpace);
    ButtonLayout->addWidget(pBforward);
    QLabel *bottomSpace = new QLabel(" ");
    ButtonLayout->addWidget(bottomSpace);

    bigLayout->addLayout(ButtonLayout);

    setCentralWidget(bigGroupbox);

    // AUTOSTART serial transmission
    //HWaccess->dc_openSerial(5,"115200","ttyS0",1);    // my suse computer
    //HWaccess->dc_openSerial(1,"9600","COM5",1);    // my suse computer
    //HWaccess->dc_openSerial(5,"115200","ttymxc2",1);      // ptu5
    //HWaccess->dc_autoRequest(true);
    //myFenster01->setButtons4autoStart();
    //HWaccess->alarm_switchSiren(0);  // test

    enableNaviButtons(BACKBUTTON,true);
    enableNaviButtons(HOMEBUTTON,true);
    enableNaviButtons(FORWBUTTON,true); 
    this->chainIni();

    //connect(myFenster02, SIGNAL(quitMyApp()), this, SLOT(close()));

}

MainWindow::~MainWindow()
{
    loadPlugIn(2);
}


void MainWindow::HideAllWindows()
{
    // vorsicht: Fenster muss oben definiert sein sonst Programmabsturz ohne Kommentar

    frame01->setEnabled(false);
    frame01->setVisible(false);
}


// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//  Call Windows
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void MainWindow::switchScreen(uint16_t winNr)    // 0...30
{

    HideAllWindows();
    //qDebug()<<"switch screen to " << winNr;

    switch (winNr)
    {
    case 1:
        frame01->setEnabled(true);
        frame01->setVisible(true);
        break;
    default:
        break;

    }

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Navigation buttons
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void MainWindow::enableNaviButtons(uint8_t switchBitwise)
{
    // switchBitwise=0: no change
    // bit0,1: enable/disable button "next"
    // bit2,3: enable/disable button "home"
    // bit4,5: enable/disable button "back"

    if (switchBitwise &1)
    {
        pBforward->setStyleSheet(ACTIVE_NAVI_COLOR);
        //pBforward->setText("next");
        pBforward->setEnabled(true);
    } else
    if (switchBitwise &2)
    {
        pBforward->setStyleSheet(DISABL_NAVI_COLOR);
        //pBforward->setText("    ");
        pBforward->setEnabled(false);
    }

    if (switchBitwise &4)
    {
        pBhome->setStyleSheet(ACTIVE_NAVI_COLOR);
        //pBhome->setText("home");
        pBhome->setEnabled(true);
    } else
    if (switchBitwise &8)
    {
        pBhome->setStyleSheet(DISABL_NAVI_COLOR);
        //pBhome->setText("    ");
        pBhome->setEnabled(false);
    }

    if (switchBitwise &16)
    {
        pBback->setStyleSheet(ACTIVE_NAVI_COLOR);
        //pBback->setText("back");
        pBback->setEnabled(true);
    } else
    if (switchBitwise &32)
    {
        pBback->setStyleSheet(DISABL_NAVI_COLOR);
        //pBback->setText("    ");
        pBback->setEnabled(false);
    }



}

void MainWindow::enableNaviButtons(uint8_t buttonNr, bool enabled)
{
    if (buttonNr==1)
    {
        if (enabled)
        {
            pBback->setStyleSheet(ACTIVE_NAVI_COLOR);
            //pBback->setText("back");
            pBback->setEnabled(true);
        } else
        {
            pBback->setStyleSheet(DISABL_NAVI_COLOR);
            //pBback->setText("    ");
            pBback->setEnabled(false);
        }
    } else
    if (buttonNr==2)
    {
        if (enabled)
        {
            pBhome->setStyleSheet(ACTIVE_NAVI_COLOR);
            //pBhome->setText("home");
            pBhome->setEnabled(true);
        } else
        {
            pBhome->setStyleSheet(DISABL_NAVI_COLOR);
            //pBhome->setText("    ");
            pBhome->setEnabled(false);
        }
    } else
    if (buttonNr==3)
    {
        if (enabled)
        {
            pBforward->setStyleSheet(ACTIVE_NAVI_COLOR);
            //pBforward->setText("next");
            pBforward->setEnabled(true);
        } else
        {
            pBforward->setStyleSheet(DISABL_NAVI_COLOR);
            //pBforward->setText("    ");
            pBforward->setEnabled(false);
        }
    }

}



// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// control work flow by Finite state machine
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

static uint16_t chainCurrentStep, chainNextStep;
static bool chain_stepIni;

void MainWindow::chainIni(void)
{
    // called once after power-up by constructor
    chainCurrentStep=WCS_STARTSCREEN;     // start screen
    chainNextStep=chainCurrentStep;
    switchScreen(chainCurrentStep);
    chain_stepIni=true;
//qDebug()<<"chain ini, call step "<<WCS_STARTUP << " " << chainCurrentStep;
}

void MainWindow::chainControl(void)
{

    uint16_t nextScreen=0;
    uint8_t  useNavi=0;
    bool busy=false;
    // working step chain:
    if (chainCurrentStep != chainNextStep)
    {
        if (chainNextStep!=WCS_STARTSCREEN)
        {
            timerVendingTimeout->stop();
            timerVendingTimeout->start(VENDINGTIMEOUT_MS);
        }
        //qDebug()<<"found new sreen";
        chainCurrentStep=chainNextStep;
        switchScreen(chainCurrentStep);
        chain_stepIni=true;

    }

    if (chainCurrentStep==1)
    {
        if (chain_stepIni)
            busy=myFenster01->work_ini(&nextScreen, &useNavi);
        else
            busy=myFenster01->working(&nextScreen, &useNavi);
    } else

    {
        // error undefined step
        qDebug()<<"error main chain control, wrong step ("<<chainCurrentStep<<") selected";
        
    }

    if (chain_stepIni)
    {
        chain_stepIni=false;
        switchScreen(chainCurrentStep);       // the mainWindow frame has always the same number as the working step
    }

    if (nextScreen>0)
    {
        // call next chain step
        //qDebug()<<"chain control: new step selected: "<< nextScreen;

        chainNextStep=nextScreen;
    }
    if (useNavi>0)
    {
        //qDebug()<<"chain control: navi buttons "<< useNavi;
        enableNaviButtons(useNavi);
    }

    if (busy>0)
    {
        // reset time-out
        timerVendingTimeout->start();
    }

}



void MainWindow::vendingTimeout(void)
{
    // there was no user operation for 30s so return to start screen
//    uint16_t nextScreen=WCS_STARTSCREEN;
//    chainNextStep=nextScreen;             erstmal stilllegen, stört bei IBN
    //qDebug()<<"chain control: vending TO";
    timerVendingTimeout->stop();
}