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

#include "widgets_group.hpp"
#include "wdg/color_methods.hpp"
#include "wdg/style_db.hpp"
#include <QEvent>
#include <QFocusEvent>
#include <QPainter>
#include <cassert>
#include <iostream>

namespace Wdg::Switches_Pad
{

Widgets_Group::Widgets_Group ( const Wdg::Style_Db * style_db_n,
                               QWidget * parent_n )
: QWidget ( parent_n )
, _style_db ( style_db_n )
{
  setContextMenuPolicy ( Qt::NoContextMenu );

  connect ( _style_db,
            &Wdg::Style_Db::sig_palette_changed,
            this,
            &Widgets_Group::style_palette_changed );

  QVBoxLayout * lay_vbox ( new QVBoxLayout );
  lay_vbox->setContentsMargins ( 0, 0, 0, 0 );
  setLayout ( lay_vbox );
}

Widgets_Group::~Widgets_Group () = default;

void
Widgets_Group::set_style_id ( unsigned int id_n )
{
  if ( _style_id != id_n ) {
    _style_id = id_n;
    update ();
  }
}

void
Widgets_Group::set_label ( QWidget * wdg_n )
{
  _label.reset ( wdg_n );

  if ( _label ) {
    // Clicking on the head label forwards the focus to the first input widget
    // See eventFilter()
    _label->setFocusPolicy ( Qt::ClickFocus );
    _label->setContextMenuPolicy ( Qt::NoContextMenu );
    _label->installEventFilter ( this );

    if ( !_lay_grid ) {
      // Create grid layout
      _lay_grid = std::make_unique< QGridLayout > ();
      _lay_grid->setContentsMargins (
          fontMetrics ().averageCharWidth () * 8 / 3, 0, 0, 0 );
      _lay_grid->setHorizontalSpacing ( horizontal_spacing () );
    }
    // Setup layout
    lay_vbox ()->addWidget ( _label.get () );
    lay_vbox ()->addLayout ( _lay_grid.get () );
  } else {
    _lay_grid.reset ();
  }
}

void
Widgets_Group::append_widgets_set ( Widgets_Set * wdg_set_n )
{
  if ( wdg_set_n == nullptr ) {
    return;
  }
  assert ( wdg_set_n->input () != nullptr );

  if ( wdg_set_n->label () != nullptr ) {
    // Clicking on the label forwards the focus to the input widget
    // See eventFilter()
    wdg_set_n->label ()->setFocusPolicy ( Qt::ClickFocus );
    wdg_set_n->label ()->setContextMenuPolicy ( Qt::NoContextMenu );
    wdg_set_n->label ()->installEventFilter ( this );
  }

  if ( _lay_grid ) {

    // Multiple input widgets

    const unsigned int row = _widgets_sets.size ();
    if ( wdg_set_n->label () != nullptr ) {
      // Input widget with separate label
      _lay_grid->addWidget ( wdg_set_n->input (), row, 0 );
      _lay_grid->addWidget ( wdg_set_n->label (), row, 1 );
    } else {
      // Single input widget
      _lay_grid->addWidget ( wdg_set_n->input (), row, 0 );
    }

  } else {

    // Single input widget

    if ( wdg_set_n->label () != nullptr ) {
      // Input widget with separate label
      QHBoxLayout * lay_hbox = new QHBoxLayout;
      lay_hbox->setContentsMargins ( 0, 0, 0, 0 );
      lay_hbox->setSpacing ( horizontal_spacing () );

      lay_hbox->addWidget ( wdg_set_n->input () );
      lay_hbox->addWidget ( wdg_set_n->label () );

      lay_vbox ()->addLayout ( lay_hbox );
    } else {
      // Single input widget
      lay_vbox ()->addWidget ( wdg_set_n->input () );
    }
  }

  _widgets_sets.emplace_back ( wdg_set_n );
}

int
Widgets_Group::horizontal_spacing () const
{
  return fontMetrics ().averageCharWidth () * 3 / 4;
}

void
Widgets_Group::style_palette_changed ( unsigned int style_id_n )
{
  if ( _style_id == style_id_n ) {
    update ();
  }
}

bool
Widgets_Group::eventFilter ( QObject * watched_n, QEvent * event_n )
{
  bool res = false;
  if ( event_n->type () == QEvent::FocusIn ) {
    if ( _label && ( watched_n == _label.get () ) ) {
      // When clicking on the head label pass the focus to the first input
      // widget
      if ( !_widgets_sets.empty () ) {
        _widgets_sets[ 0 ]->input ()->setFocus ();
        res = true;
      }
    } else {
      for ( auto & wdg_set : _widgets_sets ) {
        if ( ( wdg_set->label () != nullptr ) &&
             ( watched_n == wdg_set->label () ) ) {
          // When clicking on an input label pass the focus to the input widget
          wdg_set->input ()->setFocus ();
          break;
        }
      }
    }
  }
  return res;
}

void
Widgets_Group::paintEvent ( QPaintEvent * event_n )
{
  QWidget::paintEvent ( event_n );

  if ( _label && _lay_grid && ( num_widgets_sets () > 0 ) ) {
    const QRect re_lbl = _label->geometry ();
    const QRect re_wdg0 = _lay_grid->itemAt ( 0 )->geometry ();

    int x0 = ( re_lbl.x () * 4 + re_wdg0.x () * 3 ) / 7;
    int x1 = re_wdg0.x () - 4;

    if ( !re_lbl.isValid () || !re_wdg0.isValid () || ( x1 <= x0 ) ) {
      return;
    }

    int y0 = re_lbl.y () + re_lbl.height ();
    int y1 = y0;

    QPainter painter ( this );
    painter.setBrush ( Qt::NoBrush );
    {
      QPen pen ( painter.pen () );
      const QPalette & pal = _style_db->palette ( _style_id );
      QColor col_text = pal.color ( QPalette::WindowText );
      QColor col_window = pal.color ( QPalette::Window );
      pen.setColor ( Wdg::col_mix ( col_text, col_window, 1, 1 ) );
      painter.setPen ( pen );
    }
    for ( std::size_t ii = 0; ii < num_widgets_sets (); ++ii ) {
      const QRect re_wdg = _lay_grid->itemAtPosition ( ii, 0 )->geometry ();
      int yy = re_wdg.y () + ( re_wdg.height () + 1 ) / 2;
      if ( y1 < yy ) {
        y1 = yy;
      }
      painter.drawLine ( x0, yy, x1, yy );
    }
    painter.drawLine ( x0, y0, x0, y1 );
  }
}

} // namespace Wdg::Switches_Pad
