
/*******************************************************************************
 * Copyright (c) 2019 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *    Thomas Renne <thomas.renne@u-psud.fr>. - initial API and
 *implementation
 ******************************************************************************/
#include <QDebug>

#include "alignmentgroupmenu.h"
#include "../../../gui/lists/ms_identification_run_list_view/msidentificationlistwindow.h"
#include <QInputDialog>
#include <pappsomspp/core/pappsoexception.h>


AlignmentGroupsQMenu::AlignmentGroupsQMenu(MsIdentificationListWindow *parent,
                                           Project *project)
{
  mp_msIdListWindow         = parent;
  mp_project                = project;
  m_msrunAlignmentGroupList = project->getMsRunAlignmentGroupList();

  this->setTitle("Context menu");
  createGroupsSubMenu();
  this->addMenu(mp_subMenuGroup);
  this->addSeparator();

  QIcon *add_reference_icon =
    new QIcon(":/icons/resources/icons/icon_reference.svg");
  mp_addReference = new QAction(*add_reference_icon, tr("&As msRun reference"));
  this->addAction(mp_addReference);

  QIcon *remove_reference_icon =
    new QIcon(":/icons/resources/icons/icon_remove_reference.svg");
  mp_removeReference =
    new QAction(*remove_reference_icon, tr("&Remove reference"));
  this->addAction(mp_removeReference);

  mp_ungroup = new QAction(
    QIcon(":/icons/resources/icons/apache/unicons/icon_ungroup.svg"),
    tr("&Ungroup"));
  this->addAction(mp_ungroup);

  //   m_selectedIndexesChecks vector contains multiple verifications
  //   0: true if all the selected are grouped
  //   1: true if at least one is grouped
  //   2: true if only one is grouped
  //   3: true if the selected is a reference
  for(size_t i = 0; i < 4; i++)
    {
      m_selectedIndexesChecks.push_back(false);
    }

  connect(this,
          &AlignmentGroupsQMenu::triggered,
          this,
          &AlignmentGroupsQMenu::actionTriggered);
  connect(this,
          &AlignmentGroupsQMenu::aboutToShow,
          this,
          &AlignmentGroupsQMenu::disableActionsFollowingSelection);
}

AlignmentGroupsQMenu::~AlignmentGroupsQMenu()
{
  if(mp_subMenuGroup != nullptr)
    {
      delete mp_subMenuGroup;
    }
}

void
AlignmentGroupsQMenu::createGroupsSubMenu()
{
  mp_subMenuGroup = new QMenu(tr("&Group"), this);
  mp_subMenuGroup->setIcon(
    QIcon(":/icons/resources/icons/apache/unicons/icon_group.svg"));

  QIcon *icon = new QIcon(":/icons/resources/icons/mit/jamicons/icon_plus.svg");
  mp_newGroup = new QAction(*icon, tr("&New Group"));
  mp_subMenuGroup->addAction(mp_newGroup);
  mp_subMenuGroup->addSeparator();
  foreach(MsRunAlignmentGroupSp group, mp_project->getMsRunAlignmentGroupList())
    {
      mp_subMenuGroup->addAction(group->getMsRunAlignmentGroupName());
    }
}

void
AlignmentGroupsQMenu::disableActionsFollowingSelection()
{
  checkGroupsOnSelectedIndexes();

  if(m_selectedIndexesChecks[0] && m_selectedIndexesChecks[2])
    {
      mp_addReference->setEnabled(true);
    }
  else
    {
      mp_addReference->setEnabled(false);
    }

  if(m_selectedIndexesChecks[1])
    {
      mp_ungroup->setEnabled(true);
    }
  else
    {
      mp_ungroup->setEnabled(false);
    }
  if(m_selectedIndexesChecks[2] && m_selectedIndexesChecks[3])
    {
      mp_removeReference->setEnabled(true);
    }
  else
    {
      mp_removeReference->setEnabled(false);
    }
}


void
AlignmentGroupsQMenu::actionTriggered(QAction *action_triggered)
{
  if(action_triggered == mp_ungroup)
    {
      qDebug() << "ungroup";
      mp_msIdListWindow->setAlignmentGroup(nullptr);
    }
  else if(action_triggered == mp_newGroup)
    {
      qDebug() << "new group";
      createNewAlignmentGroup();
    }
  else if(action_triggered == mp_addReference)
    {
      qDebug() << "Add Reference";
      handleMsRunReference(true);
    }
  else if(action_triggered == mp_removeReference)
    {
      qDebug() << "Remove reference";
      handleMsRunReference(false);
    }
  else
    {
      qDebug() << "Existing Group ";

      foreach(MsRunAlignmentGroupSp existing_group,
              mp_project->getMsRunAlignmentGroupList())
        {
          if(existing_group.get()->getMsRunAlignmentGroupName() ==
             action_triggered->text())
            {
              mp_msIdListWindow->setAlignmentGroup(existing_group);
            }
        }
    }
}

