/***
 * Warthog Robotics
 * University of Sao Paulo (USP) at Sao Carlos
 * http://www.warthog.sc.usp.br/
 *
 * This file is part of WRJoy project.
 *
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 ***/

// Includes class header
#include <WRJoy/JoystickGUI/monitor.hh>

// Includes Qt library
#include <QtCore/QtCore>
#include <QtWidgets/QtWidgets>

// Includes WRJoy
#include <WRJoy/wrjoy.hh>

// Selects WRJoy namespace
using namespace WRJoy;


WRJoy::JoystickGUI::Monitor::Monitor(Joystick* joystick) {
    // Sets the controlled joystick
    _joystick = joystick;

    // Sets this object name
    this->setObjectName(QString::fromUtf8("Advanced settings widget"));

    // Configures widget elements
    configureMainWindow();
    configureToolBar();
    configureCentralWidget();

    // Configures elements connections
    configureConnections();
}


void WRJoy::JoystickGUI::Monitor::configureMainWindow() {
    // Creates the tool bar
    _toolBar = this->addToolBar(QString::fromUtf8("Advanced settings tool bar"));
    _toolBar->setObjectName(QString::fromUtf8("Advanced settings tool bar"));

    // Creates the central widget
    this->setCentralWidget(new QWidget());
    _centralWidget = this->centralWidget();
    _centralWidget->setObjectName(QString::fromUtf8("Advanced settings central widget"));
}


void WRJoy::JoystickGUI::Monitor::configureToolBar() {
    // Configures the tool bar
    _toolBar->setMovable(false);
    _toolBar->setFloatable(false);
    _toolBar->setIconSize(QSize(24,24));
    _toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);

    // Adds actions
    this->configureActions(_toolBar);
}


void WRJoy::JoystickGUI::Monitor::configureActions(QToolBar* toolBar) {
    // Adds the start monitor button
    _startMonitorAction = new QAction(QIcon(QString::fromUtf8(":/start.png")), QString::fromUtf8("Start monitor"), toolBar);
    _startMonitorAction->setObjectName(QString::fromUtf8("Monitor start monitor action"));
    _startMonitorAction->setCheckable(false);
    _startMonitorAction->setEnabled(true);
    toolBar->addAction(_startMonitorAction);

    // Adds the pause monitor button
    _pauseMonitorAction = new QAction(QIcon(QString::fromUtf8(":/pause.png")), QString::fromUtf8("Pause monitor"), toolBar);
    _pauseMonitorAction->setObjectName(QString::fromUtf8("Monitor pause monitor action"));
    _pauseMonitorAction->setCheckable(true);
    _pauseMonitorAction->setEnabled(false);
    toolBar->addAction(_pauseMonitorAction);

    // Adds the stop monitor button
    _stopMonitorAction = new QAction(QIcon(QString::fromUtf8(":/stop.png")), QString::fromUtf8("Stop monitor"), toolBar);
    _stopMonitorAction->setObjectName(QString::fromUtf8("Monitor stop monitor action"));
    _stopMonitorAction->setCheckable(false);
    _stopMonitorAction->setEnabled(false);
    toolBar->addAction(_stopMonitorAction);
}


void WRJoy::JoystickGUI::Monitor::configureCentralWidget() {
    // Configures the central widget
    QGridLayout* centralLayout = new QGridLayout(_centralWidget);
    _centralWidget->setLayout(centralLayout);

    // Creates the boxes
    this->createBoxes();

    // Adds boxes to layout
    centralLayout->addWidget(_basicInfoBox, 0, 0, 1, 2, Qt::AlignCenter);
    centralLayout->addWidget(_axesInfoBox, 1, 0, 1, 1, Qt::AlignCenter);
    centralLayout->addWidget(_buttonsInfoBox, 1, 1, 1, 1, Qt::AlignCenter);
}


void WRJoy::JoystickGUI::Monitor::configureConnections() {
    // Configures connections for the actions
    QObject::connect(_startMonitorAction, &QAction::triggered, this, &WRJoy::JoystickGUI::Monitor::startMonitor);
    QObject::connect(_pauseMonitorAction, &QAction::triggered, this, &WRJoy::JoystickGUI::Monitor::pauseMonitor);
    QObject::connect(_stopMonitorAction, &QAction::triggered, this, &WRJoy::JoystickGUI::Monitor::stopMonitor);
}


