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

#include "pad.hpp"
#include "wdg/color_methods.hpp"
#include "wdg/ds/switch.hpp"
#include "wdg/event_types.hpp"
#include "wdg/label_styled.hpp"
#include "wdg/pad_proxy/column.hpp"
#include "wdg/pad_proxy/enum.hpp"
#include "wdg/pad_proxy/group.hpp"
#include "wdg/pad_proxy/switch.hpp"
#include "wdg/pass_events.hpp"
#include "wdg/switches_pad/fill_columns/layout.hpp"
#include "wdg/switches_pad/widgets_group.hpp"
#include <QComboBox>
#include <QEvent>
#include <iostream>
#include <memory>

namespace Wdg::Switches_Pad
{

Pad::Pad ( const Wdg::Style_Db * wdg_style_db_n,
           dpe::Image_Allocator * image_alloc_n,
           QWidget * parent_n )
: QWidget ( parent_n )
, _wdg_style_db ( wdg_style_db_n )
, _image_alloc ( image_alloc_n )
{
}

Pad::~Pad ()
{
  clear_proxies_groups ();
}

void
Pad::set_viewport_geometry ( const QRect & rect_n )
{
  // std::cout << "Pad::set_viewport_geometry\n";
  if ( _viewport != rect_n ) {
    _viewport = rect_n;

    if ( layout () != 0 ) {
      Wdg::Switches_Pad::Fill_Columns::Layout * lay_cols (
          static_cast< Wdg::Switches_Pad::Fill_Columns::Layout * > (
              layout () ) );
      lay_cols->set_viewport_geometry ( _viewport );
    }
  }
}

void
Pad::set_proxies_groups (
    const std::vector< Wdg::Pad_Proxy::Group * > & groups_n )
{
  if ( _proxies_groups.size () > 0 ) {
    clear_widgets_groups ();
  }

  _proxies_groups = groups_n;

  if ( _proxies_groups.size () > 0 ) {
    create_widgets_groups ();
  }
}

void
Pad::clear_proxies_groups ()
{
  if ( _proxies_groups.size () > 0 ) {
    set_proxies_groups ( std::vector< Wdg::Pad_Proxy::Group * > () );
  }
}

void
Pad::clear_widgets_groups ()
{
  if ( layout () != 0 ) {
    delete layout ();
  }

  for ( std::size_t ii = 0; ii < _proxies_groups.size (); ++ii ) {
    Wdg::Pad_Proxy::Group * grp ( _proxies_groups[ ii ] );
    grp->set_pad ( nullptr );
    for ( std::size_t jj = 0; jj < grp->num_columns (); ++jj ) {
      Wdg::Pad_Proxy::Column * col ( grp->column ( jj ) );
      if ( col->switch_proxy () != nullptr ) {
        col->switch_proxy ()->set_widget ( nullptr );
      }
      if ( col->enum_proxy () != nullptr ) {
        col->enum_proxy ()->set_widget ( nullptr );
      }
    }
  }

  _widgets_groups.clear ();
}

void
Pad::create_widgets_groups ()
{
  // std::cout << "Mixer_Switches::create_widgets_groups\n";

  if ( _proxies_groups.size () == 0 ) {
    return;
  }

  for ( std::size_t ii = 0; ii < _proxies_groups.size (); ++ii ) {
    Wdg::Pad_Proxy::Group * proxy_group = _proxies_groups[ ii ];
    proxy_group->set_pad ( this );
    proxy_group->set_group_index ( ii );

    auto spwg = std::make_unique< Widgets_Group > ( _wdg_style_db, this );
    spwg->set_style_id ( proxy_group->style_id () );

    // Create multi channel head label on demand
    if ( proxy_group->num_columns () > 1 ) {
      Wdg::Label_Styled * label =
          new Wdg::Label_Styled ( _wdg_style_db, spwg.get () );
      label->setText ( proxy_group->group_name () );
      label->setToolTip ( proxy_group->tool_tip () );
      {
        QFont fnt ( font () );
        fnt.setBold ( true );
        label->setFont ( fnt );
      }
      label->set_style_id ( proxy_group->style_id () );
      spwg->set_label ( label );
    }

    for ( std::size_t jj = 0; jj < proxy_group->num_columns (); ++jj ) {
      Wdg::Pad_Proxy::Column * sppc = proxy_group->column ( jj );

      // Enumerated
      if ( sppc->has_enum () ) {
        Wdg::Pad_Proxy::Enum * proxy_enum = sppc->enum_proxy ();
        Widgets_Set * wdg_set = new Widgets_Set;

        // Label
        {
          Wdg::Label_Styled * label =
              new Wdg::Label_Styled ( _wdg_style_db, spwg.get () );
          label->setText ( proxy_enum->item_name () );
          label->setToolTip ( proxy_enum->tool_tip () );
          label->setEnabled ( proxy_enum->is_enabled () );
          label->set_style_id ( proxy_enum->style_id () );
          wdg_set->set_label ( label );
        }

        // Combo box
        {
          // Setup selectable items
          QComboBox * cbox = new QComboBox ( spwg.get () );
          for ( int ee = 0; ee < proxy_enum->enum_num_items (); ++ee ) {
            cbox->addItem ( proxy_enum->enum_item_name ( ee ) );
          }
          cbox->setCurrentIndex ( proxy_enum->enum_index () );
          cbox->setToolTip ( proxy_enum->tool_tip () );
          cbox->setEnabled ( proxy_enum->is_enabled () );

          connect ( cbox,
                    SIGNAL ( currentIndexChanged ( int ) ),
                    proxy_enum,
                    SLOT ( set_enum_index ( int ) ) );
          connect ( proxy_enum,
                    SIGNAL ( sig_enum_index_changed ( int ) ),
                    cbox,
                    SLOT ( setCurrentIndex ( int ) ) );

          wdg_set->set_input ( cbox );
          proxy_enum->set_widget ( cbox );
        }

        spwg->append_widgets_set ( wdg_set );
        continue;
      }

      // Switch
      if ( sppc->has_switch () ) {
        Wdg::Pad_Proxy::Switch * proxy_switch = sppc->switch_proxy ();
        Widgets_Set * wdg_set = new Widgets_Set;

        // Label
        {
          Wdg::Label_Styled * label =
              new Wdg::Label_Styled ( _wdg_style_db, spwg.get () );
          if ( proxy_group->num_columns () > 1 ) {
            label->setText ( proxy_switch->item_name () );
          } else {
            label->setText ( proxy_group->group_name () );
          }
          label->setToolTip ( proxy_switch->tool_tip () );
          label->setEnabled ( proxy_switch->is_enabled () );
          label->set_style_id ( proxy_switch->style_id () );
          wdg_set->set_label ( label );
        }

        // Switch widget
        {
          Wdg::DS::Switch * switch_wdg =
              new Wdg::DS::Switch ( _wdg_style_db, _image_alloc, spwg.get () );
          switch_wdg->setChecked ( proxy_switch->switch_state () );
          switch_wdg->setToolTip ( proxy_switch->tool_tip () );
          switch_wdg->setEnabled ( proxy_switch->is_enabled () );
          switch_wdg->set_style_id ( proxy_switch->style_id () );

          connect ( switch_wdg,
                    SIGNAL ( toggled ( bool ) ),
                    proxy_switch,
                    SLOT ( set_switch_state ( bool ) ) );

          connect ( proxy_switch,
                    SIGNAL ( sig_switch_state_changed ( bool ) ),
                    switch_wdg,
                    SLOT ( setChecked ( bool ) ) );

          wdg_set->set_input ( switch_wdg );
          proxy_switch->set_widget ( switch_wdg );
        }

        spwg->append_widgets_set ( wdg_set );
        continue;
      }
    }

    // Append widgets group to the list
    if ( spwg->num_widgets_sets () > 0 ) {
      _widgets_groups.emplace_back ( std::move ( spwg ) );
    }
  }

  // Setup layout
  {
    auto * lay_cols = new Wdg::Switches_Pad::Fill_Columns::Layout;
    lay_cols->setContentsMargins ( 0, 0, 0, 0 );
    lay_cols->set_horizontal_spacing ( fontMetrics ().averageCharWidth () * 2 );
    lay_cols->set_viewport_geometry ( _viewport );

    for ( std::size_t ii = 0; ii < _widgets_groups.size (); ++ii ) {
      lay_cols->addWidget ( _widgets_groups[ ii ].get () );
    }
    setLayout ( lay_cols );
  }
}

void
Pad::set_focus_proxy ( unsigned int proxies_group_idx_n )
{
  set_focus_proxy ( proxies_group_idx_n, 0 );
}

void
Pad::set_focus_proxy ( unsigned int proxies_group_idx_n,
                       unsigned int proxy_idx_n )
{
  const unsigned int num_groups ( _widgets_groups.size () );
  if ( proxies_group_idx_n < num_groups ) {
    Widgets_Group * spwg = _widgets_groups[ proxies_group_idx_n ].get ();

    QWidget * wdg = nullptr;

    // Try to select the input widget of given widget set
    if ( proxy_idx_n < spwg->num_widgets_sets () ) {
      wdg = spwg->widgets_set ( proxy_idx_n )->input ();
    }

    if ( wdg == nullptr ) {
      // No widget found so far - Take first input widget then
      for ( std::size_t ii = 0; ii < spwg->num_widgets_sets (); ++ii ) {
        Widgets_Set * spw = spwg->widgets_set ( ii );
        if ( spw->input () != nullptr ) {
          wdg = spw->input ();
          break;
        }
      }
    }

    if ( wdg != nullptr ) {
      wdg->setFocus ();
    }
  }
}

bool
Pad::event ( QEvent * event_n )
{
  if ( event_n->type () == Wdg::evt_pass_event_focus ) {
    Wdg::Pass_Event_Focus * ev_fp (
        static_cast< Wdg::Pass_Event_Focus * > ( event_n ) );

    _focus_info.clear ();
    if ( ev_fp->ev_focus.gotFocus () &&
         ( ev_fp->group_idx < num_proxies_groups () ) ) {
      _focus_info.has_focus = true;
      _focus_info.group_idx = ev_fp->group_idx;
      _focus_info.column_idx = ev_fp->column_idx;
    }

    Q_EMIT sig_focus_changed ();

    return true;
  }

  return QWidget::event ( event_n );
}

} // namespace Wdg::Switches_Pad
