/* massXpert - the true massist's program.
   --------------------------------------
   Copyright(C) 2006,2007 Filippo Rusconi

   http://www.massxpert.org/massXpert

   This file is part of the massXpert project.

   The massxpert project is the successor to the "GNU polyxmass"
   project that is an official GNU project package(see
   www.gnu.org). The massXpert project is not endorsed by the GNU
   project, although it is released ---in its entirety--- under the
   GNU General Public License. A huge part of the code in massXpert
   is actually a C++ rewrite of code in GNU polyxmass. As such
   massXpert was started at the Centre National de la Recherche
   Scientifique(FRANCE), that granted me the formal authorization to
   publish it under this Free Software License.

   This software is free software; you can redistribute it and/or
   modify it under the terms of the GNU  General Public
   License version 3, as published by the Free Software Foundation.


   This software 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 software; if not, write to the

   Free Software Foundation, Inc.,

   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/


#ifndef OLIGOMER_HPP
#define OLIGOMER_HPP


/////////////////////// Local includes
#include "sequence.hpp"
#include "ponderable.hpp"
#include "ionizable.hpp"
#include "calcOptions.hpp"
#include "ionizeRule.hpp"
#include "monomer.hpp"
#include "coordinates.hpp"
#include "crossLinkList.hpp"


namespace massXpert
{

  class Polymer;


  //! The Oligomer class provides an oligomer.
  /*! An oligomer is a stretch of monomers belonging to a polymer. It is
    characterized by: \                         \

    \li The polymer(a pointer to a Polymer) in which it spans a
    given region;

    \li An index(integer) at which the region starts in the polymer sequence;

    \li An index(integer) at which the region stops in the polymer
    sequence

    The start index cannot be less than 0 and greater than the size of
    the polymer minus one, and the end index follows the same rule.

    Derived from Ponderable, an oligomer is also characterized by a
    monoisotopic mass and an average mass.

    All computations about an oligomer(fragmentation, composition, for
    example, isoelectric point, ...) can only be performed by referring
    to the sequence of its "enclosing" polymer. Therefore, an oligomer
    should never exist after the destruction of its enclosing polymer.
  */
  class Oligomer : public Sequence,
                   public CoordinateList,
                   public Ionizable,
                   public PropListHolder
  {
  protected:
    //! Polymer in which this oligomer spans a region.
    const QPointer<Polymer> mp_polymer;

    // !The list of the the cross-links that are involved in the
    // !formation of the cross-linked oligomer(the CrossLink *
    // !instances are in mp_polymer->crossLinkList()). We cannot use
    // !the CrossLinkList object because when destructed it would
    // !destroy the cross-links in it, while we only want to store
    // !pointers.
    QList<CrossLink*> m_crossLinkList;

    CalcOptions m_calcOptions;

  public:
    Oligomer(Polymer *, const QString &,
             const Ponderable &,
             const IonizeRule &,
             const CalcOptions &,
             bool,
             int, int);

    Oligomer(const PolChemDef *, const QString &,
             const Ponderable &,
             const IonizeRule &,
             const CalcOptions &,
             bool,
             int, int);

    Oligomer(Polymer *, const QString & = QString(),
             const Ponderable & = Ponderable(),
             int = -1, int = -1,
             const CalcOptions & = CalcOptions());

    Oligomer(const PolChemDef *, const QString & = QString(),
             const Ponderable & = Ponderable(),
             const CalcOptions & = CalcOptions(),
             int = -1, int = -1);

    Oligomer(const Ionizable &,
             const CalcOptions & = CalcOptions(),
             int = -1, int = -1);

    Oligomer(Polymer *, const QString & = QString(),
             double = 0, double = 0, int = -1, int = -1,
             const CalcOptions & = CalcOptions());

    Oligomer(const PolChemDef *, const QString & = QString(),
             const CalcOptions & = CalcOptions(),
             double = 0, double = 0, int = -1, int = -1);

    Oligomer(const Oligomer &);

    virtual ~Oligomer();

    const Polymer *polymer() const;

    void setStartEndIndices(int, int);

    void setStartIndex(int);
    int startIndex() const;

    void setEndIndex(int);
    int endIndex() const;

    int appendCoordinates(CoordinateList *);
    
    void setIonizeRule(IonizeRule &);
    IonizeRule &ionizeRule();

    void setCalcOptions(const CalcOptions &);
    const CalcOptions &calcOptions() const;
    void updateCalcOptions();

    const Monomer &atLeftEnd() const;
    const Monomer &atRightEnd() const;
    const Monomer *monomerAt(int) const;

    QList<CrossLink*> *crossLinkList();
    bool addCrossLink(CrossLink *);

    // ELEMENTAL CALCULATION FUNCTION
    /////////////////////////////////

    QString elementalComposition();

    /////////////////////////////////
    // ELEMENTAL CALCULATION FUNCTION

    virtual int makeMonomerText();
    QString *monomerText();

    virtual bool calculateMasses();
    virtual bool calculateMasses(const CalcOptions *calcOptions,
                                 const IonizeRule *ionizeRule = 0);

    virtual bool isModified();

    int size();

    bool encompasses(int) const;
    bool encompasses(const Monomer *) const;
  };

} // namespace massXpert


#endif // OLIGOMER_HPP
