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

#include "proxies_settings_model.hpp"
#include "mwdg/mixer/proxies_model.hpp"
#include "mwdg/mixer/proxy/group.hpp"
#include "wdg/style_db.hpp"
#include <QFont>
#include <iostream>

namespace MWdg::Mixer
{

Proxies_Settings_Model::Proxies_Settings_Model ( Wdg::Style_Db * wdg_style_db_n,
                                                 QObject * parent_n )
: QAbstractItemModel ( parent_n )
, _wdg_style_db ( wdg_style_db_n )
{
}

Proxies_Settings_Model::~Proxies_Settings_Model () = default;

void
Proxies_Settings_Model::setup ( Proxies_Model * sliders_model_n,
                                Proxies_Model * switches_model_n )
{
  rebuild_sliders_begin ();
  rebuild_switches_begin ();

  if ( proxies_models_valid () ) {
    disconnect ( _sliders.model, 0, this, 0 );
    disconnect ( _switches.model, 0, this, 0 );
  }

  _sliders.model = sliders_model_n;
  _switches.model = switches_model_n;

  if ( proxies_models_valid () ) {
    // Connect sliders
    connect ( _sliders.model,
              &Proxies_Model::sig_reload_sorted_begin,
              this,
              &Proxies_Settings_Model::rebuild_sliders_begin );
    connect ( _sliders.model,
              &Proxies_Model::sig_reload_sorted_end,
              this,
              &Proxies_Settings_Model::rebuild_sliders_end );

    // Connect switches
    connect ( _switches.model,
              &Proxies_Model::sig_reload_sorted_begin,
              this,
              &Proxies_Settings_Model::rebuild_switches_begin );
    connect ( _switches.model,
              &Proxies_Model::sig_reload_sorted_end,
              this,
              &Proxies_Settings_Model::rebuild_switches_end );
  }

  rebuild_switches_end ();
  rebuild_sliders_end ();
}

bool
Proxies_Settings_Model::valid_sliders_row ( int row_n ) const
{
  if ( row_n >= 0 ) {
    if ( _sliders.proxies != nullptr ) {
      return ( static_cast< std::size_t > ( row_n ) <
               _sliders.proxies->size () );
    }
  }
  return false;
}

bool
Proxies_Settings_Model::valid_switches_row ( int row_n ) const
{
  if ( row_n >= 0 ) {
    if ( _switches.proxies != nullptr ) {
      return ( static_cast< std::size_t > ( row_n ) <
               _switches.proxies->size () );
    }
  }
  return false;
}

bool
Proxies_Settings_Model::is_l0_sliders ( const QModelIndex & index_n ) const
{
  if ( ( index_n.row () == RER_SLIDERS ) && ( index_n.column () == 0 ) &&
       ( index_n.internalId () == IID_L0_SLIDERS ) ) {
    return true;
  }
  return false;
}

bool
Proxies_Settings_Model::is_l1_slider ( const QModelIndex & index_n ) const
{
  return ( index_n.internalId () == IID_L1_SLIDER ) &&
         ( index_n.column () < num_data_cols ) &&
         ( valid_sliders_row ( index_n.row () ) );
}

bool
Proxies_Settings_Model::is_l0_switches ( const QModelIndex & index_n ) const
{
  if ( ( index_n.row () == RER_SWITCHES ) && ( index_n.column () == 0 ) &&
       ( index_n.internalId () == IID_L0_SWITCHES ) ) {
    return true;
  }
  return false;
}

bool
Proxies_Settings_Model::is_l1_switch ( const QModelIndex & index_n ) const
{
  return ( index_n.internalId () == IID_L1_SWITCH ) &&
         ( index_n.column () < num_data_cols ) &&
         ( valid_switches_row ( index_n.row () ) );
}

QBrush
Proxies_Settings_Model::foreground_brush ( unsigned int style_id_n ) const
{
  const QPalette & pal = _wdg_style_db->palette ( style_id_n );
  return QBrush ( pal.color ( QPalette::WindowText ), Qt::SolidPattern );
}

QModelIndex
Proxies_Settings_Model::index_l0_sliders () const
{
  return createIndex ( RER_SLIDERS, 0, IID_L0_SLIDERS );
}

QModelIndex
Proxies_Settings_Model::index_l0_switches () const
{
  return createIndex ( RER_SWITCHES, 0, IID_L0_SWITCHES );
}

QModelIndex
Proxies_Settings_Model::index ( int row_n,
                                int column_n,
                                const QModelIndex & parent_n ) const
{
  if ( parent_n.isValid () ) {
    if ( is_l0_sliders ( parent_n ) ) {
      if ( valid_sliders_row ( row_n ) ) {
        if ( ( column_n >= 0 ) && ( column_n < num_data_cols ) ) {
          return createIndex ( row_n, column_n, IID_L1_SLIDER );
        }
      }
    } else if ( is_l0_switches ( parent_n ) ) {
      if ( valid_switches_row ( row_n ) ) {
        if ( ( column_n >= 0 ) && ( column_n < num_data_cols ) ) {
          return createIndex ( row_n, column_n, IID_L1_SWITCH );
        }
      }
    }
  } else {
    if ( row_n == RER_SLIDERS ) {
      if ( column_n == 0 ) {
        return index_l0_sliders ();
      }
    } else if ( row_n == RER_SWITCHES ) {
      if ( column_n == 0 ) {
        return index_l0_switches ();
      }
    }
  }

  return QModelIndex ();
}

QModelIndex
Proxies_Settings_Model::parent ( const QModelIndex & index_n ) const
{
  if ( is_l1_slider ( index_n ) ) {
    return createIndex ( RER_SLIDERS, 0, IID_L0_SLIDERS );
  }
  if ( is_l1_switch ( index_n ) ) {
    return createIndex ( RER_SWITCHES, 0, IID_L0_SWITCHES );
  }

  return QModelIndex ();
}

int
Proxies_Settings_Model::rowCount ( const QModelIndex & parent_n ) const
{
  if ( parent_n.isValid () ) {
    if ( is_l0_sliders ( parent_n ) ) {
      if ( _sliders.proxies != nullptr ) {
        return _sliders.proxies->size ();
      }
    } else if ( is_l0_switches ( parent_n ) ) {
      if ( _switches.proxies != nullptr ) {
        return _switches.proxies->size ();
      }
    }
  } else {
    return num_root_rows;
  }
  return 0;
}

int
Proxies_Settings_Model::columnCount ( const QModelIndex & parent_n ) const
{
  if ( parent_n.isValid () ) {
    if ( is_l0_sliders ( parent_n ) ) {
      if ( ( _sliders.proxies != nullptr ) &&
           ( !_sliders.proxies->empty () ) ) {
        return num_data_cols;
      }
    } else if ( is_l0_switches ( parent_n ) ) {
      if ( ( _switches.proxies != nullptr ) &&
           ( !_switches.proxies->empty () ) ) {
        return num_data_cols;
      }
    }
  } else {
    return num_data_cols;
  }
  return 0;
}

QVariant
Proxies_Settings_Model::headerData ( int section_n,
                                     Qt::Orientation orientation_n,
                                     int role_n ) const
{
  if ( orientation_n == Qt::Horizontal ) {
    switch ( role_n ) {
    case Qt::DisplayRole:
      if ( section_n == CI_NAME ) {
        return QVariant ( tr ( "Controls" ) );
      } else if ( section_n == CI_SHOW ) {
        return QVariant ( tr ( "Show" ) );
      }
      break;
    default:
      break;
    }
  }
  return QAbstractItemModel::headerData ( section_n, orientation_n, role_n );
}

Qt::ItemFlags
Proxies_Settings_Model::flags ( const QModelIndex & index_n ) const
{
  if ( is_l0_sliders ( index_n ) || is_l0_switches ( index_n ) ) {
    return Qt::ItemIsEnabled;
  } else if ( is_l1_slider ( index_n ) || is_l1_switch ( index_n ) ) {
    if ( index_n.column () == CI_NAME ) {
      return Qt::ItemIsEnabled;
    } else if ( index_n.column () == CI_SHOW ) {
      return ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
    }
  }

  return Qt::NoItemFlags;
}

QVariant
Proxies_Settings_Model::data ( const QModelIndex & index_n, int role_n ) const
{
  if ( is_l0_sliders ( index_n ) ) {
    // Sliders
    switch ( role_n ) {
    case Qt::DisplayRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant ( tr ( "Sliders" ) );
      }
      break;
    case Qt::FontRole:
      if ( index_n.column () == CI_NAME ) {
        QFont fnt;
        fnt.setBold ( true );
        return QVariant ( fnt );
      }
      break;
    default:
      break;
    }
  } else if ( is_l1_slider ( index_n ) ) {
    // Slider
    switch ( role_n ) {
    case Qt::DisplayRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant (
            _sliders.proxies->at ( index_n.row () )->group_name () );
      }
      break;
    case Qt::ForegroundRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant ( foreground_brush (
            _sliders.proxies->at ( index_n.row () )->style_id () ) );
      }
      break;
    case Qt::CheckStateRole:
      if ( index_n.column () == CI_SHOW ) {
        return QVariant (
            _sliders.model->proxy_sorted_blacklisted ( index_n.row () )
                ? Qt::Unchecked
                : Qt::Checked );
      }
      break;
    default:
      break;
    }
  } else if ( is_l0_switches ( index_n ) ) {
    // Switches
    switch ( role_n ) {
    case Qt::DisplayRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant ( tr ( "Switches" ) );
      }
      break;
    case Qt::FontRole:
      if ( index_n.column () == CI_NAME ) {
        QFont fnt;
        fnt.setBold ( true );
        return QVariant ( fnt );
      }
      break;
    default:
      break;
    }
  } else if ( is_l1_switch ( index_n ) ) {
    // Switch
    switch ( role_n ) {
    case Qt::DisplayRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant (
            _switches.proxies->at ( index_n.row () )->group_name () );
      }
      break;
    case Qt::ForegroundRole:
      if ( index_n.column () == CI_NAME ) {
        return QVariant ( foreground_brush (
            _switches.proxies->at ( index_n.row () )->style_id () ) );
      }
      break;
    case Qt::CheckStateRole:
      if ( index_n.column () == CI_SHOW ) {
        return QVariant (
            _switches.model->proxy_sorted_blacklisted ( index_n.row () )
                ? Qt::Unchecked
                : Qt::Checked );
      }
      break;
    default:
      break;
    }
  }
  return QVariant ();
}

