/* 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 <QDebug>
#include <QStringList>


/////////////////////// Local includes
#include <minexpert/nongui/MassSpecFileMetaData.hpp>


namespace msXpSmineXpert
{


//! Construct an empty MassSpecFileMetaData instance.
MassSpecFileMetaData::MassSpecFileMetaData()
{
}


//! Assigns \p other to \c this MassSpecFileMetaData instance.
/*!

  The assignment is deep with a full copy of all the members of \p other into
  \c this instance.

  \param other reference to the MassSpecFileMetaData instance to be assigned
  to \c this instance.

  \return a reference to \this instance.

  */
MassSpecFileMetaData &
MassSpecFileMetaData::operator=(const MassSpecFileMetaData &other)
{
  if(&other == this)
    return *this;

  m_stringHash.clear();
  QHashIterator<QString, QString> stringHashIter(other.m_stringHash);
  while(stringHashIter.hasNext())
    {
      stringHashIter.next();
      setStringItem(stringHashIter.key(), stringHashIter.value());
    }

  m_intHash.clear();
  QHashIterator<QString, int> intHashIter(other.m_intHash);
  while(intHashIter.hasNext())
    {
      intHashIter.next();
      setIntItem(intHashIter.key(), intHashIter.value());
    }

  m_doubleHash.clear();
  QHashIterator<QString, double> doubleHashIter(other.m_doubleHash);
  while(doubleHashIter.hasNext())
    {
      doubleHashIter.next();
      setDoubleItem(doubleHashIter.key(), doubleHashIter.value());
    }

  m_boolHash.clear();
  QHashIterator<QString, bool> boolHashIter(other.m_boolHash);
  while(boolHashIter.hasNext())
    {
      boolHashIter.next();
      setBoolItem(boolHashIter.key(), boolHashIter.value());
    }

  return *this;
}


//! Destruct \c this MassSpecFileMetaData instance.
MassSpecFileMetaData::~MassSpecFileMetaData()
{
}


//! Get an item value of type string matching string \p key.
/*!

  \param key string containing the key to be used for the search in \c
  m_stringHash.

  \param reference to the value string in which to store the found value. Left
  unmodified if no value was found.

  \return true if a string value was found for \p key. False otherwise.

 */
bool
MassSpecFileMetaData::stringItem(QString key, QString &value) const
{
  if(key.isEmpty())
    return false;

  if(!m_stringHash.contains(key))
    return false;

  value = m_stringHash.value(key);

  return true;
}


//! Get all the string items of \c this MassSpecFileMetaData instance.
/*!

  Note that the \p keys and \p values strings lists are emptied before
  filling-in and that after filling-in they cannot have different sizes,
  because the hashes are \e not multi-hashes allowing multiple values for a
  given key.

  \param keys list of strings where to store all the keys (arbitrary order).

  \param values list of strings where to store all the values (arbitrary order).

  \return The number of keys stored in \p keys.

  \sa

 */
int
MassSpecFileMetaData::allStringItems(QStringList &keys,
                                     QStringList &values) const
{
  keys.clear();
  values.clear();

  keys   = m_stringHash.uniqueKeys();
  values = m_stringHash.values();

  if(keys.size() != values.size())
    {
      qFatal(
        "Fatal error at %s@%d -- %s. "
        "Key list and value list cannot have different sizes."
        "Program aborted.",
        __FILE__,
        __LINE__,
        __FUNCTION__);
    }

  return keys.size();
}


//! Insert a string item to the member \c m_stringHash.
/*!

  The \p key / \p val pair is \e inserted into the hash (not multi-inserted),
  which means that if an key item existed before it is overwritten with the
  new one.

  \param key string containing the key of the key/val pair.

  \param value string containing the value of the key/val pair.

 */
void
MassSpecFileMetaData::setStringItem(QString key, QString value)
{
  if(key.isEmpty())
    return;

  m_stringHash.insert(key, value);
}


bool
MassSpecFileMetaData::intItem(QString key, int &value) const
{
  if(key.isEmpty())
    return false;

  if(!m_intHash.contains(key))
    return false;

  value = m_intHash.value(key);

  return true;
}


int
MassSpecFileMetaData::allIntItems(QStringList &keys, QList<int> &values) const
{
  keys.clear();
  values.clear();

  keys   = m_intHash.uniqueKeys();
  values = m_intHash.values();

  if(keys.size() != values.size())
    {
      qDebug() << __FILE__ << __LINE__
               << "Error with the sizes of keys list "
                  "and values list in hash. "
                  "Exiting\n";

      exit(1);
    }

  return keys.size();
}


