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

  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)
{
}


void BCTransmitter::onToggleConnectionState( bool connect )
{
  if( connect )
  {
    if( _canDriver.getState() != BCDriver::DriverState::Ready )
      _canDriver.onStartDriver();

    // fix!
    uint32_t hwVersion = _canDriver.readRawByte( (uint32_t)BCDevice::ID::Console, (uint8_t)BC::ID::Cons_Rev_Hw);

    if(!hwVersion)
    {
      qDebug() << "Console not responding";
    }
    else
    {
      /*
      swVersion = getValue(CONSOLE, CONSOLE_REF_SW);
      printf( "Console information:" _NL
             " hardware version ........: %02d" _NL
             " software version ........: %02d" _NL
             " assistance level ........: %d" _NL,
             hwVersion, swVersion,
             getValue(CONSOLE, CONSOLE_ASSIST_INITLEVEL)
             );

      if (!gNoSerialNumbers)
        printf( " part number .............: %05d" _NL
               " item number .............: %05d" _NL _NL,
               ((getValue(CONSOLE, CONSOLE_SN_PN_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_PN_LO)),
               ((getValue(CONSOLE, CONSOLE_SN_ITEM_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_ITEM_LO))
               );
      */

    }

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


void BCTransmitter::enqueueValueOp(BC::OpID opID, const BCValue* value)
{
  QMutexLocker locker(&_mutex);
  _valueQueue.enqueue( value );

  // wir wollen nicht den ganzen Value verschicken, erstrecht
  // wollen wir 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 enqueueValueOp sofort zurückkehrt (non-blocking für den Aufrufer).

  //QMetaObject::invokeMethod(this, "processValueOp", Qt::QueuedConnection);
  QMetaObject::invokeMethod(this, [this, opID]()
  {
    this->processValueOp(opID);
  }, Qt::QueuedConnection );
}

void BCTransmitter::processValueOp( BC::OpID opID )
{

  if (_isBusy)
    return;

  _isBusy = true;

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


    try
    {
      // Abkürzung
      const BCValue& val = *currentValue;
      // Value ist 'under construction'
      //emit valueUpdated( val.deviceID, val.indexRow, BC::State::Locked );
      if( opID == BC::OpID::ReadValue )
      {
        QString result = currentValue->readRawValueX( *this );
        emit valueUpdated( val.deviceID, val.indexRow, BC::State::InSync, result );
      }

      else if( opID == BC::OpID::WriteValue )
      {
        currentValue->writeRawValueX( *this );
      }

    }
    catch (...)
    {
      qDebug() << " --- OUCH!";
    }

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

uint32_t BCTransmitter::readRawByte(  uint32_t deviceID, uint8_t registerID  ) const
{
  uint32_t result{};
  try
  {
    result = _canDriver.readRawByte( deviceID, registerID );
  }
  catch ( BCException& exception )
  {    
     qDebug() << " -- OUCH: read exception: " << exception.what();
  }
  return result;

}

void BCTransmitter::writeRawByte( uint32_t deviceID, uint8_t registerID , uint8_t value ) const
{
  try
  {
    _canDriver.writeRawByte( deviceID, registerID, value );
  }
  catch ( BCException& exception )
  {
    qDebug() << " -- OUCH: write exception: " << exception.what();
  }

}