void WRJoy::JoystickGUI::Monitor::startMonitor() {
    // Connects the signals
    QObject::connect(_joystick, &WRJoy::Joystick::opened, this, &WRJoy::JoystickGUI::Monitor::joystickOpened);
    QObject::connect(_joystick, &WRJoy::Joystick::closed, this, &WRJoy::JoystickGUI::Monitor::joystickClosed);
    QObject::connect(_joystick, &WRJoy::Joystick::started, this, &WRJoy::JoystickGUI::Monitor::joystickStarted);
    QObject::connect(_joystick, &WRJoy::Joystick::finished, this, &WRJoy::JoystickGUI::Monitor::joystickStoped);
    QObject::connect(_joystick, &WRJoy::Joystick::stateUpdated, this, &WRJoy::JoystickGUI::Monitor::updateStateForms);

    // Updates the boxes
    if (_joystick->isOpened()) {
        this->joystickOpened();

        if (_joystick->isRunning()) {
            this->joystickStarted();
        }

        else {
            this->joystickStoped();
        }
    }

    else {
        this->createForms();
        this->joystickClosed();
    }

    // Shows the basic information box
    _basicInfoBox->setHidden(false);

    // Enables pause and stop monitor actions
    _startMonitorAction->setEnabled(false);
    _pauseMonitorAction->setEnabled(true);
    _stopMonitorAction->setEnabled(true);
}


void WRJoy::JoystickGUI::Monitor::pauseMonitor(bool checked) {
    // Pauses the monitor
    if (checked) {
        // Disconnects the signals
        QObject::disconnect(_joystick, &WRJoy::Joystick::opened, this, &WRJoy::JoystickGUI::Monitor::joystickOpened);
        QObject::disconnect(_joystick, &WRJoy::Joystick::closed, this, &WRJoy::JoystickGUI::Monitor::joystickClosed);
        QObject::disconnect(_joystick, &WRJoy::Joystick::started, this, &WRJoy::JoystickGUI::Monitor::joystickStarted);
        QObject::disconnect(_joystick, &WRJoy::Joystick::finished, this, &WRJoy::JoystickGUI::Monitor::joystickStoped);
        QObject::disconnect(_joystick, &WRJoy::Joystick::stateUpdated, this, &WRJoy::JoystickGUI::Monitor::updateStateForms);
    }

    // Releases the monitor
    else {
        // Connects the signals
        QObject::connect(_joystick, &WRJoy::Joystick::opened, this, &WRJoy::JoystickGUI::Monitor::joystickOpened);
        QObject::connect(_joystick, &WRJoy::Joystick::closed, this, &WRJoy::JoystickGUI::Monitor::joystickClosed);
        QObject::connect(_joystick, &WRJoy::Joystick::started, this, &WRJoy::JoystickGUI::Monitor::joystickStarted);
        QObject::connect(_joystick, &WRJoy::Joystick::finished, this, &WRJoy::JoystickGUI::Monitor::joystickStoped);
        QObject::connect(_joystick, &WRJoy::Joystick::stateUpdated, this, &WRJoy::JoystickGUI::Monitor::updateStateForms);

        // Updates the boxes
        if (_joystick->isOpened()) {
            this->joystickOpened();

            if (_joystick->isRunning()) {
                this->joystickStarted();
            }

            else {
                this->joystickStoped();
            }
        }

        else {
            this->joystickClosed();
        }

        // Shows the basic information box
        _basicInfoBox->setHidden(false);
    }
}


