/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


/////////////////////// Qt includes
#include <QDebug>


/////////////////////// Local includes
#include "CleaveOligomerTableViewModel.hpp"
#include "CleaveOligomerTableViewSortProxyModel.hpp"


namespace MsXpS
{

namespace massxpert
{


  CleaveOligomerTableViewSortProxyModel::CleaveOligomerTableViewSortProxyModel(
    QObject *parent)
    : QSortFilterProxyModel(parent)
  {
  }


  CleaveOligomerTableViewSortProxyModel::
    ~CleaveOligomerTableViewSortProxyModel()
  {
  }


  void
  CleaveOligomerTableViewSortProxyModel::setPartialFilter(int value)
  {
    m_partialFilter = value;
  }


  void
  CleaveOligomerTableViewSortProxyModel::setMonoFilter(double value)
  {
    m_monoFilter = value;
  }


  void
  CleaveOligomerTableViewSortProxyModel::setAvgFilter(double value)
  {
    m_avgFilter = value;
  }


  void
  CleaveOligomerTableViewSortProxyModel::setTolerance(double value)
  {
    m_tolerance = value;
  }


  void
  CleaveOligomerTableViewSortProxyModel::setChargeFilter(int value)
  {
    m_chargeFilter = value;
  }


  bool
  CleaveOligomerTableViewSortProxyModel::lessThan(
    const QModelIndex &left, const QModelIndex &right) const
  {
    QVariant leftData  = sourceModel()->data(left);
    QVariant rightData = sourceModel()->data(right);

    if(leftData.typeId() == QMetaType::Int)
      {
        // The Partial column

        int leftValue  = leftData.toInt();
        int rightValue = rightData.toInt();

        return (leftValue < rightValue);
      }
    if(leftData.typeId() == QMetaType::Bool)
      {
        // The libXpertMass::Modif column

        int leftValue  = leftData.toInt();
        int rightValue = rightData.toInt();

        return (leftValue < rightValue);
      }
    else if(leftData.typeId() == QMetaType::QString &&
            (left.column() == CLEAVE_OLIGO_MONO_COLUMN ||
             left.column() == CLEAVE_OLIGO_AVG_COLUMN))
      {
        bool ok          = false;
        double leftValue = 0;
        leftValue        = leftData.toString().toDouble(&ok);

        // 	qDebug() << __FILE__ << __LINE__
        // 		 << leftData.toString() << "ok:" << ok;

        Q_ASSERT(ok);

        double rightValue = 0;
        rightValue        = rightData.toString().toDouble(&ok);

        // 	qDebug() << __FILE__ << __LINE__
        // 		 << rightData.toString() << "ok:" << ok;

        Q_ASSERT(ok);

        return (leftValue < rightValue);
      }

    if(leftData.typeId() == QMetaType::QString)
      {
        QString leftString  = leftData.toString();
        QString rightString = rightData.toString();

        if(!leftString.isEmpty() && leftString.at(0) == '[')
          return sortCoordinates(leftString, rightString);
        else if(!leftString.isEmpty() && leftString.contains('#'))
          return sortName(leftString, rightString);
        else
          return (QString::localeAwareCompare(leftString, rightString) < 0);
      }

    return true;
  }


  bool
  CleaveOligomerTableViewSortProxyModel::sortCoordinates(QString left,
                                                         QString right) const
  {
    QString local = left;

    local.remove(0, 1);
    local.remove(local.size() - 1, 1);

    int dash = local.indexOf('-');

    QString leftStartStr = local.left(dash);

    bool ok          = false;
    int leftStartInt = leftStartStr.toInt(&ok);

    local.remove(0, dash + 1);

    QString leftEndStr = local;

    ok             = false;
    int leftEndInt = leftEndStr.toInt(&ok);

    //    qDebug() << "left coordinates" << leftStartInt << "--" << leftEndInt;

    local = right;

    local.remove(0, 1);
    local.remove(local.size() - 1, 1);

    dash = local.indexOf('-');

    QString rightStartStr = local.left(dash);

    ok                = false;
    int rightStartInt = rightStartStr.toInt(&ok);

    local.remove(0, dash + 1);

    QString rightEndStr = local;

    ok              = false;
    int rightEndInt = rightEndStr.toInt(&ok);

    //    qDebug() << "right coordinates" << rightStartInt << "--" <<
    //    rightEndInt;


    if(leftStartInt < rightStartInt)
      return true;

    if(leftEndInt < rightEndInt)
      return true;

    return false;
  }


