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

#include "device_selection_view.hpp"
#include "mwdg/mixers_view.hpp"
#include "mwdg/user_device_input.hpp"
#include "qsnd/mixers_model.hpp"
#include "views/device_selection_view_setup.hpp"
#include <QContextMenuEvent>
#include <QItemSelection>
#include <QLabel>
#include <QMenu>
#include <iostream>

namespace Views
{

Device_Selection_View::Device_Selection_View ( QSnd::Cards_Db * cards_db_n,
                                               QWidget * parent_n )
: QWidget ( parent_n )
{
  // View close action
  {
    _act_close = new QAction ( this );
    _act_close->setText ( tr ( "&Close device selection" ) );
    if ( QIcon::hasThemeIcon ( "window-close" ) ) {
      _act_close->setIcon ( QIcon::fromTheme ( "window-close" ) );
    }
    connect ( _act_close,
              &QAction::triggered,
              this,
              &Device_Selection_View::sig_close );
  }

  // Control selection model and view
  {
    _mixers_model = std::make_unique< QSnd::Mixers_Model > ( cards_db_n, this );

    _mixers_view = std::make_unique< MWdg::Mixers_View > ( this );
    _mixers_view->setModel ( _mixers_model.get () );

    connect ( _mixers_view->selectionModel (),
              &QItemSelectionModel::selectionChanged,
              this,
              &Device_Selection_View::mixer_selection_changed );
  }

  {
    QSizePolicy policy ( sizePolicy () );
    policy.setHorizontalPolicy ( QSizePolicy::Preferred );
    policy.setVerticalPolicy ( QSizePolicy::Expanding );
    setSizePolicy ( policy );
  }

  QLabel * controls_label = new QLabel;
  controls_label->setText ( tr ( "Mixer device" ) );
  {
    QFont fnt ( controls_label->font () );
    fnt.setBold ( true );
    controls_label->setFont ( fnt );
  }

  _lay_user_device = new QVBoxLayout;
  _lay_top = new QVBoxLayout;
  _lay_top->setContentsMargins ( 0, 0, 0, 0 );
  _lay_bottom = new QVBoxLayout;
  _lay_bottom->setContentsMargins ( 0, 0, 0, 0 );
  {
    QVBoxLayout * lay_vbox = new QVBoxLayout;
    lay_vbox->addWidget ( controls_label, 0 );
    lay_vbox->addWidget ( _mixers_view.get (), 100 );
    lay_vbox->addLayout ( _lay_user_device, 0 );
    lay_vbox->addLayout ( _lay_top, 0 );
    lay_vbox->addStretch ( 1 );
    lay_vbox->addLayout ( _lay_bottom, 0 );
    setLayout ( lay_vbox );
  }
}

Device_Selection_View::~Device_Selection_View () = default;

void
Device_Selection_View::set_view_setup (
    Views::Device_Selection_View_Setup * setup_n )
{
  _view_setup = setup_n;
}

void
Device_Selection_View::silent_select_ctl (
    const QSnd::Ctl_Address & ctl_addr_n )
{
  if ( _selected_ctl.match ( ctl_addr_n ) ) {
    return;
  }
  {
    _silent_ctl_change = true;
    _selected_ctl = ctl_addr_n;
    _mixers_view->setCurrentIndex (
        _mixers_model->control_index ( _selected_ctl ) );
    _silent_ctl_change = false;
  }

  user_device_input_update ();
  if ( _user_device_input ) {
    _user_device_input->set_device_silent ( _selected_ctl.addr_str () );
    _view_setup->user_device = _selected_ctl.addr_str ();
  }
}

void
Device_Selection_View::reload_database ()
{
  // std::cout << "Device_Selection_View::reload_database" << "\n";
  _silent_ctl_change = true;
  _mixers_model->reload ();
  _mixers_view->setCurrentIndex (
      _mixers_model->control_index ( _selected_ctl ) );
  _silent_ctl_change = false;
}

void
Device_Selection_View::mixer_selection_changed (
    const QItemSelection & selected_n [[maybe_unused]],
    const QItemSelection & deselected_n [[maybe_unused]] )
{
  if ( _silent_ctl_change ) {
    return;
  }
  user_device_input_update ();
  update_selected_ctl ();
}

QModelIndex
Device_Selection_View::current_index () const
{
  const auto & indices = _mixers_view->selectionModel ()->selectedIndexes ();
  if ( !indices.isEmpty () ) {
    return indices[ 0 ];
  }
  return QModelIndex ();
}

QSnd::Ctl_Address
Device_Selection_View::acquire_ctl_address () const
{
  QSnd::Ctl_Address res;

  const QModelIndex & cidx = current_index ();
  QSnd::Mixers_Model::Entry entry = _mixers_model->entry ( cidx );
  switch ( entry ) {
  case QSnd::Mixers_Model::ENTRY_INVALID:
  case QSnd::Mixers_Model::ENTRY_SEPARATOR:
    res.set_addr_str ( QString () );
    break;
  case QSnd::Mixers_Model::ENTRY_DEFAULT:
    res.set_addr_str ( QStringLiteral ( "default" ) );
    break;
  case QSnd::Mixers_Model::ENTRY_CARD: {
    auto card_info = _mixers_model->card_info ( cidx );
    if ( card_info ) {
      if ( _mixers_model->card_id_is_unique ( card_info->id () ) ) {
        res.set_addr_str ( QStringLiteral ( "hw:" ) + card_info->id () );
      } else {
        res.set_addr_str ( QStringLiteral ( "hw:" ) +
                           QString::number ( card_info->index () ) );
      }
    }
  } break;
  case QSnd::Mixers_Model::ENTRY_USER_DEFINED:
    if ( _user_device_input ) {
      res.set_addr_str ( _user_device_input->device () );
    }
    break;
  }

  return res;
}

void
Device_Selection_View::update_selected_ctl ()
{
  _selected_ctl = acquire_ctl_address ();
  Q_EMIT sig_control_selected ();
}

void
Device_Selection_View::user_device_input_update ()
{
  const bool show = ( _mixers_model->entry ( current_index () ) ==
                      QSnd::Mixers_Model::ENTRY_USER_DEFINED );
  if ( show ) {
    if ( _user_device_input ) {
      return;
    }
    _user_device_input = std::make_unique< MWdg::User_Device_Input > ( this );
    if ( _view_setup != nullptr ) {
      _user_device_input->set_device_silent ( _view_setup->user_device );
    }
    connect ( _user_device_input.get (),
              &MWdg::User_Device_Input::sig_device_changed,
              this,
              &Device_Selection_View::user_device_input_changed );
    _lay_user_device->addWidget ( _user_device_input.get (), 0 );
  } else {
    _user_device_input.reset ();
  }
}

void
Device_Selection_View::user_device_input_changed ()
{
  if ( !_user_device_input ) {
    return;
  }
  if ( _view_setup != nullptr ) {
    _view_setup->user_device = _user_device_input->device ();
  }
  update_selected_ctl ();
}

void
Device_Selection_View::contextMenuEvent ( QContextMenuEvent * event_n )
{
  QMenu cmenu ( this );
  cmenu.addAction ( _act_close );
  cmenu.exec ( event_n->globalPos () );
}

} // namespace Views
