/***************************************************************************

  BionxControl
  Copyright © 2025 christoph holzheuer
  christoph.holzheuer@gmail.com

  Using:

  mhs_can_drv.c
  © 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
  Klaus Demlehner, klaus@mhs-elektronik.de
  @see www.mhs-elektronik.de

  Based on Bionx data type descriptions from:

  BigXionFlasher USB V 0.2.4 rev. 97
  © 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
  @see www.bigxionflasher.org

  Bionx Bike Info
  © 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
  @see www.ts-soft.de

  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.
  @see https://github.com/bikemike/bionx-bikeinfo

 ***************************************************************************/


#include <QThread>
#include <QDebug>

#include <bctransmitter.h>

BCTransmitter::BCTransmitter(QObject *parent)
  : QObject(parent), _isBusy(false)
{
  //_canDriver = new BCDriverTinyCan{this};
  _canDriver = new BCDriverDummy{this};
  // forward driver state
  connect( _canDriver, &BCDriver::driverStateChanged, this, &BCTransmitter::driverStateChanged );
}


void BCTransmitter::onToggleConnectionState( bool connect )
{
  if( connect )
  {
    if( _canDriver->getDriverState() != BCDriver::DriverState::DeviceReady )
      _canDriver->onStartDriver();

    // __fix!
    TransmitResult hwVersion = _canDriver->readRawByte( (uint32_t)BCDevice::ID::Console, (uint8_t)BC::ID::Cons_Rev_Hw);
    if(!hwVersion)
    {
      qDebug() << "Console not responding";
    }
    else
    {


    }

    qDebug() << " ---HAIL to the kings: " << hwVersion.value();
  }
}


void BCTransmitter::enqueueValue( BCValuePtrConst value)
{
  // Hier sind wir noch in GUI Thread
  QMutexLocker locker(&_mutex);
  _valueQueue.enqueue( value );

  // wir wollen nicht den ganzen Value verschicken, erstrecht
  // wollen wir nicht den Value in verschiedenen Threads gleichzeitig
  // in die Hand nehmen, also hantieren wir nur mit den Inidizes.

  // Trigger processing im Event-Loop des Worker Threads
  // invokeMethod mit QueuedConnection entkoppelt den Aufruf,
  // damit enqueueValue sofort zurückkehrt (non-blocking für den Aufrufer).

  QMetaObject::invokeMethod(this, "processValue", Qt::QueuedConnection);

  /*
  QMetaObject::invokeMethod(this, [this]()
  {
    processValue();
  }, Qt::QueuedConnection );
  */
}

void BCTransmitter::processValue()
{

  if (_isBusy)
    return;

  _isBusy = true;

  while (true)
  {
    BCValuePtrConst valuePtr{};
    {
      QMutexLocker locker(&_mutex);
      if (_valueQueue.isEmpty())
      {
        _isBusy = false;
        break; // Schleife verlassen, warten auf neue Events
      }
      valuePtr =_valueQueue.dequeue();
    } // Mutex wird hier freigegeben! WICHTIG: Execute ohne Lock!

    // Kosmetik
    const BCValue& value = *(valuePtr.get());

    // Value ist 'under construction'
    //emit valueUpdated( value.deviceID, value.indexRow, BCValue::State::Locked );


    uint32_t devID = static_cast<uint32_t>(value.deviceID);
    uint8_t  regID = static_cast<uint8_t> (value.registerID);

    QString newVisibleValue;
    BCValue::State newState = BCValue::State::NoState;

    if(value.state.testFlag( BCValue::State::WriteMe ) )
    {


    }
    // oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
    // Was kommt dann zuerst? Schreiben und lesen als verify ?

    else if( value.state.testFlag( BCValue::State::ReadMe ) )
    {

      /*
      // wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
      TransmitResult result = valueType.readValueFunc( *this, devID, regID );
      if( result.has_value() )
      {
        newVisibleValue = valueType.formatValue( result.value() );
        newState = BCValue::State::InSync;
      }
      else
      {
        newState = BCValue::State::Failed;
      }
*/

    }

    emit valueUpdated( value.deviceID, value.indexRow, newState, newVisibleValue );

    // __fix
    bc::processEventsFor(50);

    //emit valueStateChanged(cmd.id, true);
    //emit valueStateChanged(0, true);
  }
}


/**
 * @brief BCTransmitter::readByte
 * NEIN NEIN NEIN!
 * Reicht den read request an den aktuellen Treiber weiter. Wird von aussen, von der readValueFunc des ValueTypes
 * aufgerufen, deshalb public.
 */

TransmitResult BCTransmitter::readByte( uint32_t deviceID, uint8_t registerID  ) const
{
  return _canDriver->readRawByte( deviceID, registerID );
}


/**
 * @brief BCTransmitter::writeByte
 * Reicht den write request an den aktuellen Treiber weiter. Wird von aussen, von der writeValueFunc des ValueTypes
 * aufgerufen, deshalb public.
 */

TransmitResult BCTransmitter::writeByte( uint32_t deviceID, uint8_t registerID , uint8_t value ) const
{
  return _canDriver->writeRawByte( deviceID, registerID, value );
}