bool
Proxies_Settings_Model::setData ( const QModelIndex & index_n,
                                  const QVariant & value_n,
                                  int role_n )
{
  if ( is_l1_slider ( index_n ) ) {
    if ( role_n == Qt::CheckStateRole ) {
      bool changed = false;
      Qt::CheckState check_state =
          static_cast< Qt::CheckState > ( value_n.toInt () );
      if ( check_state == Qt::Unchecked ) {
        _sliders.model->proxy_sorted_set_blacklisted ( index_n.row (), true );
        changed = true;
      } else if ( check_state == Qt::Checked ) {
        _sliders.model->proxy_sorted_set_blacklisted ( index_n.row (), false );
        changed = true;
      }
      if ( changed ) {
        Q_EMIT dataChanged ( index_n, index_n );
        Q_EMIT sig_visibility_changed ();
      }
    }
  } else if ( is_l1_switch ( index_n ) ) {
    if ( role_n == Qt::CheckStateRole ) {
      bool changed = false;
      Qt::CheckState check_state =
          static_cast< Qt::CheckState > ( value_n.toInt () );
      if ( check_state == Qt::Unchecked ) {
        _switches.model->proxy_sorted_set_blacklisted ( index_n.row (), true );
        changed = true;
      } else if ( check_state == Qt::Checked ) {
        _switches.model->proxy_sorted_set_blacklisted ( index_n.row (), false );
        changed = true;
      }
      if ( changed ) {
        Q_EMIT dataChanged ( index_n, index_n );
        Q_EMIT sig_visibility_changed ();
      }
    }
  }
  return QAbstractItemModel::setData ( index_n, value_n, role_n );
}

