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

  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 <bcvaluemodel.h>
#include <bcvaluetype.h>

/**
 * @brief Konstruktor, ohne Besonderheiten
 * @param parent Das Elternobject
 */

BCValueModel::BCValueModel(QObject *parent)
  : QAbstractTableModel(parent)
{

}

/**
 * @brief Setzt den Headerlabel ( == die Devicebezeichnung )
 * @param headerLabel
 */
void BCValueModel::setHeaderLabel( const QString& headerLabel )
{
  _headerLabel = headerLabel;
}

/**
 * @brief Einen Einzelwert hinzufügen
 * @param val der neue Wert
 */

void BCValueModel::addValue(const BCValue& val)
{
  int row = _valueList.size();
  beginInsertRows(QModelIndex(), row, row);
  _valueList.append(val);
  endInsertRows();
}


/**
 * @brief Gibt die interne Werteliste als const ref zurück
 * @return Die WerteListe
 */

const BCValueList& BCValueModel::getValueList() const
{
  return _valueList;
}


/**
 * @brief Nimmt eine Werteliste in Besitz.
 * @param newValueList Die Wertelist. Nach dem Aufruf leer.
 */

void BCValueModel::takeValueList(BCValueList& newValueList)
{
  beginResetModel();
  // hier nehmen wir die valueList in Besitz.
  _valueList = std::exchange(newValueList, {} );
  endResetModel();
}


/**
 * @brief SLOT, der aufgerufen wird, wenn sich ein Wert und/oder der Zustand eines Wertes geändert hat.
 * Emitted 'dataChanged' um die zuständige View upzudaten.
 *
 * @param row Der Index des geänderten Wertes in der Liste
 * @param state Der neue state des Wertes
 * @param newValue Der neue sichtbare Zahlenwert, formatiert als QString, optionall
 */

void BCValueModel::onValueUpdated( int row, BC::State state, const QString& newVisisbleValue )
{
  qDebug() << " BCValueModel::onValueUpdated update: " << newVisisbleValue;
  if( row > -1 && row < _valueList.size() )
  {
    const BCValue& value = _valueList[row];
    QModelIndex idx = index(row,1);
    value.state = state;
    if( !newVisisbleValue.isEmpty() && newVisisbleValue != value.visibleValue )
    {     
      value.visibleValue = newVisisbleValue;
    }
    // wir schicken auf jeden fall einen update request
    emit dataChanged(idx, idx, {Qt::DisplayRole, Qt::EditRole});
  }
}


/**
 * @brief Gibt die Zeilenanzahl zurück
 * @param parent Der Elternindex
 * @return die Zeilenanzahl
 */

int BCValueModel::rowCount(const QModelIndex& parent) const
{
  if (parent.isValid())
    return 0;
  return _valueList.size();
}


/**
 * @brief Gibt die Spaltenanzahl zurück
 * @param parent Der Elternindex
 * @return die Spaltenanzahl
 */

int BCValueModel::columnCount(const QModelIndex& parent) const
{
  if (parent.isValid())
    return 0;
  return 2;
}


/**
 * @brief Gibt die Header-Einträge zurück
 */

QVariant BCValueModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if (role != Qt::DisplayRole || orientation != Qt::Horizontal || section != 0)
    return QVariant();

  return _headerLabel;
}


/**
 * @brief Gibt die Model-Daten zurück.
 */

QVariant BCValueModel::data(const QModelIndex& index, int role) const
{
  Q_UNUSED(role)

  int row = index.row();
  int col = index.column();

  bool wrongRole = ( role != Qt::DisplayRole && role != Qt::EditRole);
  if (wrongRole || !index.isValid() || row >= _valueList.size() )
    return QVariant();

  const BCValue& value = _valueList.at( row );

  if( col == 0 )
    return value.label;

  if( col == 1)
  {
    if( role == Qt::DisplayRole )
      return QString("%1 %2").arg( value.visibleValue, value.valueType->unitLabel);

    return value.visibleValue;
  }

  return QVariant();


  /*
Das Model Gibt hier, unabhängig von der DataRole, immer das
 * gesamte BCValue Object zurück. Die Umsetzung von Status- und Typeinfromationen in GUI-Elemente
 * findet nicht hier, sondern im BCDelagate statt.

// falsch! wie geben hier doch ordentlich die einzelwerte zurück

 // Bonus: Rechtsbündig für Zahlen
 if (role == Qt::TextAlignmentRole && (index.column() == 0 || index.column() == 2)) {
     return Qt::AlignRight | Qt::AlignVCenter;
 }

 //return QVariant::fromValue( entry );

   return QVariant();

   */
}


Qt::ItemFlags BCValueModel::flags(const QModelIndex& index) const
{
  if (!index.isValid())
    return Qt::NoItemFlags;

  return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}


bool BCValueModel::setData(const QModelIndex& index, const QVariant& value, int role)
{

  // __fix!

  if (index.isValid() && role == Qt::EditRole)
  {
    BCValue& item = _valueList[index.row()];

    // Wir erwarten hier nur den Value-Teil (vom Slider/Editor)
    // Checken ob Int oder Double
    if (value.canConvert<double>())
    {
      item.visibleValue = value.toString();
    }

    _valueList[index.row()] = item;
    emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
    return true;
  }
  return false;
}