int
AlignmentGroupsQMenu::getMsRunAlignmentGroupPosition(QString new_name)
{
  int group_name_position = -1;
  auto it                 = std::find_if(m_msrunAlignmentGroupList.begin(),
                         m_msrunAlignmentGroupList.end(),
                         [&new_name](const MsRunAlignmentGroupSp &obj) {
                           return obj->getMsRunAlignmentGroupName() == new_name;
                         });

  if(it != m_msrunAlignmentGroupList.end())
    {
      group_name_position =
        std::distance(m_msrunAlignmentGroupList.begin(), it);
    }

  return group_name_position;
}

void
AlignmentGroupsQMenu::checkGroupsOnSelectedIndexes()
{
  for(size_t i = 0; i < 4; i++)
    {
      m_selectedIndexesChecks[i] = false;
    }
  int count_grouped = 0;
  foreach(QModelIndex index, mp_msIdListWindow->getSelectedIndexes())
    {
      int position = mp_msIdListWindow->getMsIdentificationProxyModel()
                       ->mapToSource(index)
                       .row();

      MsRunSp ms_run = mp_msIdListWindow->getMsIdentificationModel()
                         ->getIdentificationDataSourceSpList()
                         .at(position)
                         ->getMsRunSp();

      if(ms_run->getAlignmentGroup() != nullptr)
        {
          count_grouped++;
          if(ms_run->getAlignmentGroup()->getMsRunReference() == ms_run)
            {
              m_selectedIndexesChecks[3] = true;
            }
        }
    }
  if(count_grouped == mp_msIdListWindow->getSelectedIndexes().size())
    {
      m_selectedIndexesChecks[0] = true;
      m_selectedIndexesChecks[1] = true;
    }
  else if(count_grouped > 0)
    {
      m_selectedIndexesChecks[1] = true;
    }

  if(count_grouped == (mp_msIdListWindow->getSelectedIndexes().size() == 1))
    {
      m_selectedIndexesChecks[2] = true;
    }
}

void
AlignmentGroupsQMenu::createNewAlignmentGroup()
{
  bool ok_clicked;
  QString value = QInputDialog::getText(this,
                                        tr("Create Group"),
                                        tr("New Group Name:"),
                                        QLineEdit::Normal,
                                        "",
                                        &ok_clicked);
  if(ok_clicked)
    {
      qDebug() << value;
      int msrun_alignment_group_position =
        getMsRunAlignmentGroupPosition(value);
      if(msrun_alignment_group_position == -1)
        {
          QRegularExpression no_space_name_regex("(.*)\\s(.*)");
          if(no_space_name_regex.match(value).hasMatch())
            {
              throw pappso::PappsoException(
                tr("Error : The alignment group name cannot have whitespace"));
            }
          else
            {
              mp_subMenuGroup->addAction(value);
              MsRunAlignmentGroupSp new_alignment_group =
                std::make_shared<MsRunAlignmentGroup>(mp_project, value);
              mp_project->addMsRunAlignmentGroupToList(new_alignment_group);
              mp_msIdListWindow->setAlignmentGroup(new_alignment_group);
            }
        }
      else
        {
          mp_msIdListWindow->setAlignmentGroup(
            m_msrunAlignmentGroupList.at(msrun_alignment_group_position));
        }
    }
}

void
AlignmentGroupsQMenu::handleMsRunReference(bool new_reference)
{
  QModelIndex index = mp_msIdListWindow->getSelectedIndexes()[0];
  int position      = mp_msIdListWindow->getMsIdentificationProxyModel()
                   ->mapToSource(index)
                   .row();

  MsRunSp ms_run = mp_msIdListWindow->getMsIdentificationModel()
                     ->getIdentificationDataSourceSpList()
                     .at(position)
                     ->getMsRunSp();

  if(new_reference == true)
    {
      ms_run->getAlignmentGroup()->setMsRunReference(ms_run);
    }
  else
    {
      ms_run->getAlignmentGroup()->setMsRunReference(nullptr);
    }
}
