/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/interface/Basda/Qt/Wheel/BasdaMoccaWheelServiceWidget.cc 14057 2016-11-10 14:53:04Z mathar $
*/

#include <Basda/Mocca/Constant.h>
#include <Nice/Map/Point.h>
#include <Nice/Property/BridgeMemFn.hh>
#include <Nice/Qt/WidgetFactory.hh>
#include <Nice/Qt/QtWidgetAttributeName.h>
#include <Nice/Property/BridgeMemFn.hh>
#include <Basda/Qt/Wheel/BasdaMoccaWheelServiceWidgetUnit.h>
#include <Basda/Qt/Wheel/BasdaMoccaWheelServiceWidgetUnitUI.h>
#include <Qt/qglobal.h>
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <Basda/Mocca/PropertyName.h>

//extern "C" void instantType()
//{
//    D_LOG("Load Basda::MoccaWheelServiceWidget");
//}

extern int qInitResources_Basda_Qt_NavigationCrossResource();

//------------------------------------------------------------
BasdaMoccaWheelServiceWidgetUnit::BasdaMoccaWheelServiceWidgetUnit(QWidget * parent,
                                                           bool /*_connect*/)
        : QWidget(parent), Nice::BridgeItem()
{
    qInitResources_Basda_Qt_NavigationCrossResource();
    Nice::BridgeItem::m_autoSynch = true;

    m_wheelView = new Ui::BasdaMoccaWheelServiceWidgetUnitUI;
    m_wheelView->setupUi(this);

    m_unit = "not defined";
    m_namedPos = -1;
    m_namedPositionNotDefined = "named position n.d.";

    init(this);
}

void BasdaMoccaWheelServiceWidgetUnit::initSlots()
{
	m_wheelView->m_basdaServiceState->Nice::BridgeItem::connect(
			m_root->node("STATE"));
    m_wheelView->m_reachableLed->Nice::BridgeItem::connect(
            m_root->leaf("CMD")->attribute(
                    Basda::Mocca::Svc::AttributeName::isReachable()));
	m_wheelView->m_nameItemLabel->Nice::BridgeItem::connect(
			m_root->node(Basda::Mocca::Svc::PropertyName::serviceName()));
// 	m_wheelView->m_deviceNameXItemLabel->Nice::BridgeItem::connect(
//             m_root->leaf("CMD")->attribute(
//                    Basda::Mocca::Svc::AttributeName::deviceName()));
    m_wheelView->m_namedPositionComboBox->Nice::BridgeItem::connect(
			m_root->node("CMD.MOVETONAMEDPOSITION.NAMED_POSITION"));

	m_unit = m_root->leaf(
            Basda::Mocca::Svc::PropertyName::position())
            ->getAttribute<std::string>(
            Basda::Mocca::Svc::AttributeName::unit());

	m_wheelView->m_progressBar->Nice::BridgeItem::connect(m_root->node("CMD"));
	m_wheelView->m_statusLabel->Nice::BridgeItem::connect(m_root->node("CMD"));

    // in order to keep the GUI updated when the property change
	NICE_QT_CONNECT(
    		m_root->leaf("CMD")->attribute(Basda::Mocca::Svc::AttributeName::namedPositionAbs()),
    		this, BasdaMoccaWheelServiceWidgetUnit, slotNice_setNamedPositionAbs,
    		std::vector<Nice::Int>);
	NICE_QT_CONNECT(
    		m_root->leaf("CMD")->attribute(Basda::Mocca::Svc::AttributeName::namedPositionRel()),
    		this, BasdaMoccaWheelServiceWidgetUnit, slotNice_setNamedPositionRel,
    		std::vector<Nice::Int>);

    std::ostringstream out;
    out << ( ( m_root->getWithDefault<bool>("CFG.ONEWAY", true) == true ) ? "ONEWAY" : "TWOWAY" );

    m_wheelView->m_labelOneway
    	->setText( QString::fromStdString( out.str() ) );
}