void
MassSpecFileMetaData::setIntItem(QString key, int value)
{
  if(key.isEmpty())
    return;

  m_intHash.insert(key, value);
}


bool
MassSpecFileMetaData::doubleItem(QString key, double &value) const
{
  if(key.isEmpty())
    return false;

  if(!m_doubleHash.contains(key))
    return false;

  value = m_doubleHash.value(key);

  return true;
}


int
MassSpecFileMetaData::allDoubleItems(QStringList &keys,
                                     QList<double> &values) const
{
  keys.clear();
  values.clear();

  keys   = m_doubleHash.uniqueKeys();
  values = m_doubleHash.values();

  if(keys.size() != values.size())
    {
      qDebug() << __FILE__ << __LINE__
               << "Error with the sizes of keys list "
                  "and values list in hash. "
                  "Exiting\n";

      exit(1);
    }

  return keys.size();
}


void
MassSpecFileMetaData::setDoubleItem(QString key, double value)
{
  if(key.isEmpty())
    return;

  m_doubleHash.insert(key, value);
}


bool
MassSpecFileMetaData::boolItem(QString key, bool &value) const
{
  if(key.isEmpty())
    return false;

  if(!m_boolHash.contains(key))
    return false;

  value = m_boolHash.value(key);

  return true;
}


int
MassSpecFileMetaData::allBoolItems(QStringList &keys, QList<bool> &values) const
{
  keys.clear();
  values.clear();

  keys   = m_boolHash.uniqueKeys();
  values = m_boolHash.values();

  if(keys.size() != values.size())
    {
      qDebug() << __FILE__ << __LINE__
               << "Error with the sizes of keys list "
                  "and values list in hash. "
                  "Exiting\n";

      exit(1);
    }

  return keys.size();
}


void
MassSpecFileMetaData::setBoolItem(QString key, bool value)
{
  if(key.isEmpty())
    return;

  m_boolHash.insert(key, value);
}


//! Get a heap-allocated string representing data.
/*!

  Only the items of the \p type MassSpecFileMetaDataType are processed in such
  a manner that they fit in a string.

  \param type MassSpecFileMetaDataType of the data to get a string
  representation of.

  \return A heap-allocated string that should be freed when no more in use.

 */
QString *
MassSpecFileMetaData::asText(MassSpecFileMetaDataType type) const
{
  QString *p_text = new QString;
  QList<QString> keyList;
  QString key;

  if(type & MassSpecFileMetaDataType::MASS_SPEC_META_DATA_TYPE_STRING)
    {
      keyList = m_stringHash.keys();

      for(int iter = 0; iter < keyList.size(); ++iter)
        {
          key           = keyList.at(iter);
          QString value = m_stringHash.value(key);

          // qDebug() << __FILE__ << __LINE__
          // << "key:value" << key << ":" << value;

          *p_text += QString("%1 = %2\n").arg(key).arg(value);
        }
    }

  if(type & MassSpecFileMetaDataType::MASS_SPEC_META_DATA_TYPE_INT)
    {
      keyList = m_intHash.keys();

      for(int iter = 0; iter < keyList.size(); ++iter)
        {
          key       = keyList.at(iter);
          int value = m_intHash.value(key);

          // qDebug() << __FILE__ << __LINE__
          // << "key:value" << key << ":" << value;

          *p_text += QString("%1 = %2\n").arg(key).arg(value);
        }
    }
  if(type & MassSpecFileMetaDataType::MASS_SPEC_META_DATA_TYPE_DOUBLE)
    {
      keyList = m_doubleHash.keys();

      for(int iter = 0; iter < keyList.size(); ++iter)
        {
          key       = keyList.at(iter);
          int value = m_doubleHash.value(key);

          // qDebug() << __FILE__ << __LINE__
          // << "key:value" << key << ":" << value;

          *p_text += QString("%1 = %2\n").arg(key).arg(value);
        }
    }


  if(type & MassSpecFileMetaDataType::MASS_SPEC_META_DATA_TYPE_BOOL)
    {
      keyList = m_boolHash.keys();

      for(int iter = 0; iter < keyList.size(); ++iter)
        {
          key        = keyList.at(iter);
          bool value = m_boolHash.value(key);

          // qDebug() << __FILE__ << __LINE__
          // << "key:value" << key << ":" << value;

          *p_text += QString("%1 = %2\n").arg(key).arg(value);
        }
    }

  // qDebug() << __FILE__ << __LINE__
  // << "*p_text:" << *p_text;

  return p_text;
}

} // namespace msXpSmineXpert
