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


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


/////////////////////// Local includes
#include "ModifSpec.hpp"


namespace MsXpS
{

namespace libXpertMass
{


/*!
\class MsXpS::libXpertMass::ModifSpec
\inmodule libXpertMass
\ingroup PolChemDefBuildingdBlocks
\inheaderfile ModifSpec.hpp

\brief The ModifSpec class provides the specification about how \l Modif
objects are represented.

The ModifSpec class specifies how a \l Modif object is represented
graphically, mainly by connecting its modif name to a graphics SVG file that
is located in the Polymer chemistry definition directory. That connection is
performed in the "modification_dictionary" dictionary file itself also located
in the polymer chemistry definition directory. Its contents look like this:

\code
Phosphorylation%T%phospho.svg
Sulphation%T%sulpho.svg
AmidationAsp%O%asparagine.svg
Acetylation%T%acetyl.svg
AmidationGlu%O%glutamine.svg
Oxidation%T%oxidation.svg
SulfideBond%T%sulfbond.svg
ProtonLoss%T%protonloss.svg
\endcode

The \c{Phosphorylation%T%phospho.svg} line indicates that, when a Monomer object
 modified by a Modif object by name "Phosphorylation" is
to be rendered graphically, the corresponding vignette to be used is in the
file named "phospho.svg" in the polymer chemistry definition directory. The 'T'
and 'O' special directives, indicate the way the modification is to be
represented graphically in the sequence editor. When a monomer is modified, the
modification event can be shown by overlaying onto the monomer's vignette
a transparent vignette or by replacing it totally with a new one.
These two behaviours are documented above with the letters 'T' (transparent
overlay) or 'O' (opaque overwrite).
*/

/*!
\variable int MsXpS::libXpertMass::ModifSpec::m_name

\brief The name of the modification.
*/

/*!
\variable int MsXpS::libXpertMass::ModifSpec::m_action

\brief The graphics action (Opaque, that is, overwrite ; Transparent, that is,
overlay) of the modification.
*/

/*!
\variable int MsXpS::libXpertMass::ModifSpec::m_raster

\brief The file name of the raster representation of the modification.
*/

/*!
\variable int MsXpS::libXpertMass::ModifSpec::m_vector

\brief The filename of the vector representation of the modification.
*/

/*!
\variable int MsXpS::libXpertMass::ModifSpec::m_sound

\brief The file name of the sound for the name of the modification.
*/


/*!
\brief Constructs a ModifSpec instance.
*/
ModifSpec::ModifSpec()
{
  m_action = 0;
}

/*!
\brief Destructs this ModifSpec instance.
*/
ModifSpec::~ModifSpec()
{
}

/*!
\brief Sets the monomer \a name.
*/
void
ModifSpec::setName(const QString &name)
{
  m_name = name;
}

/*!
\brief Returns the monomer name.
*/
const QString &
ModifSpec::name()
{
  return m_name;
}


/*!
\brief Sets the \a action.

The action is the way the Modif's vignette applies itself on top of the
\l{Monomer}'s vignette: either in an Opaque manner, thus overwriting the
initial vignette, or in a Transparent manner, thus only partially overlaying
the initial vignette.
*/
void
ModifSpec::setAction(int action)
{
  m_action = action;
}

/*!
\brief Returns the action.

\sa setAction()
*/
int
ModifSpec::action()
{
  return m_action;
}


/*!
\brief Sets the raster image file name to \a raster.
*/
void
ModifSpec::setRaster(const QString &raster)
{
  m_raster = raster;
}


/*!
\brief Returns the raster image file name.
*/
const QString &
ModifSpec::raster()
{
  return m_raster;
}

/*!
\brief Sets the vector image file name to \a vector.
*/
void
ModifSpec::setVector(const QString &vector)
{
  m_vector = vector;
}

/*!
\brief Returns the vector image file name.
*/
const QString &
ModifSpec::vector()
{
  return m_vector;
}


/*!
\brief Sets the file name of the Modif's \a sound file.
*/
void
ModifSpec::setSound(const QString &sound)
{
  m_sound = sound;
}


/*!
\brief Returns the file name of the Modif's sound file.
*/
const QString &
ModifSpec::sound()
{
  return m_sound;
}


/*!
\brief Parses the \a file_path dictionary containing the Modif
specifications.

At the moment the file has this format:

\code
Phosphorylation%T%phospho.svg
Sulphation%T%sulpho.svg
AmidationAsp%O%asparagine.svg
Acetylation%T%acetyl.svg
AmidationGlu%O%glutamine.svg
Oxidation%T%oxidation.svg
\endcode

Upon parsing, the \a modif_spec_list of ModifSpec instances will be filled with
instances created on the basis of each parsed line in the file.

Returns true if the parsing was successful, false otherwise.
*/
bool
ModifSpec::parseFile(QString &file_path, QList<ModifSpec *> *modif_spec_list)
{
  ModifSpec *modifSpec = 0;

  qint64 lineLength;

  QString line;
  QString temp;

  char buffer[1024];

  Q_ASSERT(modif_spec_list != 0);

  if(file_path.isEmpty())
    return false;

  QFile file(file_path);

  if(!file.open(QFile::ReadOnly))
    return false;

  // The lines we have to parse are of the following type:
  // Phosphorylation%T%phospho.svg
  // Any line starting with '#' are not parsed.

  // Get the first line of the file. Next we enter in to a
  // while loop.

  lineLength = file.readLine(buffer, sizeof(buffer));

  while(lineLength != -1)
    {
      // The line is now in buffer, and we want to convert
      // it to Unicode by setting it in a QString.
      line = buffer;

      // The line that is in line should contain something like:
      // Phosphorylation%T%phospho.svg

      // Remove all the spaces from the borders: Whitespace means any
      // character for which QChar::isSpace() returns true. This
      // includes the ASCII characters '\t', '\n', '\v', '\f', '\r',
      // and ' '.

      line = line.trimmed();

      if(line.isEmpty() || line.startsWith('#', Qt::CaseInsensitive))
        {
          lineLength = file.readLine(buffer, sizeof(buffer));
          continue;
        }

      qDebug() << "Reading line:" << line;

      // Now some other checks. Remember the format of the line:
      // Phosphorylation%T%phospho.svg
      QString modif_name;
      QString file_name;
      QString opacity;

      QRegularExpression reg_exp(QString("^(.*)%([TO])%(.*)$"));

      QRegularExpressionMatch match = reg_exp.match(line);

      if(match.hasMatch())
        {
          modif_name = match.captured(1);
          opacity    = match.captured(2);
          file_name  = match.captured(3);
        }
      else
        return false;

      // qDebug() << "modif_name:" << modif_name << "opacity:" << opacity
      //          << "file_name:" << file_name;

      // OK, we finally can allocate a new ModifSpec *.
      modifSpec = new ModifSpec();

      modifSpec->m_name   = modif_name;
      modifSpec->m_vector = file_name;

      if(opacity == "O")
        modifSpec->m_action = CompositingType::OPAQUE;
      else if(opacity == "T")
        modifSpec->m_action = CompositingType::TRANSPARENT;
      else
        qFatal("Programming error.");

      modif_spec_list->append(modifSpec);
      lineLength = file.readLine(buffer, sizeof(buffer));
    }

  return true;
}

} // namespace libXpertMass

} // namespace MsXpS