void BasdaMoccaWheelServiceWidgetUnit::initAttributes()
{
    m_cmd = Basda::MoccaWheelServiceWorkerInterface::create(getNode());

    m_unitPrec = m_root->leaf(
                              Basda::Mocca::Svc::PropertyName::position())->attribute(
                              Nice::QtWidgetAttributeName::unitPrec())->get<std::map<std::string, int> >();
    std::map<std::string, int>::iterator unitNamePrecIt = m_unitPrec.begin();
    m_wheelView->m_unitComboBox->blockSignals(true);
    while (unitNamePrecIt != m_unitPrec.end())
      {
        m_wheelView->m_unitComboBox->addItem(QString::fromStdString(unitNamePrecIt->first));
        unitNamePrecIt++;
      }
    m_wheelView->m_unitComboBox->blockSignals(false);
    std::string unit = m_root->leaf(
                                    Basda::Mocca::Svc::PropertyName::position())
      ->getAttribute<std::string>(
                                  Basda::Mocca::Svc::AttributeName::unit());
    m_wheelView->m_unitComboBox->setCurrentIndex(m_wheelView->m_unitComboBox->findText(QString::fromStdString(unit)));
    slotQt_valueUnitChanged(QString::fromStdString(unit));

    m_wheelView->m_positionItemLabel->Nice::BridgeItem::connect(
            m_root->node("VAR.POSITION"));
    m_wheelView->m_positionRemainderItemLabel->Nice::BridgeItem::connect(
            m_root->node("VAR.POSITION_REMAINDER"));
    m_wheelView->m_currentNamedPositionItemLabel->Nice::BridgeItem::connect(
            m_root->node("VAR.NAMED_POSITION"));
    m_wheelView->m_currentSwitchStatus->Nice::BridgeItem::connect(
            m_root->node("VAR.SWITCH_STATUS"));

    m_wheelView->m_positionItemLabel->setToolTip(
            QString::fromStdString(
                    Basda::Mocca::Svc::PropertyName::position() + " in ["
                            + m_unit + "]"));

    m_wheelView->m_positionRemainderItemLabel->setToolTip(
            QString::fromStdString(
                    Basda::Mocca::Svc::PropertyName::positionRemainder() + " in ["
                            + m_unit + "]"));

    m_wheelView->m_configuredNamedPositionItemLabel->setToolTip(
            QString::fromStdString("The named position as it is configured."));
    m_wheelView->m_configuredReferenceSwitch->setToolTip(
            QString::fromStdString("The named reference switches as it is configured."));

	m_namedPos = m_root->node("CMD.MOVETONAMEDPOSITION.NAMED_POSITION")->get<int>();

    // save the named position in a vector
    // in case the attributes does not exist, the default value will be return
    std::vector<Nice::Int> pos(1, 0);
    Nice::BitSet bs;
    bs.depth = 8;
    bs.value = Nice::U32(pow(2, bs.depth) - 1);
    Nice::SeqBitSet ref = Nice::SeqBitSet(1, bs);
    m_namedPosRel = m_root->leaf("CMD")->getAttributeWithDefault<std::vector<Nice::Int> >(
    				Basda::Mocca::Svc::AttributeName::namedPositionRel(), pos);
    m_namedPosAbs = m_root->leaf("CMD")->getAttributeWithDefault<std::vector<Nice::Int> >(
    				Basda::Mocca::Svc::AttributeName::namedPositionAbs(), pos);
    m_namedRef    = m_root->leaf("CMD")->getAttributeWithDefault< Nice::SeqBitSet >(
                    Basda::Mocca::Svc::AttributeName::namedReference(), ref);

    if (m_namedPosRel.empty()) m_namedPosRel.resize(1);
    if (m_namedPosAbs.empty()) m_namedPosAbs.resize(1);

    m_wheelView->m_namedPositionComboBox->setToolTip(
            "Select pre-defined named position. Selecting here will not initiate the move.");

    m_wheelView->m_moveHomeXToolButton->setToolTip("Home the motor");
    m_wheelView->m_moveAbsoluteXToolButton->setToolTip(
            "Move to location indicated in spinbox above");
    m_wheelView->m_moveRelativeXToolButton->setToolTip(
            "Move in increments as specified in the spinbox above.");

    m_wheelView->m_unitComboBox->setToolTip(
            "Select pre-defined unit transformation matrix.");

    updateDoubleSpinBoxRel();
    updateDoubleSpinBoxAbs();
    updateNamedPositionLabels();
}

