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

#include "slider.hpp"
#include "wdg/pass_events.hpp"
#include "wdg/uint_mapper.hpp"
#include <QApplication>
#include <iostream>

namespace MWdg::Mixer::Sliders::Proxy
{

Slider::Slider ()
: _qsnd_mixer_elem ( nullptr )
, _volume_val ( 0 )
, _volume_min ( 0 )
, _volume_max ( 0 )
, _dB_val ( 0 )
, _channel_idx ( 0 )
, _snd_dir ( 0 )
, _is_joined ( false )
, _alsa_updating ( false )
{
  update_limits ();
}

Slider::~Slider () = default;

void
Slider::set_snd_dir ( unsigned char dir_n )
{
  _snd_dir = dir_n;
  update_limits ();
}

void
Slider::set_channel_idx ( unsigned int idx_n )
{
  _channel_idx = idx_n;
}

void
Slider::set_qsnd_mixer_elem ( QSnd::Mixer::Elem * selem_n )
{
  _qsnd_mixer_elem = selem_n;
  update_limits ();
}

void
Slider::set_is_joined ( bool flag_n )
{
  _is_joined = flag_n;
}

void
Slider::set_dB_value ( long dB_val_n )
{
  if ( has_dB () ) {
    if ( _dB_val != dB_val_n ) {
      _dB_val = dB_val_n;
      this->dB_value_changed ();
      Q_EMIT sig_dB_value_changed ( _dB_val );
    }
  }
}

void
Slider::update_limits ()
{
  unsigned long idx_max ( 0 );
  if ( qsnd_mixer_elem () == 0 ) {
    _volume_min = 0;
    _volume_max = 0;
  } else {
    _volume_min = qsnd_mixer_elem ()->volume_min ( snd_dir () );
    _volume_max = qsnd_mixer_elem ()->volume_max ( snd_dir () );
    idx_max = Wdg::integer_distance ( _volume_min, _volume_max );
  }

  set_slider_index_max ( idx_max );
}

void
Slider::set_volume_value ( long value_n )
{
  if ( _volume_val != value_n ) {
    _volume_val = value_n;
    this->volume_value_changed ();
  }
}

int
Slider::volume_permille () const
{
  int res;
  unsigned long val;
  unsigned long max;
  if ( _volume_val >= 0 ) {
    val = _volume_val;
    max = _volume_max;
  } else {
    val = -_volume_val;
    max = -_volume_min;
  }

  res = Wdg::permille ( val, max );
  if ( _volume_val < 0 ) {
    res = -res;
  }
  return res;
}

void
Slider::dB_value_changed ()
{
  // std::cout << "Slider::dB_value_changed " <<
  //  slider_value() << "\n";

  if ( ( qsnd_mixer_elem () != 0 ) && ( !_alsa_updating ) ) {
    if ( is_joined () ) {
      qsnd_mixer_elem ()->set_dB_all ( snd_dir (), dB_value () );
    } else {
      qsnd_mixer_elem ()->set_dB ( snd_dir (), channel_idx (), dB_value () );
    }
  }

  // std::cout << "Slider::dB_value_changed " << "done" <<
  //"\n";
}

void
Slider::volume_value_changed ()
{
  // std::cout << "Slider::volume_value_changed " <<
  //  volume_value() << "\n";
  {
    unsigned long idx (
        Wdg::integer_distance ( volume_min (), volume_value () ) );
    set_slider_index ( idx );
  }

  if ( ( qsnd_mixer_elem () != 0 ) && ( !_alsa_updating ) ) {
    bool key_mod (
        ( QApplication::keyboardModifiers () & Qt::ControlModifier ) != 0 );
    key_mod = ( key_mod && has_focus () );
    if ( is_joined () || key_mod ) {
      qsnd_mixer_elem ()->set_volume_all ( snd_dir (), volume_value () );
    } else {
      qsnd_mixer_elem ()->set_volume (
          snd_dir (), channel_idx (), volume_value () );
    }
  }
}

void
Slider::slider_index_changed ()
{
  // std::cout << "Slider::slider_index_changed " <<
  //  slider_index() << "\n";

  {
    long vol ( _volume_min );
    vol += slider_index ();
    set_volume_value ( vol );
  }
}

void
Slider::update_value_from_source ()
{
  if ( ( qsnd_mixer_elem () != nullptr ) && ( !_alsa_updating ) ) {
    _alsa_updating = true;
    if ( has_dB () ) {
      set_dB_value (
          qsnd_mixer_elem ()->dB_value ( snd_dir (), channel_idx () ) );
    }
    set_volume_value (
        qsnd_mixer_elem ()->volume ( snd_dir (), channel_idx () ) );
    _alsa_updating = false;
  }
}

bool
Slider::eventFilter ( QObject * obj_n, QEvent * event_n )
{
  bool res = Wdg::Pad_Proxy::Slider::eventFilter ( obj_n, event_n );

  if ( !res ) {
    if ( ( event_n->type () == QEvent::KeyPress ) ||
         ( event_n->type () == QEvent::KeyRelease ) ||
         ( event_n->type () == QEvent::ShortcutOverride ) ) {
      QKeyEvent * ev_kev ( static_cast< QKeyEvent * > ( event_n ) );
      // Pass certain key events to the parent proxy

      if ( parent () != nullptr ) {
        switch ( ev_kev->key () ) {
        case Qt::Key_Space:
        case Qt::Key_VolumeMute: {
          Wdg::Pass_Event_Key ev_pass ( *ev_kev, 0 );
          QCoreApplication::sendEvent ( parent (), &ev_pass );
        } break;
        default:
          break;
        }
      }
    }
  }

  return res;
}

} // namespace MWdg::Mixer::Sliders::Proxy
