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

#include "switch.hpp"
#include "dpe/image_allocator.hpp"
#include "dpe/image_request.hpp"
#include "dpe/image_set.hpp"
#include "wdg/ds/widget_types.hpp"
#include "wdg/style_db.hpp"
#include <QEvent>
#include <QPainter>
#include <iostream>

namespace Wdg::DS
{

Switch::Switch ( const Wdg::Style_Db * style_db_n,
                 dpe::Image_Allocator * image_alloc_n,
                 QWidget * parent_n )
: QAbstractButton ( parent_n )
, _dsi ( 2, image_alloc_n )
, _update_pixmaps_pending ( false )
, _meta_bg ( num_images_bg, Wdg::DS::WT_SWITCH, 0 )
, _meta_handle ( num_images_handle, Wdg::DS::WT_SWITCH, 1 )
, _style_db ( style_db_n )
{
  _dsi.image_request ()->meta[ 0 ] = &_meta_bg;
  _dsi.image_request ()->meta[ 1 ] = &_meta_handle;

  setCheckable ( true );
  {
    QSizePolicy policy ( sizePolicy () );
    policy.setHorizontalPolicy ( QSizePolicy::Preferred );
    policy.setVerticalPolicy ( QSizePolicy::Preferred );
    setSizePolicy ( policy );
  }

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

  update_palette ();
}

Switch::~Switch ()
{
  _dsi.set_image_alloc ( nullptr );
}

QSize
Switch::sizeHint () const
{
  ensurePolished ();
  const QFontMetrics fmet ( fontMetrics () );
  return QSize ( fmet.height (), fmet.height () );
}

QSize
Switch::minimumSizeHint () const
{
  ensurePolished ();
  const QFontMetrics fmet ( fontMetrics () );
  return QSize ( fmet.height (), fmet.height () );
}

void
Switch::set_style_id ( unsigned int id_n )
{
  if ( style_id () != id_n ) {
    _dsi.set_images_meta_style_id ( id_n );
    update_palette ();
    update_pixmaps ();
    update ();
  }
}

void
Switch::set_variant_id ( unsigned int id_n )
{
  _dsi.set_images_meta_variant_id ( id_n );
}

void
Switch::style_palette_changed ( unsigned int style_id_n )
{
  if ( style_id_n == style_id () ) {
    update_palette ();
    update_pixmaps ();
    update ();
  }
}

void
Switch::changeEvent ( QEvent * event_n )
{
  QWidget::changeEvent ( event_n );

  switch ( event_n->type () ) {
  case QEvent::ActivationChange:
  case QEvent::EnabledChange:
  case QEvent::StyleChange:
  case QEvent::PaletteChange:
  case QEvent::LayoutDirectionChange:
    break;
  default:
    break;
  }

  update_palette ();
  update_pixmaps ();
  update ();
}

void
Switch::enterEvent ( QEnterEvent * event_n )
{
  QAbstractButton::enterEvent ( event_n );
  update ();
}

void
Switch::leaveEvent ( QEvent * event_n )
{
  QAbstractButton::leaveEvent ( event_n );
  update ();
}

void
Switch::resizeEvent ( QResizeEvent * event_n )
{
  QAbstractButton::resizeEvent ( event_n );
  QRect ren ( contentsRect () );
  if ( ren.width () != ren.height () ) {
    const int delta ( ren.width () - ren.height () );
    if ( delta > 0 ) {
      ren.setWidth ( ren.height () );
      ren.moveLeft ( ren.left () + delta / 2 );
    } else {
      ren.setHeight ( ren.width () );
      ren.moveTop ( ren.top () - delta / 2 );
    }
  }

  _pxmap_rect = ren;

  update_pixmaps ();
}

void
Switch::paintEvent ( QPaintEvent * )
{
  if ( _update_pixmaps_pending ) {
    update_pixmaps ();
  }
  _dsi.wait_for_request ();
  if ( !_dsi.images ().ready () ) {
    return;
  }

  QPixmap * pixmap_handle = nullptr;
  QPixmap * pixmap_bg = nullptr;

  // Background setup
  {
    unsigned int img_idx = 0;
    if ( hasFocus () ) {
      img_idx = 1;
    }
    if ( underMouse () && isEnabled () ) {
      img_idx += 2;
    }

    dpe::Image & img = _dsi.images ().img_sets[ 0 ]->image ( img_idx );
    pixmap_bg = img.convert_to_pixmap ();
  }

  // Handle setup
  {
    unsigned int img_idx = 0;
    if ( isDown () ) {
      img_idx = 8;
      if ( underMouse () ) {
        ++img_idx;
      }
    } else {
      if ( isChecked () ) {
        img_idx = 4;
      }
      if ( underMouse () && isEnabled () ) {
        img_idx += 2;
      }
      if ( hasFocus () ) {
        ++img_idx;
      }
    }

    dpe::Image & img = _dsi.images ().img_sets[ 1 ]->image ( img_idx );
    pixmap_handle = img.convert_to_pixmap ();
  }

  // Painting
  QPainter painter ( this );
  if ( pixmap_bg != nullptr ) {
    painter.drawPixmap ( _pxmap_rect.topLeft (), *pixmap_bg );
  }
  if ( pixmap_handle != nullptr ) {
    painter.drawPixmap ( _pxmap_rect.topLeft (), *pixmap_handle );
  }
}

void
Switch::update_palette ()
{
  if ( style_db () != nullptr ) {
    QPalette pal = style_db ()->palette ( style_id () );
    if ( palette () != pal ) {
      setPalette ( pal );
    }
  }
}

void
Switch::update_pixmaps ()
{
  if ( _dsi.image_alloc () != nullptr ) {
    if ( isVisible () ) {
      _update_pixmaps_pending = false;
      // std::cout << "DS_Slider::update_pixmaps " << this << "\n";
      _dsi.wait_for_request ();

      _meta_bg.size = _pxmap_rect.size ();
      _meta_handle.size = _pxmap_rect.size ();
      _dsi.set_images_meta_style_sub_id ( _dsi.style_sub_id ( this ) );
      _dsi.set_images_meta_palette ( palette () );

      _dsi.send_request ();

      update ();
    } else {
      _update_pixmaps_pending = true;
    }
  }
}

} // namespace Wdg::DS
