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

#include "device_settings_dialog.hpp"
#include "mstate/mixer/state.hpp"
#include "mwdg/mixer/proxies_model.hpp"
#include "mwdg/mixer/proxies_settings_model.hpp"
#include "qastools_config.hpp"
#include "qsnd/mixer/mixer.hpp"
#include "views/device_settings_dialog_setup.hpp"
#include <QCheckBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QTableView>
#include <QTreeView>
#include <QVBoxLayout>
#include <QWidget>
#include <QtGlobal>
#include <iostream>

namespace Views
{

Device_Settings_Dialog::Device_Settings_Dialog ( Wdg::Style_Db * wdg_style_db_n,
                                                 QWidget * parent_n,
                                                 Qt::WindowFlags flags_n )
: Views::Multi_Page_Dialog ( parent_n, flags_n )
, _wdg_style_db ( wdg_style_db_n )
{
  {
    QString title_str ( tr ( "Device settings" ) );
    setWindowTitle (
        QString ( "%1 - %2" ).arg ( PROGRAM_TITLE ).arg ( title_str ) );
    set_title_str ( title_str );
  }

  add_pages_begin ();
  init_controls ();
  init_info ();
  add_pages_end ();
}

Device_Settings_Dialog::~Device_Settings_Dialog () = default;

void
Device_Settings_Dialog::init_controls ()
{
  QWidget * central_wdg = new QWidget;
  QVBoxLayout * central_layout = new QVBoxLayout;
  central_layout->setContentsMargins ( 0, 0, 0, 0 );

  // Settings model
  {
    _controls.settings_model =
        new MWdg::Mixer::Proxies_Settings_Model ( _wdg_style_db, this );
    connect ( _controls.settings_model,
              &MWdg::Mixer::Proxies_Settings_Model::sig_visibility_changed,
              this,
              &Device_Settings_Dialog::sig_visibility_changed );
  }
  // Tree view
  {
    _controls.tree_view = new QTreeView;
    _controls.tree_view->setModel ( _controls.settings_model );
    central_layout->addWidget ( _controls.tree_view );
  }
  // Sort by stream dir check box
  {
    _controls.cbox_sort_by_stream =
        new QCheckBox ( tr ( "Sort by playback and capture" ) );
    connect ( _controls.cbox_sort_by_stream,
              &QCheckBox::stateChanged,
              this,
              &Device_Settings_Dialog::controls_sort_by_stream_changed );

    QHBoxLayout * lay_hbox = new QHBoxLayout;
    lay_hbox->addWidget ( _controls.cbox_sort_by_stream, 0 );
    lay_hbox->addStretch ( 1 );
    central_layout->addLayout ( lay_hbox );
  }

  central_wdg->setLayout ( central_layout );

  add_page ( tr ( "Controls" ), central_wdg );
}

void
Device_Settings_Dialog::init_info ()
{
  QWidget * central_wdg = new QWidget;
  QVBoxLayout * central_layout = new QVBoxLayout;
  central_layout->setContentsMargins ( 0, 0, 0, 0 );

  {
    _info.model = new QStandardItemModel ( this );

    auto vrow = [ this ] ( int row_n,
                           const QString & text_n,
                           QStandardItem *& value_item_n ) {
      _info.model->setVerticalHeaderItem ( row_n,
                                           new QStandardItem ( text_n ) );
      value_item_n = new QStandardItem ();
      _info.model->setItem ( row_n, value_item_n );
    };

    int row = 0;
    vrow ( row++, tr ( "Address" ), _info.item_address );
    vrow ( row++, tr ( "Index" ), _info.item_index );
    vrow ( row++, tr ( "Id" ), _info.item_id );
    vrow ( row++, tr ( "Name" ), _info.item_name );
    vrow ( row++, tr ( "Long name" ), _info.item_long_name );
    vrow ( row++, tr ( "Mixer name" ), _info.item_mixer_name );
    vrow ( row++, tr ( "Driver" ), _info.item_driver );
    vrow ( row++, tr ( "Components" ), _info.item_components );
  }

  {
    QTableView * table_view = new QTableView;
    table_view->setModel ( _info.model );
    table_view->setSelectionMode ( QAbstractItemView::SingleSelection );
    table_view->setSelectionBehavior ( QAbstractItemView::SelectItems );
    table_view->horizontalHeader ()->setStretchLastSection ( true );
    table_view->horizontalHeader ()->hide ();
    central_layout->addWidget ( table_view );
  }

  central_wdg->setLayout ( central_layout );

  add_page ( tr ( "Information" ), central_wdg );
}

QSize
Device_Settings_Dialog::sizeHint () const
{
  QSize res = Views::Multi_Page_Dialog::sizeHint ();
  QWidget * par = parentWidget ();
  if ( par != nullptr ) {
    int wpar = ( par->width () * 3 / 5 );
    res.setWidth ( qMax ( res.width (), wpar ) );
    int hpar = ( par->height () * 3 / 4 );
    res.setHeight ( qMax ( res.height (), hpar ) );
  }
  return res;
}

void
Device_Settings_Dialog::set_setup ( Device_Settings_Dialog_Setup * setup_n )
{
  _setup = setup_n;

  if ( _setup != nullptr ) {
    restoreGeometry ( _setup->window_geometry );
    restore_splitter_state ( _setup->splitter_state );
    _controls.tree_view->header ()->restoreState (
        _setup->controls_header_view_state );

    // Select current page
    if ( _setup->page >= num_pages () ) {
      _setup->page = 0;
    }
    set_current_page_idx ( _setup->page );
  }
}

void
Device_Settings_Dialog::set_models (
    MWdg::Mixer::Proxies_Model * model_sliders_n,
    MWdg::Mixer::Proxies_Model * model_switches_n )
{
  if ( _controls.settings_model->sliders_model () != nullptr ) {
    disconnect ( _controls.settings_model->sliders_model (), 0, this, 0 );
  }

  _controls.settings_model->setup ( model_sliders_n, model_switches_n );

  if ( _controls.settings_model->sliders_model () != nullptr ) {
    // Reload controls widget states when the selected mixer changed
    connect ( _controls.settings_model->sliders_model (),
              &MWdg::Mixer::Proxies_Model::sig_reload_end,
              this,
              &Device_Settings_Dialog::update_values );
    // Update values
    update_values ();
  }
}

void
Device_Settings_Dialog::update_values ()
{
  update_values_controls ();
  update_values_information ();
}

void
Device_Settings_Dialog::update_values_controls ()
{
  Qt::CheckState sort_by_stream = Qt::Unchecked;

  // Update values
  auto * proxies_model = _controls.settings_model->sliders_model ();
  if ( ( proxies_model != nullptr ) && proxies_model->mixer_state () ) {
    sort_by_stream = proxies_model->mixer_state ()->sort_stream_dir ()
                         ? Qt::Checked
                         : Qt::Unchecked;
  }

  _controls.updating_values = true;
  _controls.cbox_sort_by_stream->setCheckState ( sort_by_stream );
  _controls.updating_values = false;

  // Expand tree view
  _controls.tree_view->setExpanded (
      _controls.settings_model->index_l0_sliders (), true );
  _controls.tree_view->setExpanded (
      _controls.settings_model->index_l0_switches (), true );
}

void
Device_Settings_Dialog::update_values_information ()
{
  QString address;

  auto * proxies_model = _controls.settings_model->sliders_model ();
  if ( ( proxies_model != nullptr ) &&
       ( proxies_model->qsnd_mixer () != nullptr ) ) {
    address = proxies_model->qsnd_mixer ()->device_address ();
  }

  if ( address.isEmpty () ) {
    _info.card_info.clear ();
  } else {
    _info.card_info.acquire_info ( address );
  }

  _info.item_address->setText ( address );
  if ( _info.card_info.is_valid () ) {
    // Valid card info
    _info.item_index->setText ( QString::number ( _info.card_info.index () ) );
    _info.item_id->setText ( _info.card_info.id () );
    _info.item_name->setText ( _info.card_info.name () );
    _info.item_long_name->setText ( _info.card_info.long_name () );
    _info.item_mixer_name->setText ( _info.card_info.mixer_name () );
    _info.item_driver->setText ( _info.card_info.driver () );
    _info.item_components->setText ( _info.card_info.components () );
  } else {
    // Invalid card info
    QString empty;
    _info.item_index->setText ( empty );
    _info.item_id->setText ( empty );
    _info.item_name->setText ( empty );
    _info.item_long_name->setText ( empty );
    _info.item_mixer_name->setText ( empty );
    _info.item_driver->setText ( empty );
    _info.item_components->setText ( empty );
  }
}

void
Device_Settings_Dialog::controls_sort_by_stream_changed ( int state_n )
{
  if ( _controls.updating_values ) {
    return;
  }

  auto * proxies_model = _controls.settings_model->sliders_model ();
  if ( ( proxies_model == nullptr ) || !proxies_model->mixer_state () ) {
    return;
  }

  std::shared_ptr< MState::Mixer::State > mixer_state =
      proxies_model->mixer_state ();
  bool sort_state = mixer_state->sort_stream_dir ();
  {
    Qt::CheckState check_state = static_cast< Qt::CheckState > ( state_n );
    if ( check_state == Qt::Unchecked ) {
      sort_state = false;
    } else if ( check_state == Qt::Checked ) {
      sort_state = true;
    }
  }
  // Apply changes
  if ( mixer_state->sort_stream_dir () != sort_state ) {
    mixer_state->set_sort_stream_dir ( sort_state );
    Q_EMIT sig_sorting_changed ();
  }
}

void
Device_Settings_Dialog::closeEvent ( QCloseEvent * event_n )
{
  // Save settings
  if ( _setup != nullptr ) {
    _setup->page = current_page_idx ();
    _setup->window_geometry = saveGeometry ();
    _setup->splitter_state = splitter_state ();
    _setup->controls_header_view_state =
        _controls.tree_view->header ()->saveState ();
  }

  Views::Multi_Page_Dialog::closeEvent ( event_n );
}

} // namespace Views