void WRJoy::JoystickGUI::Monitor::stopMonitor() {
    // Shows a confirmation dialog
    QString dialogTitle   = _joystick->name().append(QString::fromUtf8(" - Stop monitor"));
    QString dialogMessage = QString::fromUtf8("Are you sure you want to stop ").append(_joystick->name()).append(QString::fromUtf8("'s monitor?"));

    QMessageBox::StandardButton response;
    response = QMessageBox::warning(this, dialogTitle, dialogMessage,
                                    QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
                                    QMessageBox::No);

    // Stops the monitor
    if (response == QMessageBox::Yes) {
        // Disconnects the signals
        QObject::disconnect(_joystick, &WRJoy::Joystick::opened, this, &WRJoy::JoystickGUI::Monitor::joystickOpened);
        QObject::disconnect(_joystick, &WRJoy::Joystick::closed, this, &WRJoy::JoystickGUI::Monitor::joystickClosed);
        QObject::disconnect(_joystick, &WRJoy::Joystick::started, this, &WRJoy::JoystickGUI::Monitor::joystickStarted);
        QObject::disconnect(_joystick, &WRJoy::Joystick::finished, this, &WRJoy::JoystickGUI::Monitor::joystickStoped);
        QObject::disconnect(_joystick, &WRJoy::Joystick::stateUpdated, this, &WRJoy::JoystickGUI::Monitor::updateStateForms);

        // Clears the boxes
        this->clearAllBoxes();

        // Hides all boxes
        _basicInfoBox->setHidden(true);
        _axesInfoBox->setHidden(true);
        _buttonsInfoBox->setHidden(true);

        // Enables start and disables pause monitor actions
        _startMonitorAction->setEnabled(true);
        _pauseMonitorAction->setChecked(false);
        _pauseMonitorAction->setEnabled(false);
        _stopMonitorAction->setEnabled(false);
    }
}


void WRJoy::JoystickGUI::Monitor::joystickOpened() {
    // Updates the boxes
    this->updateBoxes();

    // Updates basic form
    this->updateBasicInformationForm();

    // Shows state boxes
    _axesInfoBox->setHidden(false);
    _buttonsInfoBox->setHidden(false);
}


void WRJoy::JoystickGUI::Monitor::joystickClosed() {
    // Clears the boxes
    this->clearStateBoxes();

    // Clears basic form
    this->clearBasicInformationForm();

    // Hides state boxes
    _axesInfoBox->setHidden(true);
    _buttonsInfoBox->setHidden(true);
}


void WRJoy::JoystickGUI::Monitor::joystickStarted() {
    // Updates basic form
    this->updateBasicInformationForm();
}


void WRJoy::JoystickGUI::Monitor::joystickStoped() {
    // Updates basic form
    this->updateBasicInformationForm();

    // Clears the forms
    this->clearStateForms();
}


void WRJoy::JoystickGUI::Monitor::createBoxes() {
    // Creates the boxes
    this->createBasicInformationBox();
    this->createAxesInformationBox();
    this->createButtonsInformationBox();
}


void WRJoy::JoystickGUI::Monitor::createBasicInformationBox() {
    // Creates and configures basic information box
    _basicInfoBox = new QGroupBox(QString::fromUtf8("Basic information"));
    _basicInfoBox->setObjectName(QString::fromUtf8("Monitor basic information group box"));
    _basicInfoBox->setHidden(true);

    // Creates the box layout
    QFormLayout* basicInfoLayout = new QFormLayout(_basicInfoBox);
    basicInfoLayout->setFormAlignment(Qt::AlignCenter);
    basicInfoLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    _basicInfoBox->setLayout(basicInfoLayout);
}


void WRJoy::JoystickGUI::Monitor::createAxesInformationBox() {
    // Creates and configures axes information box
    _axesInfoBox = new QGroupBox(QString::fromUtf8("Axes information"));
    _axesInfoBox->setObjectName(QString::fromUtf8("Monitor axes information group box"));
    _axesInfoBox->setHidden(true);

    // Creates the box layout
    QFormLayout* axesInfoLayout = new QFormLayout(_axesInfoBox);
    axesInfoLayout->setFormAlignment(Qt::AlignCenter);
    axesInfoLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    _axesInfoBox->setLayout(axesInfoLayout);
}


void WRJoy::JoystickGUI::Monitor::createButtonsInformationBox() {
    // Creates and configures buttons information box
    _buttonsInfoBox = new QGroupBox(QString::fromUtf8("Buttons information"));
    _buttonsInfoBox->setObjectName(QString::fromUtf8("Monitor buttons information group box"));
    _buttonsInfoBox->setHidden(true);

    // Creates the box layout
    QFormLayout* buttonsInfoLayout = new QFormLayout(_buttonsInfoBox);
    buttonsInfoLayout->setFormAlignment(Qt::AlignCenter);
    buttonsInfoLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    _buttonsInfoBox->setLayout(buttonsInfoLayout);
}


void WRJoy::JoystickGUI::Monitor::updateBoxes() {
    // Clear the boxes
    this->clearAllBoxes();

    // Creates the forms
    this->createForms();
}


