/*
 * scbus utils to switch card settings.
 *
 * Copyright (C) 2011 Otvos Attila oattila@onebithq.com
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


#include <stdio.h>

#include "configdialog.h"

#include <QDebug>

ConfigTab::ConfigTab(const int deviceid, const int output, RS485Config config, QList<int>* devices, QWidget *parent) : QWidget(parent) {
    char sdeviceid[16];
    char tmp[16];

    this->deviceid=deviceid;
    this->output=output;
    this->currConfig=config;
    this->newConfig=config;

    snprintf(sdeviceid,sizeof(sdeviceid),"%02X",deviceid);
    QLabel *deviceLabel = new QLabel(tr("Device:"));
    if(deviceid)
        deviceValueLabel = new QLabel(QString(sdeviceid));
    else
        deviceValueLabel = new QLabel(QString("Not selected"));
    deviceValueLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);

    QLabel *outputLabel = new QLabel(tr("Output:"));
    QLabel *outputValueLabel = new QLabel("a");
    outputValueLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);

    ls = new LedStatus();
    ls->setBrush(QBrush(QColor(255,0,0)));
    ls->setStatus(1<<(output-1));

    QLabel *iDeviceLabel = new QLabel(tr("Device:"));
    iDevice = new QComboBox();
    this->devices=devices;
    foreach(int n, *devices) {
        snprintf(tmp,sizeof(tmp),"%02X",n);
        iDevice->addItem(QString(tmp));
    }
    QLabel *iInputLabel = new QLabel(tr("Input:"));
    iInput = new QComboBox();

    QLabel *iTypeLabel = new QLabel(tr("Type:"));
    iType = new QComboBox();

    QLabel *iParLabel = new QLabel(tr("Parameter:"));
    iPar = new QComboBox();

    QLabel *dummyLabel = new QLabel("");
    dummyLabel->setAlignment(Qt::AlignBottom);
    dummyLabel->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    QHBoxLayout *buttonLayout = new QHBoxLayout();
    acceptButton = new QPushButton("Accept");
    resetButton = new QPushButton("Reset");
    buttonLayout->addWidget(resetButton);
    buttonLayout->addWidget(acceptButton);
    QWidget * buttonWidget = new QWidget();
    buttonWidget->setLayout(buttonLayout);

    QGridLayout *mainLayout = new QGridLayout;
    int row=0;
    mainLayout->addWidget(deviceLabel,row,0);
    mainLayout->addWidget(deviceValueLabel,row++,1);
    mainLayout->addWidget(outputLabel,row,0);
//    mainLayout->addWidget(outputValueLabel,row++,1);
    mainLayout->addWidget(ls,row++,1);

    mainLayout->addWidget(iTypeLabel,row,0);
    mainLayout->addWidget(iType,row++,1);

    mainLayout->addWidget(iDeviceLabel,row,0);
    mainLayout->addWidget(iDevice,row++,1);
    mainLayout->addWidget(iInputLabel,row,0);
    mainLayout->addWidget(iInput,row++,1);
    mainLayout->addWidget(iParLabel,row,0);
    mainLayout->addWidget(iPar,row++,1);
    mainLayout->addWidget(dummyLabel,row++,0,1,2);
    mainLayout->addWidget(buttonWidget,row++,0,1,2);


//    mainLayout->addStretch(1);

    setLayout(mainLayout);

    updateDevices();

    timmer=0;
    alterinput=0;
    if(newConfig.type==0x02)
        alterinput=newConfig.par;
    if(newConfig.type==0x05 || newConfig.type==0x06 || newConfig.type==0x07 || newConfig.type==0x08 || newConfig.type==0x09 || newConfig.type==0x0a)
        timmer=newConfig.par;
    updatePar(config.type,true);

    connect(iDevice,SIGNAL(currentIndexChanged(int)),this,SLOT(deviceChanged(int)));
    connect(iInput,SIGNAL(currentIndexChanged(int)),this,SLOT(inputChanged(int)));
    connect(iType,SIGNAL(currentIndexChanged(int)),this,SLOT(typeChanged(int)));
    connect(iPar,SIGNAL(currentIndexChanged(int)),this,SLOT(parChanged(int)));
    connect(resetButton,SIGNAL(pressed()),this,SLOT(pressReset()));
    connect(acceptButton,SIGNAL(pressed()),this,SLOT(pressAccept()));

    setConfig(config);
    setBox(iType,config.type);
    setBox(iDevice,config.device);
    setBox(iInput,config.input);
    setBox(iPar,config.par);
}

int ConfigTab::getDevice(void) {
    return deviceid;
}

void ConfigTab::pressReset(void) {
    updatePar(currConfig.type,true);
    newConfig=currConfig;
    updateDevices();
    setBox(iType,newConfig.type);
    setBox(iDevice,newConfig.device);
    setBox(iInput,newConfig.input);
    setBox(iPar,newConfig.par);
    mdf(true);
}

void ConfigTab::pressAccept(void) {
    emit accept(deviceid, output-1, newConfig);
}

void ConfigTab::setBox(QComboBox* box, int value) {
    int n;

    for(n=0;n<box->count();n++) {
        if(box->itemData(n).toInt()==value) {
            box->setCurrentIndex(n);
            return;
        }
    }
}

void ConfigTab::setConfig(RS485Config config) {
    currConfig=config;
    if(cmpconfig(newConfig,currConfig)) {
        mdf(true);
        if(config.type==0x02) {
            alterinput=newConfig.par;
        }
        if(config.type==0x05 || config.type==0x06 || config.type==0x07 || config.type==0x08 || config.type==0x09 || config.type==0x0a) {
            timmer=newConfig.par;
        }
        updatePar(config.type,true);
        setBox(iType,config.type);
        setBox(iDevice,config.device);
        setBox(iInput,config.input);
        setBox(iPar,config.par);
        newConfig=config;
    }
}


void ConfigTab::updateDevices(void) {
    char sdeviceid[16];
    char tmp[16];
    int i;

    disconnect(iDevice,SIGNAL(currentIndexChanged(int)),this,0);
    disconnect(iInput,SIGNAL(currentIndexChanged(int)),this,0);
    disconnect(iType,SIGNAL(currentIndexChanged(int)),this,0);
    disconnect(iPar,SIGNAL(currentIndexChanged(int)),this,0);
    snprintf(sdeviceid,sizeof(sdeviceid),"%02X",deviceid);
    if(deviceid)
        deviceValueLabel->setText(QString(sdeviceid));
    else
        deviceValueLabel->setText(QString("Not selected"));
    if(newConfig.act) {
        iType->clear();
        iType->addItem("Disabled",0xff);                         // 0xff
        iType->addItem("Follow input",0x00);                     // 0x00
        iType->addItem("Follow output",0x01);                    // 0x01
        iType->addItem("Alternative",0x02);                      // 0x02
        iType->addItem("FlipFlop rising edge",0x03);             // 0x03
        iType->addItem("FlipFlop falling edge",0x04);            // 0x04
        iType->addItem("Timer&Continue rising edge",0x05);       // 0x05
        iType->addItem("Timer&Continue falling edge",0x06);      // 0x06
        iType->addItem("Timer&Reset rising edge",0x07);          // 0x07
        iType->addItem("Timer&Reset falling edge",0x08);         // 0x08
        iType->addItem("Timer rising edge",0x09);                // 0x09
        iType->addItem("Timer falling edge",0x0a);               // 0x0a
        iType->setEnabled(true);
        for(i=0;i<iType->count();i++) {
            if(iType->itemData(i).toInt()==newConfig.type) {
                iType->setCurrentIndex(i);
                break;
            }
        }
    } else {
        iType->clear();
        iType->setEnabled(false);
    }
    if(newConfig.act) {
        iDevice->clear();
        iDevice->addItem("",0xff);
        foreach(int n, *devices) {
            snprintf(tmp,sizeof(tmp),"%02X",n);
            iDevice->addItem(QString(tmp),n);
        }
        iDevice->setEnabled(true);
        for(i=0;i<iDevice->count();i++) {
            if(iDevice->itemData(i).toInt()==newConfig.device) {
                iDevice->setCurrentIndex(i);
                break;
            }
        }

        iInput->clear();
        iInput->addItem("",0xff);
        iInput->addItem("01",0);
        iInput->addItem("02",1);
        iInput->addItem("03",2);
        iInput->addItem("04",3);
        iInput->addItem("05",4);
        iInput->addItem("06",5);
        iInput->setEnabled(true);
        for(i=0;i<iInput->count();i++) {
            if(iInput->itemData(i).toInt()==newConfig.input) {
                iInput->setCurrentIndex(i);
                break;
            }
        }
        iPar->setEnabled(true);
        updatePar(newConfig.type,true);
    } else {
        iDevice->clear();
        iDevice->setEnabled(false);
        iInput->clear();
        iInput->setEnabled(false);
        iPar->setEnabled(false);
    }
    acceptButton->setEnabled(!cmpconfig(newConfig,currConfig) && newConfig.device!=0xff && newConfig.input!=0xff);
    resetButton->setEnabled(!cmpconfig(newConfig,currConfig));
    connect(iDevice,SIGNAL(currentIndexChanged(int)),this,SLOT(deviceChanged(int)));
    connect(iInput,SIGNAL(currentIndexChanged(int)),this,SLOT(inputChanged(int)));
    connect(iType,SIGNAL(currentIndexChanged(int)),this,SLOT(typeChanged(int)));
    connect(iPar,SIGNAL(currentIndexChanged(int)),this,SLOT(parChanged(int)));
}

void ConfigTab::setDevice(int deviceid, RS485Config config) {

    if(cmpconfig(newConfig,currConfig) || this->deviceid!=deviceid) {
        if(newConfig.type==0x02)
            alterinput=newConfig.par;
        if(newConfig.type==0x05 || newConfig.type==0x06 || newConfig.type==0x07 || newConfig.type==0x08 || newConfig.type==0x09 || newConfig.type==0x0a)
            timmer=newConfig.par;
        updatePar(config.type,true);
        newConfig=config;
        setBox(iType,config.type);
        setBox(iDevice,config.device);
        setBox(iInput,config.input);
        setBox(iPar,config.par);
        currConfig=config;
        mdf(true);
    }
    this->deviceid=deviceid;
    currConfig=config;
    updateDevices();
}

void ConfigTab::mdf(bool m) {
    acceptButton->setEnabled(!m && newConfig.device!=0xff && newConfig.input!=0xff);
    resetButton->setEnabled(!m);
    emit setModify(output,!m);
}

void ConfigTab::typeChanged(int index) {
    int d = iType->itemData(index).toInt();

    if(newConfig.type==0x02)
        alterinput=newConfig.par;
    if(newConfig.type==0x05 || newConfig.type==0x06 || newConfig.type==0x07 || newConfig.type==0x08 || newConfig.type==0x09 || newConfig.type==0x0a)
        timmer=newConfig.par;
    if(d==0xff) {
        newConfig.type=d;
        iDevice->setEnabled(false);
        iInput->setEnabled(false);
        iPar->setEnabled(false);
        setBox(iDevice,0xff);
        setBox(iInput,0xff);
        setBox(iPar,0xff);
        mdf(currConfig.type==d);
        return;
    } else {
        iDevice->setEnabled(true);
        iInput->setEnabled(true);
        iPar->setEnabled(true);
        if(newConfig.type==0xff) {
            updatePar(d,false);
            setBox(iDevice,newConfig.device);
            setBox(iInput,newConfig.input);
            setBox(iPar,newConfig.par);
            mdf(cmpconfig(newConfig,currConfig));
            return;
        }
    }
    updatePar(d,false);
    mdf(currConfig.type==d);
}

void ConfigTab::deviceChanged(int index) {
    int d = iDevice->itemData(index).toInt();

    if(newConfig.type==0xff)
        return;
    newConfig.device=d;
    mdf(currConfig.device==d);
}

void ConfigTab::inputChanged(int index) {
    int d = iInput->itemData(index).toInt();
    if(newConfig.type==0xff)
        return;
    newConfig.input=d;
    mdf(currConfig.input==d);
}

void ConfigTab::parChanged(int index) {
    int d = iPar->itemData(index).toInt();

    if(newConfig.type==0xff)
        return;
    newConfig.par=d;
    if(newConfig.type==0x02)
        alterinput=newConfig.par;
    if(newConfig.type==0x05 || newConfig.type==0x06 || newConfig.type==0x07 || newConfig.type==0x08 || newConfig.type==0x09 || newConfig.type==0x0a)
        timmer=newConfig.par;
    mdf(currConfig.par==d);
}

RS485Config ConfigTab::getEditedConfig(void) {
    return newConfig;
}

void ConfigTab::setEditedConfig(RS485Config config) {
    newConfig=config;
    setBox(iType,config.type);
    setBox(iDevice,config.device);
    setBox(iInput,config.input);
    setBox(iPar,config.par);
}

void ConfigTab::updatePar(int type, bool force) {
    int oldtype=newConfig.type;
    char tmp[32];
    unsigned int t;
    int m,s;

    newConfig.type=type;
    switch(type) {
    case 0x02:
        if(oldtype!=0x02 || force) {
            disconnect(iPar,SIGNAL(currentIndexChanged(int)),this,0);
            iPar->clear();
            iPar->addItem("",0xff);
            iPar->addItem("01",0);
            iPar->addItem("02",1);
            iPar->addItem("03",2);
            iPar->addItem("04",3);
            iPar->addItem("05",4);
            iPar->addItem("06",5);
            setBox(iPar,alterinput);
            newConfig.par=alterinput;
            connect(iPar,SIGNAL(currentIndexChanged(int)),this,SLOT(parChanged(int)));
        } else
            alterinput=newConfig.par;
        break;
    case 0x05:
    case 0x06:
    case 0x07:
    case 0x08:
    case 0x09:
    case 0x0a:
        if(oldtype!=type || force) {
            disconnect(iPar,SIGNAL(currentIndexChanged(int)),this,0);
            iPar->clear();
            iPar->addItem("",0x00);
            for(int i=1;i<0xff;i++) {
                if(i>60)
                    t=60+(i-60)*10;
                else
                    t=i;
                s=t%60;
                m=(t-s)/60;
                snprintf(tmp,sizeof(tmp),"%02d:%02d",m,s);
                iPar->addItem(QString(tmp),i);
            }
            setBox(iPar,timmer);
            newConfig.par=timmer;
            connect(iPar,SIGNAL(currentIndexChanged(int)),this,SLOT(parChanged(int)));
        } else
            timmer=newConfig.par;
        break;
    default:
        iPar->clear();
    }
}

