/* massXpert - the true massist's program.
   --------------------------------------
   Copyright(C) 2006,2007 Filippo Rusconi

   http://www.massxpert.org/massXpert

   This file is part of the massXpert project.

   The massxpert project is the successor to the "GNU polyxmass"
   project that is an official GNU project package(see
   www.gnu.org). The massXpert project is not endorsed by the GNU
   project, although it is released ---in its entirety--- under the
   GNU General Public License. A huge part of the code in massXpert
   is actually a C++ rewrite of code in GNU polyxmass. As such
   massXpert was started at the Centre National de la Recherche
   Scientifique(FRANCE), that granted me the formal authorization to
   publish it under this Free Software License.

   This software is free software; you can redistribute it and/or
   modify it under the terms of the GNU  General Public
   License version 3, as published by the Free Software Foundation.
   

   This software 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 software; if not, write to the

   Free Software Foundation, Inc.,

   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/////////////////////// Qt includes


/////////////////////// Local includes
#include "cleaveOligomerTableViewModel.hpp"
#include "application.hpp"


namespace massXpert
{


  CleaveOligomerTableViewModel::CleaveOligomerTableViewModel
  (OligomerList *oligomerList, QObject *parent)
    : QAbstractTableModel(parent)
  {
    if(!oligomerList)
      qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
    
    mp_oligomerList = oligomerList;
    
    if(!parent)
      qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);

    mp_parentDlg = static_cast<CleavageDlg *>(parent);

    reset();
  }
  

  CleaveOligomerTableViewModel::~CleaveOligomerTableViewModel()
  {
    
  }

  
  const OligomerList *
  CleaveOligomerTableViewModel::oligomerList()
  {
    return mp_oligomerList;
  }
  
  
  CleavageDlg *
  CleaveOligomerTableViewModel::parentDlg()
  {
    return mp_parentDlg;
  }
  
    
  void 
  CleaveOligomerTableViewModel::setTableView
  (CleaveOligomerTableView *tableView)
  {
    if(!tableView)
      qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
    
    mp_tableView = tableView;
  }
  
  
  CleaveOligomerTableView *
  CleaveOligomerTableViewModel::tableView()
  {
    return mp_tableView;
  }
  
  
  int 
  CleaveOligomerTableViewModel::rowCount(const QModelIndex &parent) const
  {
    Q_UNUSED(parent);
    
    return mp_oligomerList->size();
  }
  

  int 
  CleaveOligomerTableViewModel::columnCount(const QModelIndex &parent) const
  {
    Q_UNUSED(parent);
    
    return CLEAVE_OLIGO_TOTAL_COLUMNS;
  }
  

  QVariant 
  CleaveOligomerTableViewModel::headerData(int section, 
                                           Qt::Orientation orientation, 
                                           int role) const
  {
    if(role != Qt::DisplayRole)
      return QVariant();
    
    if(orientation == Qt::Vertical)
      {
        // Return the row number.
        QString valueString;
        valueString.setNum(section);
      }
    else if(orientation == Qt::Horizontal)
      {
        // Return the header of the column.
        switch(section) 
          {
          case CLEAVE_OLIGO_PARTIAL_COLUMN:
            return tr("Part. cleav.");
          case CLEAVE_OLIGO_NAME_COLUMN:
            return tr("Name");
          case CLEAVE_OLIGO_COORDINATES_COLUMN:
            return tr("Coords");
          case CLEAVE_OLIGO_MONO_COLUMN:
            return tr("Mono");
          case CLEAVE_OLIGO_AVG_COLUMN:
            return tr("Avg");
          case CLEAVE_OLIGO_CHARGE_COLUMN:
            return tr("Charge");
          case CLEAVE_OLIGO_MODIF_COLUMN:
            return tr("Modif?");
          default :
            qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
          }
      }
    // Should never get here.
    return QVariant();
  }
  

  QVariant 
  CleaveOligomerTableViewModel::data
  (const QModelIndex &index, int role) const
  {
    if (!index.isValid())
      return QVariant();
    
    if(role == Qt::TextAlignmentRole)
      {
        return int(Qt::AlignRight | Qt::AlignVCenter);
      }
    else if(role == Qt::DisplayRole)
      {
        Application *application = static_cast<Application *>(qApp);
        QLocale locale = application->locale();

        int row = index.row();
        int column = index.column();
        
        // Let's get the data for the right column and the right
        // row. Let's find the row first, so that we get to the proper
        // oligomer.
        
        CleaveOligomer *oligomer =
          static_cast<CleaveOligomer *>(mp_oligomerList->at(row));
        
        // Now see what's the column that is asked for. Prepare a
        // string that we'll feed with the right data before returning
        // it as a QVariant.
        
        QString valueString;
        
        if(column == CLEAVE_OLIGO_PARTIAL_COLUMN)
          {
            int partialCleavage = oligomer->partialCleavage();
            
            valueString.setNum(partialCleavage);
          }
        else if(column == CLEAVE_OLIGO_NAME_COLUMN)
          {
            valueString = oligomer->name();
          }
        else if(column == CLEAVE_OLIGO_COORDINATES_COLUMN)
          {
            int oligomerCount =
              static_cast<CoordinateList *>(oligomer)->size();
            
            for(int jter = 0; jter < oligomerCount; ++jter)
              {
                Coordinates *coordinates = 
                  static_cast<CoordinateList *>(oligomer)->at(jter);
                
                valueString += QString("[%1-%2]")
                  .arg(coordinates->start() + 1)
                  .arg(coordinates->end() + 1);
              }
          }
        else if(column == CLEAVE_OLIGO_MONO_COLUMN)
          {
            valueString = oligomer->mono(locale, MXP_OLIGOMER_DEC_PLACES);
          }
        else if(column == CLEAVE_OLIGO_AVG_COLUMN)
          {
            valueString = oligomer->avg(locale, MXP_OLIGOMER_DEC_PLACES);
          }
        else if(column == CLEAVE_OLIGO_CHARGE_COLUMN)
          {
            int charge = oligomer->charge();
            
            valueString.setNum(charge);
          }
        else if(column == CLEAVE_OLIGO_MODIF_COLUMN)
          {
            if(oligomer->isModified())
              valueString = "True";
            else
              valueString = "False";
          }
        else 
          {
            qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
          }

        return valueString;
      }
    // End of 
    // else if(role == Qt::DisplayRole)
    
    return QVariant();
  }
  
  int
  CleaveOligomerTableViewModel::addOligomers(const OligomerList &oligomerList)
  {
    // We receive a list of oligomers which we are asked to add to the
    // list of oligomers that we actually do not own, since they are
    // owned by the CleavageDlg instance that is the "owner" of this
    // model. But since we want to add the oligomers to the list of
    // oligomers belonging to the CleavageDlg instance in such a way
    // that the tableView takes them into account, we have to do that
    // addition work here.

    // Note that we are acutally *transferring* all the oligomers from
    // the oligomerList to this model's mp_oligomerList.

    int oligomerCount = mp_oligomerList->size();

    // qDebug() << __FILE__ << __LINE__
    //          << "model oligomers:" << oligomerCount;
    
    int oligomersToAdd = oligomerList.size();

    // qDebug() << __FILE__ << __LINE__
    //          << "oligomers to add:" << oligomersToAdd;

    int addedOligomerCount = 0;
    
    // We have to let know the model that we are going to modify the
    // list of oligomers and thus the number of rows in the table
    // view. We will append the oligomers to the preexisting ones,
    // which means we are going to have our first appended oligomer at
    // index = oligomerCount.

    beginInsertRows(QModelIndex(), 
                    oligomerCount, 
                    (oligomerCount + oligomersToAdd -1));
    
    for(int iter = 0 ; iter < oligomersToAdd ; ++iter)
      {
        CleaveOligomer *oligomer = 
          static_cast<CleaveOligomer *>(oligomerList.at(iter));
        
        mp_oligomerList->append(oligomer);
        
        ++addedOligomerCount;
      }
    
    endInsertRows();

    return addedOligomerCount;
  }
  
  
  
  int
  CleaveOligomerTableViewModel::removeOligomers(int firstIndex, int lastIndex)
  {
    // We are asked to remove the oligomers [firstIndex--lastIndex].

    // firstIndex has to be >= 0 and < mp_oligomerList->size(). If
    // lastIndex is -1, then remove all oligomers in range
    // [firstIndex--last oligomer].

    // We are asked to remove the oligomers from the list of oligomers
    // that we actually do not own, since they are owned by the
    // CleavageDlg instance that is the "owner" of this model. But
    // since we want to remove the oligomers from the list of
    // oligomers belonging to the CleavageDlg instance in such a way
    // that the tableView takes them into account, we have to do that
    // removal work here.

    int oligomerCount = mp_oligomerList->size();

    if(!oligomerCount)
      return 0;
    
    if(firstIndex < 0 || firstIndex >= oligomerCount)
      {
        // qDebug() << __FILE__ << __LINE__
        //          << "firstIndex:" << firstIndex
        //          << "lastIndex:" << lastIndex;
        
        qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
      }
    
    int firstIdx = firstIndex;

    // lastIndex can be < 0 (that is -1) if the oligomer to remove
    // must go up to the last oligomer in the list.
    if(lastIndex < -1 || lastIndex >= oligomerCount)
      {
        // qDebug() << __FILE__ << __LINE__
        //          << "firstIndex:" << firstIndex
        //          << "lastIndex:" << lastIndex;
        
        qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
      }
    
    int lastIdx = 0;
    
    if(lastIndex == -1)
      lastIdx = (oligomerCount - 1);
    else
      lastIdx = lastIndex;
    
    beginRemoveRows(QModelIndex(), firstIdx, lastIdx);

    int removedOligomerCount = 0;

    int iter = lastIdx;
    
    while(iter >= firstIdx)
      {
        CleaveOligomer *oligomer = 
          static_cast<CleaveOligomer *>(mp_oligomerList->takeAt(iter));
        
        delete oligomer;
        
        ++removedOligomerCount;
        
        --iter;
      }
    
    endRemoveRows();

    return removedOligomerCount;
  }
  

} // namespace massXpert