void WRJoy::JoystickGUI::Monitor::clearAllBoxes() {
    // Clears all boxes
    this->clearBasicInformationBox();
    this->clearAxesInformationBox();
    this->clearButtonsInformationBox();
}


void WRJoy::JoystickGUI::Monitor::clearStateBoxes() {
    // Clears state boxes
    this->clearAxesInformationBox();
    this->clearButtonsInformationBox();
}


void WRJoy::JoystickGUI::Monitor::clearBasicInformationBox() {
    // Removes and deletes all layout children
    QLayoutItem* child;
    while (_basicInfoBox->layout()->count() > 0) {
        child = _basicInfoBox->layout()->takeAt(0);
        if (child->widget())
            delete(child->widget());
    }
}


void WRJoy::JoystickGUI::Monitor::clearAxesInformationBox() {
    // Removes and deletes all layout children
    QLayoutItem* child;
    while (_axesInfoBox->layout()->count() > 0) {
        child = _axesInfoBox->layout()->takeAt(0);
        if (child->widget()) {
            delete(child->widget());
        }
    }

    // Clears the axes list
    _axesInfoAxes.clear();
}


void WRJoy::JoystickGUI::Monitor::clearButtonsInformationBox() {
    // Removes and deletes all layout children
    QLayoutItem* child;
    while (_buttonsInfoBox->layout()->count() > 0) {
        child = _buttonsInfoBox->layout()->takeAt(0);
        if (child->widget()) {
            delete(child->widget());
        }
    }

    // Clears the buttons list
    _buttonsInfoButtons.clear();
}


void WRJoy::JoystickGUI::Monitor::createForms() {
    // Creates the forms
    this->createBasicInformationForm();
    this->createAxesInformationForm();
    this->createButtonsInformationForm();

    // Clears the forms
    this->clearAllForms();
}


void WRJoy::JoystickGUI::Monitor::createBasicInformationForm() {
    // Creates the basic information form items
    _basicInfoJoystickStatus     = new QLabel();
    _basicInfoJoystickName       = new QLabel();
    _basicInfoJoystickSDLIndex   = new QLabel();
    _basicInfoJoystickNumAxes    = new QLabel();
    _basicInfoJoystickNumButtons = new QLabel();

    // Adds them to the layout
    QFormLayout* basicInfoLayout = (QFormLayout*) _basicInfoBox->layout();
    basicInfoLayout->addRow(QString::fromUtf8("Status:"), _basicInfoJoystickStatus);
    basicInfoLayout->addRow(QString::fromUtf8("Name:"), _basicInfoJoystickName);
    basicInfoLayout->addRow(QString::fromUtf8("SDL index:"), _basicInfoJoystickSDLIndex);
    basicInfoLayout->addRow(QString::fromUtf8("Number of axes:"), _basicInfoJoystickNumAxes);
    basicInfoLayout->addRow(QString::fromUtf8("Number of buttons:"), _basicInfoJoystickNumButtons);
}


void WRJoy::JoystickGUI::Monitor::createAxesInformationForm() {
    // Gets the number of axes
    qint8 numAxes;
    numAxes = _joystick->numberAxes();

    if (numAxes != -1) {
        // Gets the box layout
        QFormLayout* axesInfoLayout = (QFormLayout*) _axesInfoBox->layout();

        // Adds the layout items
        _axesInfoAxes.clear();

        quint8 i;
        for (i = 0; i < numAxes; i++) {
            _axesInfoAxes << new QLabel();
            axesInfoLayout->addRow(QString::fromUtf8("Axis ").append(QString::number(i)).append(":"), _axesInfoAxes.at(i));
        }
    }
}


void WRJoy::JoystickGUI::Monitor::createButtonsInformationForm() {
    // Gets the number of buttons
    qint8 numButtons;
    numButtons = _joystick->numberButtons();

    if (numButtons != -1) {
        // Gets the box layout
        QFormLayout* buttonsInfoLayout = (QFormLayout*) _buttonsInfoBox->layout();

        // Adds the layout itens
        _buttonsInfoButtons.clear();

        quint8 i;
        for (i = 0; i < numButtons; i++) {
            _buttonsInfoButtons << new QLabel();
            buttonsInfoLayout->addRow(QString::fromUtf8("Button ").append(QString::number(i)).append(":"), _buttonsInfoButtons.at(i));
        }
    }
}


