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

#include "mixers_delegate.hpp"
#include "qsnd/mixers_model.hpp"
#include <QApplication>
#include <QPainter>
#include <iostream>

namespace MWdg
{

Mixers_Delegate::Mixers_Delegate ( QObject * parent_n )
: QStyledItemDelegate ( parent_n )
{
}

Mixers_Delegate::~Mixers_Delegate () = default;

QMargins
Mixers_Delegate::item_margins ( const QFontMetrics & fmet_n ) const
{
  QMargins res;
  int horizontal = fmet_n.averageCharWidth () * 3 / 4;
  int vertical = fmet_n.height () / 4;
  res.setTop ( vertical );
  res.setBottom ( vertical );
  res.setLeft ( horizontal );
  res.setRight ( horizontal );
  return res;
}

QSize
Mixers_Delegate::sizeHint ( const QStyleOptionViewItem & option_n,
                            const QModelIndex & index_n ) const
{
  QSize res ( 0, 0 );
  if ( index_n.model () == nullptr ) {
    return res;
  }
  auto mixers_model =
      dynamic_cast< const QSnd::Mixers_Model * > ( index_n.model () );
  if ( mixers_model == nullptr ) {
    return res;
  }
  QSnd::Mixers_Model::Entry entry = mixers_model->entry ( index_n );

  QStyleOptionViewItem opt ( option_n );
  initStyleOption ( &opt, index_n );

  const QMargins imarg = item_margins ( opt.fontMetrics );

  // Width
  res.rwidth () += opt.fontMetrics.averageCharWidth () * 12;
  res.rwidth () += imarg.left ();
  res.rwidth () += imarg.right ();

  // Height
  switch ( entry ) {
  case QSnd::Mixers_Model::ENTRY_INVALID:
    break;
  case QSnd::Mixers_Model::ENTRY_SEPARATOR:
    res.rheight () += 1;
    break;
  case QSnd::Mixers_Model::ENTRY_DEFAULT:
  case QSnd::Mixers_Model::ENTRY_CARD:
    res.rheight () += opt.fontMetrics.height () * 2;
    res.rheight () += _vspace;
    res.rheight () += imarg.top ();
    res.rheight () += imarg.bottom ();
    break;
  case QSnd::Mixers_Model::ENTRY_USER_DEFINED:
    res.rheight () += opt.fontMetrics.height ();
    res.rheight () += imarg.top ();
    res.rheight () += imarg.bottom ();
    break;
  }

  return res;
}

void
Mixers_Delegate::paint ( QPainter * painter_n,
                         const QStyleOptionViewItem & option_n,
                         const QModelIndex & index_n ) const
{
  if ( index_n.model () == nullptr ) {
    return;
  }
  auto mixers_model =
      dynamic_cast< const QSnd::Mixers_Model * > ( index_n.model () );
  if ( mixers_model == nullptr ) {
    return;
  }
  QSnd::Mixers_Model::Entry entry = mixers_model->entry ( index_n );

  QStyleOptionViewItem opt ( option_n );
  initStyleOption ( &opt, index_n );
  opt.text = QString ();

  const QMargins imarg = item_margins ( opt.fontMetrics );
  double rrad = qMin ( qMin ( imarg.top (), imarg.bottom () ),
                       qMin ( imarg.left (), imarg.right () ) );

  // Foreground (text) color
  QColor col_fg;
  {
    // Color group from state
    QPalette::ColorGroup col_grp = QPalette::Active;
    if ( ( ( opt.state & QStyle::State_Enabled ) != 0 ) ||
         ( entry == QSnd::Mixers_Model::ENTRY_SEPARATOR ) ) {
      if ( ( opt.state & QStyle::State_Active ) == 0 ) {
        col_grp = QPalette::Inactive;
      }
    } else {
      col_grp = QPalette::Disabled;
    }

    // Adjust background brush and foreground color from state
    QPalette::ColorRole col_role = QPalette::Text;
    if ( ( opt.state & QStyle::State_Selected ) != 0 ) {
      col_role = QPalette::HighlightedText;

      QBrush & br = opt.backgroundBrush;
      br.setStyle ( Qt::SolidPattern );
      br.setColor ( opt.palette.color ( col_grp, QPalette::Highlight ) );
    }
    col_fg = opt.palette.color ( col_grp, col_role );
  }

  // Save and setup painter
  painter_n->save ();
  painter_n->setRenderHints ( QPainter::TextAntialiasing |
                              QPainter::Antialiasing );

  // Paint background
  if ( ( opt.state & QStyle::State_Selected ) != 0 ) {
    // Paint solid area
    {
      painter_n->setBrush ( opt.backgroundBrush );
      painter_n->setPen ( Qt::NoPen );
      painter_n->drawRoundedRect ( opt.rect, rrad, rrad );
    }

    // Paint frame
    {
      painter_n->setBrush ( Qt::NoBrush );
      {
        QPen pen;
        pen.setWidth ( 1 );
        {
          QColor pcol ( col_fg );
          Qt::PenStyle pstyle;
          if ( ( opt.state & QStyle::State_Active ) != 0 ) {
            pcol.setAlpha ( 128 );
            pstyle = Qt::DotLine;
          } else {
            pcol.setAlpha ( 32 );
            pstyle = Qt::SolidLine;
          }
          pen.setColor ( pcol );
          pen.setStyle ( pstyle );
        }
        painter_n->setPen ( pen );
      }
      QRectF re_frame ( opt.rect );
      re_frame.adjust ( 0.5, 0.5, -0.5, -0.5 );
      painter_n->drawRoundedRect ( re_frame, rrad, rrad );
    }
  }

  switch ( entry ) {
  case QSnd::Mixers_Model::ENTRY_INVALID:
    break;

  case QSnd::Mixers_Model::ENTRY_SEPARATOR: {
    QRect re_line;
    re_line.setWidth ( opt.rect.width () - imarg.left () - imarg.right () );
    re_line.setHeight ( opt.rect.height () );
    re_line.moveLeft ( opt.rect.left () + imarg.left () );
    re_line.moveTop ( opt.rect.top () );

    painter_n->setPen ( Qt::NoPen );
    {
      QColor pcol ( col_fg );
      pcol.setAlpha ( 110 );
      QBrush pbrush ( pcol, Qt::SolidPattern );
      painter_n->setBrush ( pbrush );
    }
    painter_n->drawRect ( re_line );
  } break;

  case QSnd::Mixers_Model::ENTRY_DEFAULT:
  case QSnd::Mixers_Model::ENTRY_CARD: {
    QRect re_t1;
    re_t1.setWidth ( opt.rect.width () - imarg.left () - imarg.right () );
    re_t1.setHeight ( opt.fontMetrics.height () );
    re_t1.moveLeft ( opt.rect.left () + imarg.left () );
    re_t1.moveTop ( opt.rect.top () + imarg.top () );

    QRect re_t2;
    re_t2.setWidth ( re_t1.width () );
    re_t2.setHeight ( re_t1.height () );
    re_t2.moveLeft ( re_t1.left () );
    re_t2.moveTop ( re_t1.top () + re_t1.height () + _vspace );

    // Setup painter for text
    painter_n->setPen ( QPen ( col_fg ) );
    painter_n->setBrush ( Qt::NoBrush );
    painter_n->setFont ( opt.font );

    // Name string
    {
      QVariant var;
      if ( entry == QSnd::Mixers_Model::ENTRY_DEFAULT ) {
        var = index_n.data ( Qt::DisplayRole );
      } else {
        var = index_n.data ( QSnd::Mixers_Model::ROLE_NAME );
      }
      QString txt = opt.fontMetrics.elidedText (
          var.toString (), opt.textElideMode, re_t1.width () );
      painter_n->drawText ( re_t1, Qt::AlignLeft | Qt::AlignVCenter, txt );
    }

    // Bottom string
    {
      QFont pfnt = opt.font;
      pfnt.setItalic ( true );
      painter_n->setFont ( pfnt );
    }

    {
      QColor pcol ( col_fg );
      pcol.setAlpha ( 190 );
      painter_n->setPen ( QPen ( pcol ) );
    }
    {
      QVariant var;
      if ( entry == QSnd::Mixers_Model::ENTRY_DEFAULT ) {
        var = index_n.data ( QSnd::Mixers_Model::ROLE_NAME );
      } else {
        var = index_n.data ( QSnd::Mixers_Model::ROLE_MIXER_NAME );
      }
      QString txt = opt.fontMetrics.elidedText (
          var.toString (), opt.textElideMode, re_t2.width () );
      painter_n->drawText ( re_t2, Qt::AlignLeft | Qt::AlignVCenter, txt );
    }
  } break;

  case QSnd::Mixers_Model::ENTRY_USER_DEFINED: {
    QRect re_t0;
    re_t0.setWidth ( opt.rect.width () - imarg.left () - imarg.right () );
    re_t0.setHeight ( opt.fontMetrics.height () );
    re_t0.moveLeft ( opt.rect.left () + imarg.left () );
    re_t0.moveTop ( opt.rect.top () + imarg.top () );

    // Setup painter for text
    painter_n->setPen ( QPen ( col_fg ) );
    painter_n->setBrush ( Qt::NoBrush );
    painter_n->setFont ( opt.font );

    // Name string
    {
      QString txt ( index_n.data ( Qt::DisplayRole ).toString () );
      txt =
          opt.fontMetrics.elidedText ( txt, opt.textElideMode, re_t0.width () );
      painter_n->drawText ( re_t0, Qt::AlignLeft | Qt::AlignVCenter, txt );
    }
  } break;
  }

  // Restore painter
  painter_n->restore ();
}

} // namespace MWdg
