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

#pragma once

#include <QObject>
#include <vector>

// Forward declaration
namespace MState::Mixer
{
class Controls;
class State;
} // namespace MState::Mixer
namespace MWdg::Mixer
{
class Setup;
}
namespace MWdg::Mixer::Proxy
{
class Group;
}
namespace QSnd::Mixer
{
class Elem;
class Mixer;
} // namespace QSnd::Mixer

namespace MWdg::Mixer
{

/// @brief Proxies_Model
///
class Proxies_Model : public QObject
{
  Q_OBJECT

  public:
  // -- Public types

  using Proxies_Groups_Owner =
      std::vector< std::unique_ptr< MWdg::Mixer::Proxy::Group > >;

  // -- Construction

  Proxies_Model ( QObject * parent_n = nullptr );

  ~Proxies_Model () override;

  // -- Mixer setup

  const MWdg::Mixer::Setup *
  mixer_setup () const
  {
    return _mixer_setup;
  }

  void
  set_mixer_setup ( const MWdg::Mixer::Setup * setup_n );

  // -- Setup

  void
  clear ();

  void
  reload ();

  void
  setup ( QSnd::Mixer::Mixer * qsnd_mixer_n,
          const std::shared_ptr< MState::Mixer::State > & mixer_state_n );

  QSnd::Mixer::Mixer *
  qsnd_mixer () const
  {
    return _qsnd_mixer;
  }

  const std::shared_ptr< MState::Mixer::State > &
  mixer_state () const
  {
    return _mixer_state;
  }

  MState::Mixer::Controls *
  mixer_state_controls () const
  {
    return _mixer_state_controls;
  }

  Q_SIGNAL
  void
  sig_reload_begin ();

  Q_SIGNAL
  void
  sig_reload_end ();

  const std::vector< MWdg::Mixer::Proxy::Group * > &
  proxies_all () const
  {
    return _proxies_all;
  }

  // -- Proxies sorted

  void
  reload_proxies_sorted ();

  const std::vector< MWdg::Mixer::Proxy::Group * > &
  proxies_sorted () const
  {
    return _proxies_sorted;
  }

  /// @brief Returns true if the proxy is blacklisted
  bool
  proxy_sorted_blacklisted ( std::size_t index_n ) const;

  void
  proxy_sorted_set_blacklisted ( std::size_t index_n, bool flag_n );

  Q_SIGNAL void
  sig_reload_sorted_begin ();

  Q_SIGNAL
  void
  sig_reload_sorted_end ();

  // -- Proxies filtered

  /// @brief Clears proxies_visible() and reloads proxies_filtered()
  ///
  /// To update the visible proxies list as well
  /// call reload_proxies_visible() afterwards.

  void
  reload_proxies_filtered ();

  const std::vector< MWdg::Mixer::Proxy::Group * > &
  proxies_filtered () const
  {
    return _proxies_filtered;
  }

  /// @brief Number of filtered proxies with snd_dir_n stream direction
  std::size_t
  proxies_filtered_stats_stream ( std::size_t snd_dir_n )
  {
    return _proxies_filtered_stats_stream[ snd_dir_n ];
  }

  Q_SIGNAL
  void
  sig_reload_filtered_begin ();

  Q_SIGNAL
  void
  sig_reload_filtered_end ();

  // -- Proxies visible

  void
  reload_proxies_visible ();

  Q_SIGNAL
  void
  sig_reload_visible_begin ();

  Q_SIGNAL
  void
  sig_reload_visible_end ();

  const std::vector< MWdg::Mixer::Proxy::Group * > &
  proxies_visible () const
  {
    return _proxies_visible;
  }

  // -- Mixer interface

  void
  toggle_joined_separated ( MWdg::Mixer::Proxy::Group * mspg_n );

  protected:
  // -- Event processing

  bool
  event ( QEvent * event_n ) override;

  // -- Utility

  bool
  show_tool_tips () const;

  QString
  create_group_id ( QSnd::Mixer::Elem * qsme_n, std::size_t snd_dir_n );

  QString
  create_group_tool_tip ( QSnd::Mixer::Elem * qsme_n, std::size_t snd_dir_n );

  virtual MState::Mixer::Controls *
  get_mixer_state_controls () const = 0;

  virtual void
  create_proxies_groups ( Proxies_Groups_Owner & groups_n ) = 0;

  virtual void
  join_proxies_group ( MWdg::Mixer::Proxy::Group * pgrp_n ) = 0;

  virtual void
  separate_proxies_group ( MWdg::Mixer::Proxy::Group * pgrp_n ) = 0;

  bool
  should_be_separated ( const MWdg::Mixer::Proxy::Group * pgrp_n ) const;

  bool
  filter_passed ( const MWdg::Mixer::Proxy::Group * pgrp_n ) const;

  bool
  filter_visible_passed ( const MWdg::Mixer::Proxy::Group * mspg_n ) const;

  void
  clear_proxies_visible ();

  Q_SLOT
  void
  separation_requested ();

  void
  separate_where_requested ();

  protected:
  // -- Attributes
  const MWdg::Mixer::Setup * _mixer_setup = nullptr;
  QSnd::Mixer::Mixer * _qsnd_mixer = nullptr;
  std::shared_ptr< MState::Mixer::State > _mixer_state;
  MState::Mixer::Controls * _mixer_state_controls = nullptr;

  // Proxies groups
  Proxies_Groups_Owner _proxies_groups;
  std::vector< MWdg::Mixer::Proxy::Group * > _proxies_all;
  std::vector< MWdg::Mixer::Proxy::Group * > _proxies_sorted;
  std::vector< MWdg::Mixer::Proxy::Group * > _proxies_filtered;
  std::vector< MWdg::Mixer::Proxy::Group * > _proxies_visible;

  // Statistics
  std::array< std::size_t, 2 > _proxies_filtered_stats_stream;

  // Flags
  bool _separation_requested = false;

  // Strings
  struct
  {
    QString l10n_stream_dir[ 2 ];
  } _tool_tip;
};

} // namespace MWdg::Mixer