void BasdaMoccaWheelServiceWidgetUnit::updateDoubleSpinBoxAbs()
{
    // restore the named position values
    // if no named position is defined set the values with 0
    if (m_namedPos >= 0 && m_namedPos < (int) m_namedPosAbs.size())
        m_wheelView->m_moveAbsoluteXDoubleSpinBox->setValue(
                m_namedPosAbs[m_namedPos]);
    else
    {
        m_namedPosAbs.push_back(
                (Nice::Int)m_wheelView->m_moveAbsoluteXDoubleSpinBox->value());
        m_root->leaf("CMD")->attribute(
                Basda::Mocca::Svc::AttributeName::namedPositionAbs())
                ->set<std::vector<Nice::Int> >(m_namedPosAbs);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::updateDoubleSpinBoxRel()
{
    // restore the named position values
    // if no named position is defined set the values with 0
    if (m_namedPos >= 0 && m_namedPos < (int) m_namedPosRel.size())
        m_wheelView->m_moveRelativeXDoubleSpinBox->setValue(
                m_namedPosRel[m_namedPos]);
    else
    {
        m_namedPosRel.push_back(
                (Nice::Int)m_wheelView->m_moveRelativeXDoubleSpinBox->value());
        m_root->leaf("CMD")->attribute(
                Basda::Mocca::Svc::AttributeName::namedPositionRel())
                ->set<std::vector<Nice::Int> >(m_namedPosRel);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::updateNamedPositionLabels()
{
    if (m_namedPos >= 0 && m_namedPos < (int) m_namedRef.size())
    {
        m_wheelView->m_configuredNamedPositionItemLabel->setText(QString::number(m_namedPosAbs[m_namedPos]));
        std::stringstream ss;
        ss << m_namedRef[m_namedPos];
        m_wheelView->m_configuredReferenceSwitch->setText(QString::fromStdString(ss.str()));
    }
    else
    {
        m_wheelView->m_configuredNamedPositionItemLabel->setText(QString(""));
        m_wheelView->m_configuredReferenceSwitch->setText(QString(""));
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotNice_setNamedPositionAbs(std::vector<
                                                                Nice::Int> _p)
{
    if (m_namedPosAbs != _p)
    {
        m_namedPosAbs = _p;
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotNice_setNamedPositionRel(std::vector<
                                                                Nice::Int> _p)
{
    if (m_namedPosRel != _p)
    {
        m_namedPosRel = _p;
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_signRelXChanged()
{
    double pos = m_wheelView->m_moveRelativeXDoubleSpinBox->value();
    m_wheelView->m_moveRelativeXDoubleSpinBox->setValue(pos * -1.0);
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_signAbsXChanged()
{
    double pos = m_wheelView->m_moveAbsoluteXDoubleSpinBox->value();
    m_wheelView->m_moveAbsoluteXDoubleSpinBox->setValue(pos * -1.0);
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_valueUnitChanged(QString _v)
{
  I_LOG(_v.toStdString());
  if (_v.toStdString() != m_unit)
    {
      m_unit = _v.toStdString();
      m_wheelView->m_moveAbsoluteXDoubleSpinBox->setDecimals(m_unitPrec[m_unit]);
      m_wheelView->m_moveRelativeXDoubleSpinBox->setDecimals(m_unitPrec[m_unit]);
      I_LOG("Unit set to " << m_unit);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_valueNamedPositionChanged(int _index)
{
    if (m_wheelView->m_namedPositionComboBox->count() > 1)
    {
        int index = m_wheelView->m_namedPositionComboBox->findText(
                QString::fromStdString(m_namedPositionNotDefined));
        if (index > -1)
        {
            m_namedPosAbs.erase(m_namedPosAbs.begin() + index);
            m_namedPosRel.erase(m_namedPosRel.begin() + index);
            m_wheelView->m_namedPositionComboBox->removeItem(index);
            if (_index > 0) _index -= 1;
        }
    }
    m_namedPos = _index;
    updateDoubleSpinBoxRel();
    updateDoubleSpinBoxAbs();
    updateNamedPositionLabels();
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_abort()
{
    try
    {
        m_cmd->abort();
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_stop()
{
    try
    {
        m_cmd->stop();
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_moveToNamedPositionX()
{
    try
    {
        m_cmd->moveToNamedPositionStart(
                m_wheelView->m_namedPositionComboBox->currentIndex());
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_moveAbsoluteX()
{
    try
    {
        m_cmd->moveAbsoluteStart(
                (Nice::Int)m_wheelView->m_moveAbsoluteXDoubleSpinBox->value(), m_unit);
        U9_LOG("moving absolute to " << m_wheelView->m_moveAbsoluteXDoubleSpinBox->value()
               << " " << m_unit);
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_moveRelativeX()
{
    try
    {
        m_cmd->moveRelativeStart(
                (Nice::Int)m_wheelView->m_moveRelativeXDoubleSpinBox->value(), m_unit);
        I_LOG("moving relative to " << m_wheelView->m_moveRelativeXDoubleSpinBox->value()
               << " " << m_unit);
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_moveToHomeX()
{
	try
	{
		m_cmd->moveToHomeStart();
    m_cmd->moveToHomeWait();
    m_cmd->moveToHomeStart();
	}

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

	catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

void BasdaMoccaWheelServiceWidgetUnit::slotQt_scanAllReferenceSwitches()
{
    try
    {
        m_cmd->scanAllReferenceSwitchesStart();
        m_wheelView->m_configuredReferenceSwitch->setToolTip(
                QString::fromStdString("The named reference switches as it was scanned."));
    }

    catch (Basda::ServiceWorkerInterfaceIsBusyException &e)
    {
        E_LOG(e)
    }

    catch (Basda::ServiceWorkerInterfaceCommandFailedException &e)
    {
        E_LOG(e)
    }

    catch (const std::exception& ex)
    {
        E_LOG(ex.what());
        assert(false);
    }
}

struct WidgetFactoryTypeMapInitializerBasdaMoccaWheelServiceWidgetUnit
{
        WidgetFactoryTypeMapInitializerBasdaMoccaWheelServiceWidgetUnit()
        {
            NicePlugins::addPlugin(
                    new QTPluginImpl<BasdaMoccaWheelServiceWidgetUnit>(
                            "BasdaMoccaWheelServiceWidgetUnit.h",
                            "BasdaMoccaWheelServiceWidgetUnit"));
            Nice::WidgetFactory::addWidgetFactory<BasdaMoccaWheelServiceWidgetUnit>(
                    "BasdaMoccaWheelServiceWidgetUnit",
                    "BasdaMoccaWheelServiceWidgetUnit");
        }
        ;
} s_WidgetFactoryTypeMapInitializerBasdaMoccaWheelServiceWidgetUnit;
