/**
 * \file core/labelingmethod.cpp
 * \date 20/5/2017
 * \author Olivier Langella
 * \brief labeling method
 */

/*******************************************************************************
 * Copyright (c) 2017 Olivier Langella <olivier.langella@u-psud.fr>.
 *
 * This file is part of XTPcpp.
 *
 *     XTPcpp 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.
 *
 *     XTPcpp 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 XTPcpp.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "labelingmethod.h"
#include <pappsomspp/pappsoexception.h>
#include <QFile>
#include <QDomDocument>

LabelingMethod::LabelingMethod(const QString &method_id) : _xml_id(method_id)
{

  qDebug() << "LabelingMethod::LabelingMethod begin " << _xml_id;
  QDomDocument *dom = new QDomDocument("labeling_methods");
  QFile xml_doc(":/labeling/resources/catalog_label.xml");
  if(!xml_doc.open(QIODevice::ReadOnly))
    {
      // error
      throw pappso::PappsoException(
        QObject::tr("error opening catalog_label resource file"));
    }
  if(!dom->setContent(&xml_doc))
    {
      xml_doc.close();
      throw pappso::PappsoException(
        QObject::tr("error opening catalog_label xml content"));
    }

  QDomNode child = dom->documentElement().firstChild();
  while(!child.isNull())
    {
      if(child.toElement().tagName() == "isotope_label_list")
        {
          if(child.toElement().attribute("id") == _xml_id)
            {
              parseMethod(child);
            }
        }
      child = child.nextSibling();
    }

  xml_doc.close();
  delete dom;
}


const Label *
LabelingMethod::getLabel(
  const std::list<pappso::AaModificationP> &modification_set) const
{
  for(Label *p_label : _label_list)
    {

      if(p_label->containsAaModificationP(modification_set))
        {
          return p_label;
        }
    }
  auto p_empty_label = getEmptyLabel();
  if(p_empty_label != nullptr)
    {
      return p_empty_label;
    }
  return nullptr;
}

const QString &
LabelingMethod::getXmlId() const
{
  return _xml_id;
}
LabelingMethod::LabelingMethod(const LabelingMethod &other)
  : _xml_id(other._xml_id)
{
  for(Label *p_label : other._label_list)
    {
      _label_list.push_back(new Label(*p_label));
    }
}
LabelingMethod::~LabelingMethod()
{
  for(Label *p_label : _label_list)
    {
      delete p_label;
    }
}

LabelingMethodSp
LabelingMethod::makeLabelingMethodSp() const
{
  return std::make_shared<LabelingMethod>(*this);
}
void
LabelingMethod::parseMethod(QDomNode &method_node)
{
  QDomNode child = method_node.firstChild();
  while(!child.isNull())
    {
      if(child.toElement().tagName() == "isotope_label")
        {
          _label_list.push_back(new Label(child));
        }
      child = child.nextSibling();
    }
}

void
LabelingMethod::writeMassChroqMl(QXmlStreamWriter *output_stream) const
{
  //<isotope_label_list>
  output_stream->writeStartElement("isotope_label_list");
  output_stream->writeComment(getXmlId());
  /*
    <isotope_label id="iso1">
      <mod at="Nter" value="28.0" acc="MOD:00429"/>
      <mod at="K" value="28.0" acc="MOD:00429"/>
    </isotope_label>
    <isotope_label id="iso2">
      <mod at="Nter" value="32.0" />
      <mod at="K" value="32.0" />
    </isotope_label>*/
  for(Label *p_label : _label_list)
    {
      p_label->writeMassChroqMl(output_stream);
    }
  //</isotope_label_list>
  output_stream->writeEndElement();
}

const std::vector<Label *> &
LabelingMethod::getLabelList() const
{
  return _label_list;
}

const Label *
LabelingMethod::getEmptyLabel() const
{
  for(const Label *p_label : _label_list)
    {
      if(p_label->isEmpty())
        return p_label;
    }
  return nullptr;
}
