/* 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
 */

/////////////////////// Stdlib includes
#include <memory>


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


/////////////////////// libmassincludes
#include <libXpertMass/PolChemDef.hpp>
#include <libXpertMass/Monomer.hpp>
#include <libXpertMass/Polymer.hpp>

/////////////////////// Local includes
#include "PolChemDefRendering.hpp"
#include "Modification_default_vignette.hpp"
#include "Cross_link_default_vignette.hpp"


namespace MsXpS
{

namespace massxpert
{


//! Constructs a polymer chemistry definition.
PolChemDefRendering::PolChemDefRendering()
{
  //   qDebug() << "Constructing PolChemDefRendering:" << this;
}


PolChemDefRendering::PolChemDefRendering(const PolChemDefRendering &other)
  : mcsp_polChemDef(other.mcsp_polChemDef)
{
}


PolChemDefRendering::PolChemDefRendering(
  libXpertMass::PolChemDefCstSPtr polChemDefCstSPtr)
  : mcsp_polChemDef(polChemDefCstSPtr)
{
  Q_ASSERT(mcsp_polChemDef != nullptr);
  // qDebug() << "polChemDef is:" << mcsp_polChemDef.get()
  //<< "cst pol chem def usage:" << mcsp_polChemDef.use_count();
}


//! Destroys the polymer chemistry definition
PolChemDefRendering::~PolChemDefRendering()
{
  // qDebug() << "Entering ~PolChemDefRendering() with polChemDef name:"
  //<< mcsp_polChemDef->name() << this;
}


void
PolChemDefRendering::setPolChemDefCstSPtr(
  libXpertMass::PolChemDefCstSPtr polChemDefCstSPtr)
{
  mcsp_polChemDef = polChemDefCstSPtr;

  Q_ASSERT(mcsp_polChemDef != nullptr);
  // qDebug() << "polChemDef is:" << mcsp_polChemDef.get()
  //<< "cst pol chem def usage:" << mcsp_polChemDef.use_count();
}


libXpertMass::PolChemDefCstSPtr
PolChemDefRendering::getPolChemDef()
{
  return mcsp_polChemDef;
}

//! Returns the hash of vignette renderers.
/*!
  \return The hash of vignette renderers.
  */
QHash<QString, ChemEntVignetteRenderer *> *
PolChemDefRendering::chemEntVignetteRendererHash()
{
  return &m_chemEntVignetteRendererHash;
}


//! Searches a chemical entity vignette renderer associated to \p key.
/*! Searches in the chemical entity vignette renderers' hash for a
  vignette renderer having a key \p key.

  \param key Key with which to look for a vignette renderer.

  \return The vignette renderer associated to \p key.
  */
ChemEntVignetteRenderer *
PolChemDefRendering::chemEntVignetteRenderer(const QString &key)
{
  return m_chemEntVignetteRendererHash.value(key);
}


//! Creates a chemical entity vignette renderer.
/*!  The returned renderer must either be set as a shared renderer by
  a ChemEntVignette instance(which takes care of adding a
  reference count to it) or must be dealt with properly so as to avoid
  leaks.

  \param filePath File path to the graphics file.

  \param parent Parent object.

  \return The newly allocated chemical entity vignette renderer.

  \sa newMonomerVignetteRenderer(const QString &code, QObject *parent).
  \sa newModifVignetteRenderer(const QString &name, QObject *parent).
  */
ChemEntVignetteRenderer *
PolChemDefRendering::newChemEntVignetteRenderer(const QString &filePath,
                                                QObject *parent)
{
  return new ChemEntVignetteRenderer(filePath, parent);
}


//! Creates a monomer vignette renderer.
/*!

  \param str Code of the monomer.

  \param parent Parent object.

  \return The newly allocated monomer vignette renderer or 0 upon
  failure.

  \sa newModifVignetteRenderer(const QString &str, QObject *parent).
  */
ChemEntVignetteRenderer *
PolChemDefRendering::newMonomerVignetteRenderer(const QString &str,
                                                QObject *parent)
{
  libXpertMass::MonomerSpec *monomerSpec = 0;
  bool found                        = false;

  QList<libXpertMass::MonomerSpec *> monomerSpecList =
    mcsp_polChemDef->monomerSpecList();

  for(int iter = 0; iter < monomerSpecList.size(); ++iter)
    {
      monomerSpec = monomerSpecList.at(iter);

      if(monomerSpec->code() == str)
        {
          found = true;
          break;
        }
    }

  if(!found)
    return (0);

  QString filePath =
    mcsp_polChemDef->getXmlDataDirPath() + "/" + monomerSpec->vector();

  ChemEntVignetteRenderer *chemEntVignetteRenderer =
    new ChemEntVignetteRenderer(filePath, parent);

  if(!chemEntVignetteRenderer->isValid())
    {
      delete chemEntVignetteRenderer;
      return 0;
    }

  m_chemEntVignetteRendererHash.insert(monomerSpec->code(),
                                       chemEntVignetteRenderer);

  chemEntVignetteRenderer->setHash(&m_chemEntVignetteRendererHash);

  return chemEntVignetteRenderer;
}


//! Creates a modification vignette renderer.
/*!

  \param str Name.

  \param parent Parent object.

  \return The newly allocated modification vignette renderer or 0 upon
  failure.

  \sa newMonomerVignetteRenderer(const QString &str, QObject *parent).
  */
ChemEntVignetteRenderer *
PolChemDefRendering::newModifVignetteRenderer(const QString &modifName,
                                              QObject *parent)
{
  libXpertMass::ModifSpec *modifSpec = 0;
  bool found                    = false;

  QList<libXpertMass::ModifSpec *> modifSpecList = mcsp_polChemDef->modifSpecList();


  for(int iter = 0; iter < modifSpecList.size(); ++iter)
    {
      modifSpec = modifSpecList.at(iter);

      if(modifSpec->name() == modifName)
        {
          found = true;
          break;
        }
    }

  // If the modification name modifName is for a modification that has no
  // vignette associated to it in modification_dictionary, then use
  // the default one(if there is one in the directory corresponding
  // to current polymer chemistry definition). If there is not any,
  // then use the one that is defined in the
  // Modification_default_vignette.hpp file included in this source
  // file.

  QString filePath;

  if(!found)
    filePath =
      mcsp_polChemDef->getXmlDataDirPath() + "/default-modif-vignette.svg";
  else
    filePath = mcsp_polChemDef->getXmlDataDirPath() + "/" + modifSpec->vector();

  ChemEntVignetteRenderer *chemEntVignetteRenderer = 0;

  if(!QFile(filePath).exists())
    {
      // None of the two files exists. Try to construct the renderer
      // using the svg vignette declared in
      // Modification_default_vignette.hpp in the form of QByteArray
      // defaultModifVignette.
      chemEntVignetteRenderer =
        new ChemEntVignetteRenderer(defaultModifVignette, parent);
    }
  else
    {
      chemEntVignetteRenderer = new ChemEntVignetteRenderer(filePath, parent);
    }

  if(!chemEntVignetteRenderer->isValid())
    {
      delete chemEntVignetteRenderer;

      return 0;
    }

  m_chemEntVignetteRendererHash.insert(modifName, chemEntVignetteRenderer);

  chemEntVignetteRenderer->setHash(&m_chemEntVignetteRendererHash);

  return chemEntVignetteRenderer;
}


ChemEntVignetteRenderer *
PolChemDefRendering::newCrossLinkerVignetteRenderer(const QString &name,
                                                    QObject *parent)
{
  libXpertMass::CrossLinkerSpec *crossLinkerSpec = 0;
  bool found                                = false;

  QList<libXpertMass::CrossLinkerSpec *> crossLinkerSpecList =
    mcsp_polChemDef->crossLinkerSpecList();


  for(int iter = 0; iter < crossLinkerSpecList.size(); ++iter)
    {
      crossLinkerSpec = crossLinkerSpecList.at(iter);

      if(crossLinkerSpec->name() == name)
        {
          found = true;
          break;
        }
    }

  // If the crossLinker name is for a crossLink that has no
  // vignette associated to it in cross_linker_dictionary, then use
  // the default one(if there is one in the directory corresponding
  // to current polymer chemistry definition). If there is not any,
  // then use the one that is defined in the
  // Modification_default_vignette.hpp file included in this source
  // file.

  QString filePath;

  if(!found)
    filePath =
      mcsp_polChemDef->getXmlDataDirPath() + "/default-cross-link-vignette.svg";
  else
    filePath =
      mcsp_polChemDef->getXmlDataDirPath() + "/" + crossLinkerSpec->vector();

  ChemEntVignetteRenderer *chemEntVignetteRenderer = 0;

  if(!QFile(filePath).exists())
    {
      // None of the two files exists. Try to construct the renderer
      // using the svg vignette declared in
      // Cross_link_default_vignette.hpp in the form of QByteArray
      // defaultModifVignette.
      chemEntVignetteRenderer =
        new ChemEntVignetteRenderer(defaultCrossLinkerVignette, parent);
    }
  else
    {
      chemEntVignetteRenderer = new ChemEntVignetteRenderer(filePath, parent);
    }

  if(!chemEntVignetteRenderer->isValid())
    {
      delete chemEntVignetteRenderer;

      return 0;
    }

  m_chemEntVignetteRendererHash.insert(name, chemEntVignetteRenderer);

  chemEntVignetteRenderer->setHash(&m_chemEntVignetteRendererHash);

  return chemEntVignetteRenderer;
}


} // namespace massxpert

} // namespace MsXpS
