/// QasTools: Desktop toolset for the Linux sound system ALSA.
/// \copyright See COPYING file.

#include "cards_model.hpp"
#include "qsnd/cards_db.hpp"
#include <iostream>

namespace QSnd
{

Cards_Model::Cards_Model ( QSnd::Cards_Db * cards_db_n, QObject * parent_n )
: QAbstractListModel ( parent_n )
, _cards_db ( cards_db_n )
{
  connect ( _cards_db,
            &QSnd::Cards_Db::sig_card_new,
            this,
            &Cards_Model::on_card_new );

  connect ( _cards_db,
            &QSnd::Cards_Db::sig_card_removed,
            this,
            &Cards_Model::on_card_removed );

  // Initialize cards from card database
  _cards = cards_db_n->cards ();
}

Cards_Model::~Cards_Model () = default;

Cards_Model::Card_Handle
Cards_Model::card_info_by_model_index ( const QModelIndex & idx_n ) const
{
  if ( !idx_n.isValid () || idx_n.parent ().isValid () ||
       ( idx_n.column () != 0 ) || ( idx_n.row () < 0 ) ||
       ( idx_n.row () >= static_cast< int > ( _cards.size () ) ) ) {
    return Card_Handle ();
  }
  return _cards[ idx_n.row () ];
}

QModelIndex
Cards_Model::model_index_by_card_id ( const QString & id_str_n ) const
{
  bool is_int = false;
  int int_val = id_str_n.toInt ( &is_int );

  int ii = 0;
  for ( const auto & item : _cards ) {
    if ( is_int && ( item->index () == int_val ) ) {
      return index ( ii, 0 );
    }
    if ( item->id () == id_str_n ) {
      return index ( ii, 0 );
    }
    ++ii;
  }

  return QModelIndex ();
}

QHash< int, QByteArray >
Cards_Model::roleNames () const
{
  auto res = QAbstractListModel::roleNames ();
  res.insert ( ROLE_INDEX, "index" );
  res.insert ( ROLE_ID, "id" );
  res.insert ( ROLE_DRIVER, "driver" );
  res.insert ( ROLE_NAME, "name" );
  res.insert ( ROLE_LONG_NAME, "longName" );
  res.insert ( ROLE_MIXER_NAME, "mixerName" );
  res.insert ( ROLE_COMPONENTS, "components" );
  return res;
}

int
Cards_Model::rowCount ( const QModelIndex & parent_n ) const
{
  if ( parent_n.isValid () ) {
    return 0;
  }
  return _cards.size ();
}

QVariant
Cards_Model::data ( const QModelIndex & index_n, int role_n ) const
{
  auto handle = card_info_by_model_index ( index_n );
  if ( handle ) {
    switch ( role_n ) {
    case Qt::DisplayRole:
      return QVariant ( handle->name () );
    case ROLE_INDEX:
      return QVariant ( handle->index () );
    case ROLE_ID:
      return QVariant ( handle->id () );
    case ROLE_DRIVER:
      return QVariant ( handle->driver () );
    case ROLE_NAME:
      return QVariant ( handle->name () );
    case ROLE_LONG_NAME:
      return QVariant ( handle->long_name () );
    case ROLE_MIXER_NAME:
      return QVariant ( handle->mixer_name () );
    case ROLE_COMPONENTS:
      return QVariant ( handle->components () );
    default:
      break;
    }
  }
  return QVariant ();
}

void
Cards_Model::on_card_new ( std::shared_ptr< const QSnd::Card_Info > handle_n )
{
  int index = 0;
  for ( const auto & ex_card : _cards ) {
    if ( ex_card->index () > handle_n->index () ) {
      break;
    }
    ++index;
  }
  beginInsertRows ( QModelIndex (), index, index );
  _cards.insert ( _cards.cbegin () + index, handle_n );
  endInsertRows ();
  Q_EMIT countChanged ();
}

void
Cards_Model::on_card_removed (
    std::shared_ptr< const QSnd::Card_Info > handle_n )
{
  for ( auto it = _cards.cbegin (); it != _cards.cend (); ++it ) {
    if ( *( *it ) == *handle_n ) {
      auto index = std::distance ( _cards.cbegin (), it );
      beginRemoveRows ( QModelIndex (), index, index );
      _cards.erase ( it );
      endRemoveRows ();
      Q_EMIT countChanged ();
      break;
    }
  }
}

} // namespace QSnd
