/**
 * \file pappsomspp/amino_acid/aastringcodec.h
 * \date 09/05/2023
 * \author Olivier Langella
 * \brief code and decodefrom  amino acid string to integer
 */

/*******************************************************************************
 * Copyright (c) 2023 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of PAPPSOms-tools.
 *
 *     PAPPSOms-tools 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.
 *
 *     PAPPSOms-tools 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 PAPPSOms-tools.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#pragma once

#include "../exportinmportconfig.h"
#include "aacode.h"

namespace pappso
{


class AaStringCodec;

/** \brief shared pointer on a Protein object
 */
typedef std::shared_ptr<const AaStringCodec> AaStringCodecSp;

struct CodeToMass
{
  uint32_t code = 0;
  double mass   = 0;
};
/**
 * @brief code and decode amino acid string sequence to unique integer
 */
class PMSPP_LIB_DECL AaStringCodec
{
  public:
  /**
   * Default constructor
   */
  AaStringCodec(const AaCode &aaCode);

  /**
   * Copy constructor
   *
   * @param other TODO
   */
  AaStringCodec(const AaStringCodec &other);

  /**
   * Destructor
   */
  ~AaStringCodec();


  /** @brief get the maximum code number for a given peptide size
   */
  std::size_t getLimitMax(std::size_t size) const;

  /** @brief get integer from amino acide suite string
   */
  uint32_t code(const QString &aa_str) const;


  /** @brief get the lowest common denominator integer from amino acide suite
   * string
   */
  uint32_t codeLlc(const QString &aa_str) const;

  /** @brief get the lowest common denominator integer from amino acide code
   * vector
   */
  uint32_t codeLlc(std::vector<uint8_t>::const_iterator it_begin,
                   std::size_t size) const;


  QString decode(uint32_t code) const;

  QStringList decode(const std::vector<uint32_t> &code_list) const;

  double getMass(uint32_t code) const;


  /** @brief generates all possible combination of llc code mass
   * llc : the lowest common code denominator for a given aa formula
   *
   * generate from peptide size =1 to peptide size
   */
  std::vector<CodeToMass>
  generateLlcCodeListUpToMaxPeptideSize(std::size_t size) const;

  /** @brief generates all possible combination of llc code mass
   * llc : the lowest common code denominator for a given aa formula
   *
   * generate only for this peptide size
   */
  std::vector<CodeToMass>
  generateLlcCodeListByMaxPeptideSize(std::size_t size) const;

  /** @brief tell if a code only contains a list of amino acid
   *
   * @param code the code to valid
   * @param aa_ok list of required amino acids
   */
  bool codeOnlyContains(uint32_t code, const std::vector<uint8_t> &aa_ok) const;


  /** @brief tell if a unique code only contains one amino acid 1 or n times
   *
   * @param code the code to valid
   * @param aa_ok the amino acid the code must contains
   * @param times the number of aa_ok presence in code
   */
  bool
  uniqueCodeContainsAminoAcid(uint32_t code, uint8_t aa_ok, int times) const;


  const AaCode &getAaCode() const;

  private:
  /** @brief recursive method to generate models
   */
  void recGenerateModel(std::vector<CodeToMass> &glist,
                        std::vector<uint8_t> &model,
                        std::size_t position) const;

  CodeToMass generateCodeMassFromModel(const std::vector<uint8_t> &model) const;

  private:
  uint32_t m_base = 0;
  const AaCode &m_aaCode;
  std::vector<uint32_t> m_units;
};
} // namespace pappso