void WRJoy::JoystickGUI::Monitor::updateAllForms() {
    // Updates all information forms
    this->updateBasicInformationForm();
    this->updateAxesInformationForm();
    this->updateButtonsInformationForm();
}


void WRJoy::JoystickGUI::Monitor::updateStateForms() {
    // Updates axes and buttons information forms
    this->updateAxesInformationForm();
    this->updateButtonsInformationForm();
}


void WRJoy::JoystickGUI::Monitor::updateBasicInformationForm() {
    // Updates all basic information
    if (_joystick->isOpened()) {
        if (_joystick->isRunning()) {
            _basicInfoJoystickStatus->setText(QString::fromUtf8("Running"));
        }
        else {
            _basicInfoJoystickStatus->setText(QString::fromUtf8("Stoped"));
        }
    }
    else {
        _basicInfoJoystickStatus->setText(QString::fromUtf8("Closed"));
    }

    _basicInfoJoystickName->setText(_joystick->sdlJoystickName());
    _basicInfoJoystickSDLIndex->setText(QString::number(_joystick->sdlJoystickIndex()));
    _basicInfoJoystickNumAxes->setText(QString::number(_joystick->numberAxes()));
    _basicInfoJoystickNumButtons->setText(QString::number(_joystick->numberButtons()));

    _basicInfoBox->update();
}


void WRJoy::JoystickGUI::Monitor::updateAxesInformationForm() {
    // Gets the number of axes
    qint8 numAxes;
    numAxes = _joystick->numberAxes();

    // Sets axes informtaion to the items
    if (numAxes != -1) {
        quint8 i;
        for (i = 0; i < numAxes; i++) {
            _axesInfoAxes.at(i)->setText(QString::number(_joystick->axisState(i), 'f', 3));
        }
    }
}


void WRJoy::JoystickGUI::Monitor::updateButtonsInformationForm() {
    // Gets the number of buttons
    qint8 numButtons;
    numButtons = _joystick->numberButtons();

    // Sets buttons informtaion to the items
    if (numButtons != -1) {
        quint8 i;
        for (i = 0; i < numButtons; i++) {
            _buttonsInfoButtons.at(i)->setText(QString::number(_joystick->buttonState(i), 'f', 0));
        }
    }
}


void WRJoy::JoystickGUI::Monitor::clearAllForms() {
    // Clears all information forms
    this->clearBasicInformationForm();
    this->clearAxesInformationForm();
    this->clearButtonsInformationForm();
}


void WRJoy::JoystickGUI::Monitor::clearStateForms() {
    // Clears axes and buttons information forms
    this->clearAxesInformationForm();
    this->clearButtonsInformationForm();
}


void WRJoy::JoystickGUI::Monitor::clearBasicInformationForm() {
    // Sets the joystick status
    if (_joystick->isOpened()) {
        if (_joystick->isRunning()) {
            _basicInfoJoystickStatus->setText(QString::fromUtf8("Running"));
        }
        else {
            _basicInfoJoystickStatus->setText(QString::fromUtf8("Stoped"));
        }
    }
    else {
        _basicInfoJoystickStatus->setText(QString::fromUtf8("Closed"));
    }

    // Sets null information to the other items
    _basicInfoJoystickName->setText(QString::fromUtf8("--"));
    _basicInfoJoystickSDLIndex->setText(QString::fromUtf8("--"));
    _basicInfoJoystickNumAxes->setText(QString::fromUtf8("--"));
    _basicInfoJoystickNumButtons->setText(QString::fromUtf8("--"));
}


void WRJoy::JoystickGUI::Monitor::clearAxesInformationForm() {
    // Gets the number of axes
    qint8 numAxes;
    numAxes = _joystick->numberAxes();

    // Sets null informtaion to the items
    if (numAxes != -1) {
        quint8 i;
        for (i = 0; i < numAxes; i++) {
            _axesInfoAxes.at(i)->setText(QString::fromUtf8("--"));
        }
    }
}


void WRJoy::JoystickGUI::Monitor::clearButtonsInformationForm() {
    // Gets the number of buttons
    qint8 numButtons;
    numButtons = _joystick->numberButtons();

    // Sets null informtaion to the items
    if (numButtons != -1) {
        quint8 i;
        for (i = 0; i < numButtons; i++) {
            _buttonsInfoButtons.at(i)->setText(QString::fromUtf8("--"));
        }
    }
}