  bool
  CleaveOligomerTableViewSortProxyModel::sortName(QString left,
                                                  QString right) const
  {
    // The format is this way:
    //
    // 0#29#z=2
    //
    // This indicates: 0 partial cleavage, oligomer number 29, with
    // charge z=2.


    // left QString.
    //
    QString local = left;

    QStringList leftList = local.split("#", Qt::SkipEmptyParts);

    bool ok            = false;
    int leftPartialInt = leftList.at(0).toInt(&ok);

    ok               = false;
    int leftOligoInt = leftList.at(1).toInt(&ok);

    QString leftChargeString = leftList.at(2).section('=', 1, 1);

    ok                = false;
    int leftChargeInt = leftChargeString.toInt(&ok);


    // right QString.
    //
    local = right;

    QStringList rightList = local.split("#", Qt::SkipEmptyParts);

    ok                  = false;
    int rightPartialInt = rightList.at(0).toInt(&ok);

    ok                = false;
    int rightOligoInt = rightList.at(1).toInt(&ok);

    QString rightChargeString = rightList.at(2).section('=', 1, 1);

    ok                 = false;
    int rightChargeInt = rightChargeString.toInt(&ok);

    //     qDebug() << leftPartialInt << "#" << leftOligoInt
    // 	      << "#" << leftChargeInt
    // 	      << "  /  "
    // 	      << rightPartialInt << "#" << rightOligoInt
    // 	      << "#" << rightChargeInt;

    // Now do the comparison work.
    //
    if(leftPartialInt < rightPartialInt)
      {
        return true;
      }
    else if(leftPartialInt == rightPartialInt)
      {
        if(leftOligoInt < rightOligoInt)
          {
            return true;
          }
        else if(leftOligoInt == rightOligoInt)
          {
            if(leftChargeInt < rightChargeInt)
              return true;
          }
      }

    return false;
  }


  bool
  CleaveOligomerTableViewSortProxyModel::filterAcceptsRow(
    int sourceRow, const QModelIndex &sourceParent) const
  {
    if(filterKeyColumn() == CLEAVE_OLIGO_PARTIAL_COLUMN)
      {
        QModelIndex index = sourceModel()->index(
          sourceRow, CLEAVE_OLIGO_PARTIAL_COLUMN, sourceParent);

        int partial = sourceModel()->data(index).toInt();

        if(m_partialFilter == partial)
          return true;
        else
          return false;
      }
    else if(filterKeyColumn() == CLEAVE_OLIGO_MONO_COLUMN)
      {
        QModelIndex index = sourceModel()->index(
          sourceRow, CLEAVE_OLIGO_MONO_COLUMN, sourceParent);

        bool ok = false;

        QVariant data = sourceModel()->data(index);
        // FIXME: go straight to double with no string intermediate.
        double mass = data.toString().toDouble(&ok);
        Q_ASSERT(ok);

        double left  = m_monoFilter - m_tolerance;
        double right = m_monoFilter + m_tolerance;

        if(left <= mass && mass <= right)
          return true;
        else
          return false;
      }
    else if(filterKeyColumn() == CLEAVE_OLIGO_AVG_COLUMN)
      {
        QModelIndex index = sourceModel()->index(
          sourceRow, CLEAVE_OLIGO_AVG_COLUMN, sourceParent);

        bool ok = false;

        QVariant data = sourceModel()->data(index);

        double mass = data.toString().toDouble(&ok);
        Q_ASSERT(ok);

        double left  = m_avgFilter - m_tolerance;
        double right = m_avgFilter + m_tolerance;

        if(left <= mass && mass <= right)
          return true;
        else
          return false;
      }
    else if(filterKeyColumn() == CLEAVE_OLIGO_CHARGE_COLUMN)
      {
        QModelIndex index = sourceModel()->index(
          sourceRow, CLEAVE_OLIGO_CHARGE_COLUMN, sourceParent);
        int charge = sourceModel()->data(index).toInt();

        if(m_chargeFilter == charge)
          return true;
        else
          return false;
      }

    return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
  }


  void
  CleaveOligomerTableViewSortProxyModel::applyNewFilter()
  {
    invalidateFilter();
  }

} // namespace massxpert

} // namespace MsXpS
