/**
 * \file /files/tandemparametersfile.cpp
 * \date 19/9/2017
 * \author Olivier Langella
 * \brief handles X!Tandem parameters file (presets)
 */

/*******************************************************************************
 * 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 "tandemparametersfile.h"
#include <QXmlSimpleReader>
#include <QXmlStreamWriter>
#include <QDir>
#include <pappsomspp/pappsoexception.h>
#include <pappsomspp/exception/exceptionnotfound.h>


TandemParametersFile::TandemParametersFile(const QString &fasta_source)
  : _param_source(fasta_source)
{

  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
           << fasta_source;
}
TandemParametersFile::TandemParametersFile(const QFileInfo &fasta_source)
  : _param_source(fasta_source)
{
}
TandemParametersFile::TandemParametersFile(const TandemParametersFile &other)
  : _param_source(other._param_source)
{
}
TandemParametersFile::~TandemParametersFile()
{
}
const QString
TandemParametersFile::getMethodName()
{
  if(m_fileType == ParamFileType::empty)
    {
      TandemParameters parameters;
      XtandemParamSaxHandler *parser = new XtandemParamSaxHandler(&parameters);
      setTandemParametersFileType(parser);
    }
  // qDebug() << (std::int8_t)m_fileType;
  if(m_fileType == ParamFileType::preset)
    {
      return _param_source.baseName();
    }
  else if(m_fileType == ParamFileType::result)
    {
      return m_presetFileInfo.baseName();
    }
  else if(m_fileType == ParamFileType::not_xtandem)
    {
      throw pappso::PappsoException(
        QObject::tr("error : %1 is not a TandemParameters file\n")
          .arg(_param_source.fileName()));
    }
  else // m_fileType == ParamFileType::no_file
    {
      throw pappso::PappsoException(QObject::tr("error : %1 Doesn't exist'\n")
                                      .arg(_param_source.fileName()));
    }
}

const QString
TandemParametersFile::getFilename() const
{
  return _param_source.fileName();
}

const QDir
TandemParametersFile::getAbsoluteDir() const
{
  return _param_source.absoluteDir();
}
const QString
TandemParametersFile::getAbsoluteFilePath() const
{
  return _param_source.absoluteFilePath();
}
bool
TandemParametersFile::exists() const
{
  return _param_source.exists();
}
void
TandemParametersFile::setDirectory(const QDir &directory)
{
  QFileInfo new_dir(QString("%1/%2")
                      .arg(directory.absolutePath())
                      .arg(_param_source.fileName()));
  _param_source = new_dir;
}

void
TandemParametersFile::setTandemParameters(const TandemParameters &parameters)
{

  QFile xml_file(_param_source.absoluteFilePath());
  QFile new_file(QString("%1/%2.xml")
                   .arg(_param_source.absolutePath())
                   .arg(parameters.getMethodName()));
  try
    {
      if(_param_source.absoluteFilePath() !=
         QFileInfo(new_file).absoluteFilePath())
        {
          if(xml_file.exists())
            {
              // move if renamed
              xml_file.remove();
            }
        }
      QXmlStreamWriter *p_out;
      if(new_file.open(QIODevice::WriteOnly))
        {

          _param_source.setFile(new_file);
          p_out = new QXmlStreamWriter();
          p_out->setDevice(&new_file);
          writeXmlParametersFile(p_out, parameters);
          new_file.close();
          delete p_out;
        }
      else
        {
          throw pappso::PappsoException(
            QObject::tr(
              "error : cannot open the XML X!Tandem parameter file : %1\n")
              .arg(new_file.fileName()));
        }
    }

  catch(pappso::PappsoException &error_pappso)
    {
      throw pappso::PappsoException(
        QObject::tr("error writing tandem preset file %1 : \n%2")
          .arg(QFileInfo(new_file).absoluteFilePath())
          .arg(error_pappso.qwhat()));
    }
  catch(std::exception &error)
    {
      throw pappso::PappsoException(
        QObject::tr("error writing tandem preset file %1 : \n%2")
          .arg(QFileInfo(new_file).absoluteFilePath())
          .arg(error.what()));
    }
}

TandemParameters
TandemParametersFile::getTandemParameters()
{

  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
  TandemParameters parameters;
  XtandemParamSaxHandler *parser = new XtandemParamSaxHandler(&parameters);

  QXmlSimpleReader simplereader;
  simplereader.setContentHandler(parser);
  simplereader.setErrorHandler(parser);
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
           << _param_source.absoluteFilePath() << "'";


  QFile qfile(_param_source.absoluteFilePath());
  QXmlInputSource xmlInputSource(&qfile);

  if(simplereader.parse(xmlInputSource))
    {
      m_isTandemParameterFile = parser->isTandemParameter();
      qDebug() << m_isTandemParameterFile;
      // parameters.getValue("spectrum, parent monoisotopic mass error units");
      qfile.close();
    }
  else
    {
      qDebug();
      m_isTandemParameterFile = parser->isTandemParameter();
      qfile.close();

      throw pappso::PappsoException(
        QObject::tr("Error reading %1 X!Tandem preset file :\n %2")
          .arg(_param_source.absoluteFilePath())
          .arg(parser->errorString()));
    }

  qDebug();

  setTandemParametersFileType(parser);

  qDebug();

  if(m_fileType == ParamFileType::result)
    {
      m_presetFileInfo = parser->getTandemPresetFileInfo();
    }
  delete parser;
  parameters.setMethodName(getMethodName());

  qDebug();
  return parameters;
}

bool
TandemParametersFile::isTandemPresetFile()
{
  getTandemParameters();
  if(m_fileType == ParamFileType::result || m_fileType == ParamFileType::preset)
    {
      return true;
    }
  else
    {
      return false;
    }
}

void
TandemParametersFile::writeXmlParametersFile(
  QXmlStreamWriter *p_out, const TandemParameters &parameters) const
{
  p_out->setAutoFormatting(true);
  p_out->writeStartDocument("1.0");

  //<?xml version="1.0" encoding="UTF-8"?>
  //<bioml label="example api document">
  //<note type="input" label="spectrum, parent monoisotopic mass error
  // units">ppm</note> <note type="input" label="spectrum, parent monoisotopic
  // mass error minus">10</note>
  p_out->writeStartElement("bioml");
  p_out->writeAttribute("label", "example api document");
  for(const QString &label : parameters.getMapLabelValue().keys())
    {
      p_out->writeStartElement("note");
      p_out->writeAttribute("type", "input");
      p_out->writeAttribute("label", label);
      p_out->writeCharacters(parameters.getMapLabelValue().value(label));
      p_out->writeEndElement();
    }
  //</bioml>
  p_out->writeEndElement();
  p_out->writeEndDocument();
}

void
TandemParametersFile::setTandemParametersFileType(
  XtandemParamSaxHandler *parser)
{
  if(this->exists())
    {
      try
        {
          if(parser->getTandemPresetFileInfo().absoluteFilePath() != "")
            {
              m_fileType = ParamFileType::result;
            }
          else
            {
              m_fileType = ParamFileType::preset;
            }
        }
      catch(pappso::ExceptionNotFound &error)
        {
          throw pappso::ExceptionNotFound(
            QObject::tr("error : %1 Doesn't exist'\n")
              .arg(_param_source.fileName()));
          m_fileType = ParamFileType::no_file;
        }
      catch(pappso::PappsoException &error)
        {
          throw pappso::PappsoException(
            QObject::tr("error : %1 Doesn't exist'\n")
              .arg(_param_source.fileName()));
          m_fileType = ParamFileType::not_xtandem;
        }
    }
}