void
Proxies_Settings_Model::rebuild_sliders_begin ()
{
  if ( _sliders.proxies != nullptr ) {
    if ( !_sliders.proxies->empty () ) {
      beginRemoveRows ( index_l0_sliders (), 0, _sliders.proxies->size () - 1 );
      _sliders.proxies = nullptr;
      endRemoveRows ();
    } else {
      _sliders.proxies = nullptr;
    }
  }
}

void
Proxies_Settings_Model::rebuild_sliders_end ()
{
  if ( _sliders.model != nullptr ) {
    const auto & proxies = _sliders.model->proxies_sorted ();
    if ( !proxies.empty () ) {
      beginInsertRows ( index_l0_sliders (), 0, proxies.size () - 1 );
      _sliders.proxies = &proxies;
      endInsertRows ();
    }
  }
}

void
Proxies_Settings_Model::rebuild_switches_begin ()
{
  if ( _switches.proxies != nullptr ) {
    if ( !_switches.proxies->empty () ) {
      beginRemoveRows (
          index_l0_switches (), 0, _switches.proxies->size () - 1 );
      _switches.proxies = nullptr;
      endRemoveRows ();
    } else {
      _switches.proxies = nullptr;
    }
  }
}

void
Proxies_Settings_Model::rebuild_switches_end ()
{
  if ( _switches.model != nullptr ) {
    const auto & proxies = _switches.model->proxies_sorted ();
    if ( !proxies.empty () ) {
      beginInsertRows ( index_l0_switches (), 0, proxies.size () - 1 );
      _switches.proxies = &proxies;
      endInsertRows ();
    }
  }
}

} // namespace MWdg::Mixer
