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

#include "proxies_model.hpp"
#include "mstate/mixer/controls.hpp"
#include "mstate/mixer/state.hpp"
#include "mwdg/mixer/sliders/proxy/column.hpp"
#include "mwdg/mixer/sliders/proxy/group.hpp"
#include "mwdg/mixer/sliders/proxy/slider.hpp"
#include "mwdg/mixer/sliders/proxy/switch.hpp"
#include "mwdg/mixer_styles.hpp"
#include "qsnd/mixer/elem.hpp"
#include "qsnd/mixer/mixer.hpp"
#include "wdg/pad_proxy/style.hpp"
#include <QCoreApplication>
#include <QEvent>
#include <algorithm>
#include <iostream>

namespace MWdg::Mixer::Sliders
{

Proxies_Model::Proxies_Model ( QObject * parent_n )
: MWdg::Mixer::Proxies_Model ( parent_n )
{
  _tool_tip.l10n_slider[ 0 ] = tr ( "Playback slider" );
  _tool_tip.l10n_slider[ 1 ] = tr ( "Capture slider" );
  _tool_tip.l10n_switch[ 0 ] = tr ( "Playback switch" );
  _tool_tip.l10n_switch[ 1 ] = tr ( "Capture switch" );
}

Proxies_Model::~Proxies_Model () = default;

void
Proxies_Model::create_proxies_groups ( Proxies_Groups_Owner & groups_n )
{
  for ( std::size_t ii = 0; ii < _qsnd_mixer->num_elems (); ++ii ) {
    QSnd::Mixer::Elem * qsme = _qsnd_mixer->elem ( ii );

    for ( std::size_t snd_dir = 0; snd_dir < 2; ++snd_dir ) {
      if ( !qsme->has_volume ( snd_dir ) ) {
        continue;
      }

      // Create a new group
      std::unique_ptr< MWdg::Mixer::Proxy::Group > pgrp (
          new Proxy::Group ( this ) );

      pgrp->set_qsnd_mixer_elem ( qsme );
      pgrp->set_snd_dir ( snd_dir );
      pgrp->set_group_id ( create_group_id ( qsme, snd_dir ) );
      pgrp->set_group_name ( qsme->display_name () );
      pgrp->set_style_id ( MWdg::Mixer_Style::PLAYBACK + snd_dir );
      if ( show_tool_tips () ) {
        pgrp->set_tool_tip ( create_group_tool_tip ( qsme, snd_dir ) );
      }

      if ( should_be_separated ( pgrp.get () ) ) {
        setup_proxies_group_separate ( pgrp.get () );
      } else {
        setup_proxies_group_joined ( pgrp.get () );
      }

      if ( pgrp->num_columns () > 0 ) {
        // Keep group
        groups_n.emplace_back ( std::move ( pgrp ) );
      }
    }
  }
}

void
Proxies_Model::setup_proxies_group_joined ( MWdg::Mixer::Proxy::Group * pgrp_n )
{
  // Store separation state
  _mixer_state->sliders ().set_proxies_group_separated ( pgrp_n->group_id (),
                                                         false );

  pgrp_n->clear_columns ();
  pgrp_n->set_is_joined ( true );

  create_proxies_column ( pgrp_n, 0 );
  pgrp_n->update_mixer_values ();
}

void
Proxies_Model::setup_proxies_group_separate (
    MWdg::Mixer::Proxy::Group * pgrp_n )
{
  // Store separation state
  _mixer_state->sliders ().set_proxies_group_separated ( pgrp_n->group_id (),
                                                         true );

  pgrp_n->clear_columns ();
  pgrp_n->set_is_joined ( false );

  const std::size_t num_channels =
      pgrp_n->qsnd_mixer_elem ()->num_channels ( pgrp_n->snd_dir () );
  for ( std::size_t ii = 0; ii < num_channels; ++ii ) {
    create_proxies_column ( pgrp_n, ii );
  }
  pgrp_n->update_mixer_values ();
}

void
Proxies_Model::create_proxies_column ( MWdg::Mixer::Proxy::Group * pgrp_n,
                                       unsigned int channel_idx_n )
{
  QSnd::Mixer::Elem * qsme = pgrp_n->qsnd_mixer_elem ();
  const std::size_t snd_dir = pgrp_n->snd_dir ();

  auto mspc = std::make_unique< Proxy::Column > ();

  // Item name
  QString iname;
  if ( pgrp_n->is_joined () ) {
    iname = pgrp_n->group_name ();
  } else {
    iname = tr ( "%1 (%2)" );
    iname = iname.arg ( QCoreApplication::translate (
        "ALSA::Channel_Name", qsme->channel_name ( snd_dir, channel_idx_n ) ) );
    iname = iname.arg ( qsme->channel ( snd_dir, channel_idx_n ) );
  }

  // Tool tip
  QString ttip_name;
  QString ttip_channel;
  if ( show_tool_tips () ) {
    ttip_name += QLatin1StringView ( "<div><b>" );
    ttip_name += pgrp_n->group_name ();
    ttip_name += QLatin1StringView ( "</b></div>\n" );

    if ( !pgrp_n->is_joined () ) {
      ttip_channel += QLatin1StringView ( "<div>" );
      ttip_channel += iname;
      ttip_channel += QLatin1StringView ( "</div>\n" );
    }
  }

  // Create volume proxy
  if ( qsme->has_volume ( snd_dir ) &&
       ( channel_idx_n < qsme->num_volume_channels ( snd_dir ) ) ) {
    Proxy::Slider * msps = new Proxy::Slider;

    msps->set_snd_dir ( snd_dir );
    msps->set_channel_idx ( channel_idx_n );
    msps->set_is_joined ( pgrp_n->is_joined () );
    msps->set_qsnd_mixer_elem ( qsme );

    msps->set_item_name ( iname );
    msps->set_group_name ( pgrp_n->group_name () );
    msps->set_style_id ( pgrp_n->style_id () );

    if ( show_tool_tips () ) {
      QString ttip ( ttip_name );
      {
        QString ttip_type;
        ttip_type += QLatin1StringView ( "<div>" );
        ttip_type += _tool_tip.l10n_slider[ snd_dir ];
        ttip_type += QLatin1StringView ( "</div>" );
        ttip += ttip_type;
      }
      ttip += ttip_channel;
      msps->set_tool_tip ( ttip );
    }

    // Proxy Style
    if ( msps->has_dB () ) {

      Wdg::Pad_Proxy::Style * pstyle ( new Wdg::Pad_Proxy::Style );

      if ( ( msps->dB_max () > 0 ) && ( msps->dB_min () < 0 ) ) {
        pstyle->slider_has_minimum = true;
        pstyle->slider_minimum_idx = msps->ask_dB_vol_nearest ( 0 );
      } else {
        if ( msps->dB_max () <= 0 ) {
          pstyle->slider_has_minimum = true;
          pstyle->slider_minimum_idx = msps->slider_index_max ();
        } else if ( msps->dB_min () >= 0 ) {
          pstyle->slider_has_minimum = true;
          pstyle->slider_minimum_idx = 0;
        }
      }

      msps->set_style ( pstyle );
    }

    mspc->set_slider_proxy ( msps );
  }

  // Create switch proxy
  if ( qsme->has_switch ( snd_dir ) &&
       ( channel_idx_n < qsme->num_switch_channels ( snd_dir ) ) ) {
    Proxy::Switch * msps = new Proxy::Switch;

    msps->set_snd_dir ( snd_dir );
    msps->set_channel_idx ( channel_idx_n );
    msps->set_is_joined ( pgrp_n->is_joined () );
    msps->set_qsnd_mixer_elem ( qsme );

    msps->set_item_name ( iname );
    msps->set_group_name ( pgrp_n->group_name () );
    msps->set_style_id ( pgrp_n->style_id () );

    if ( show_tool_tips () ) {
      QString ttip ( ttip_name );
      {
        QString ttip_type;
        ttip_type += QLatin1StringView ( "<div>" );
        ttip_type += _tool_tip.l10n_switch[ snd_dir ];
        ttip_type += QLatin1StringView ( "</div>" );
        ttip += ttip_type;
      }
      ttip += ttip_channel;
      msps->set_tool_tip ( ttip );
    }

    mspc->set_switch_proxy ( msps );
  }

  if ( mspc->has_slider () || mspc->has_switch () ) {
    pgrp_n->append_column ( mspc.release () );
  }
}

MState::Mixer::Controls *
Proxies_Model::get_mixer_state_controls () const
{
  if ( mixer_state () ) {
    return &mixer_state ()->sliders ();
  }
  return nullptr;
}

void
Proxies_Model::join_proxies_group ( MWdg::Mixer::Proxy::Group * pgrp_n )
{
  if ( !pgrp_n->is_joined () ) {
    // Level volumes and switches
    {
      QSnd::Mixer::Elem * qsme = pgrp_n->qsnd_mixer_elem ();
      qsme->level_volumes ( pgrp_n->snd_dir () );
      qsme->level_switches ( pgrp_n->snd_dir () );
    }
    setup_proxies_group_joined ( pgrp_n );
  }
}

void
Proxies_Model::separate_proxies_group ( MWdg::Mixer::Proxy::Group * pgrp_n )
{
  if ( pgrp_n->is_joined () && pgrp_n->can_be_separated () ) {
    setup_proxies_group_separate ( pgrp_n );
  }
}

} // namespace MWdg::Mixer::Sliders
