// XDrawChem
// Copyright (C) 2004-2005  Bryan Herger <bherger@users.sourceforge.net>
// Copyright (C) 2020  Yaman Qalieh <ybq987@gmail.com>

// 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 <https://www.gnu.org/licenses/>.

// chemdata.h --  the class that manages all of XDrawChem's data.

#ifndef CHEMDATA_H
#define CHEMDATA_H

#include <QList>
#include <QPoint>
#include <QString>

#include "bond.h"
#include "cml.h"
#include "drawable.h"
#include "gobject.h"
#include "molinfodialog.h"
#include "text.h"
#include "xdc_event.h"

#include "prefs.h"

extern Preferences preferences;

class Render2D;
class Clipboard;

class ChemData : public QObject {
    Q_OBJECT

  public:
    void setRender2D(Render2D *r1) { r = r1; }
    Render2D *getRender2D() { return r; }
    bool edited() { return notSaved; }
    bool needsSave() { return notSaved; }
    void saved() { notSaved = false; }

    // defined in chemdata.cpp
    ChemData(QObject *parent = 0);
    ~ChemData();
    void drawAll();
    Molecule *firstMolecule();
    void addMolecule(Molecule *);
    void addBond(DPoint *, DPoint *, int, int, QColor, bool hl = false);
    void addArrow(DPoint *, DPoint *, QColor, int, int, bool hl = false);
    void addCurveArrow(DPoint *, DPoint *, QColor, QString, bool hl = false);
    void addBracket(DPoint *, DPoint *, QColor, int, bool hl = false);
    void addText(Text *);
    void addGraphicObject(GraphicObject *);
    void addSymbol(DPoint *, QString, bool hl = false);
    void Erase(Drawable *);
    void EraseSelected();
    void DetectSplit();
    DPoint *FindNearestPoint(DPoint *, double &);
    Drawable *FindNearestObject(DPoint *, double &);
    void NewSelectRect(QRect, bool);
    void SelectAll();
    void DeselectAll();
    void Move(double, double);
    void Resize(DPoint *, double);
    void Rotate(DPoint *, double);
    void Flip(DPoint *, int);
    void SetColorIfHighlighted(QColor);
    void FinishMove();
    QRect selectionBox();
    QList<DPoint *> UniquePoints();
    QList<Drawable *> UniqueObjects();
    int Size();
    void SetTopLeft(QPoint p) { RenderTopLeft = p; }
    Molecule *insideMolecule(DPoint *);

    // defined in chemdata_edit.cpp
    void Cut();
    void Copy();
    bool Paste();
    void StartUndo(int fn = 0, DPoint *s1 = 0);
    bool Undo();
    bool Redo();
    void ScaleAll(double bond_length = -1.0);

    // defined in chemdata_rw.cpp
    bool load(QString);
    bool save(QString);
    bool load_legacy(QString);

    // defined in chemdata_xdc.cpp
    bool load_native(QString);
    bool save_native(QString);

    // defined in chemdata_cdx.cpp
    bool save_cdx(QString);
    bool save_cdxml(QString);

    // defined in chemdata_mdl.cpp
    bool load_mdl(QString);
    bool ProcessMDL(QString);
    bool save_mdl(QString);

    // defined in chemdata_xml.cpp
    bool load_xml(QString);
    bool ProcessXML(QString);
    bool LoadCDXMLFile(QString, QString);
    bool SelfContainedTag(QString);
    QString ReadTag(QString, int &);
    QString ReadData(QString, int &);
    QStringList ReadAttr(QString);
    QStringList Tokenize(QString);
    void ParseBoundingBox(QString, double &, double &, double &, double &);

    // defined in chemdata_cml.cpp
    bool NewLoadCMLFile(QString);
    bool LoadCMLFile(QString, QString);
    bool save_cml(QString);
    void Convert_CML_Lists_To_Native();

    // defined in chemdata_tools.cpp
    void Save3D(QString);
    void clearAllGroups();
    void Tool(DPoint *, int);
    void AutoLayout();
    void fromSMILES(QString);
    void SmartPlace(QString, DPoint *);
    void SmartPlaceToo(QString, DPoint *);
    void SmartPlaceThree(QString, DPoint *);
    double CalculateRingAttachAngle(DPoint *);
    bool SelectWithinLoop(QVector<QPoint>);
    // defined in cdx2cdxml.cpp
    QString ParseProperty(QByteArray);
    QString CDXToCDXML(QString);
    // defined in chemdata_rxn.cpp
    void ReactionAnalysis(int);
    // defined in retro.cpp
    void Retro(Molecule *);
    // defined here
    void setThickKludge(int lt1) { thick_kludge = lt1; }
    Clipboard *getClipboard() {
        if (!clip)
            clip = new Clipboard;
        return clip;
    }
    void setClipboard(Clipboard *clip1) {
        if (clip1)
            ++clip1->owners;
        clip = clip1;
    }

  public slots:
    void XDCEventHandler(XDC_Event *);
    void returnFromMID();

  signals:
    void SignalSetStatusBar(QString);
    void SignalHelpTopic(QString);
    void SignalUpdateCustomRingMenu();

  private:
    // the Render2D widget this ChemData is linked to
    Render2D *r;
    // Top left corner of visible part of r
    QPoint RenderTopLeft;
    // Application clipboard
    Clipboard *clip = nullptr;
    // list of Drawable objects we are tracking
    QList<Drawable *> drawlist;
    // Variables for reading CML/CDXML/XML files
    QString MoleculeTitle;
    QString MoleculeId;
    QList<CML_Atom *> CML_Atoms;
    QList<CML_Atom *> CML_Atoms_Sub;
    QList<CML_Bond *> CML_Bonds;
    QList<CML_Bond *> CML_Bonds_Sub;
    QList<int *> TagStack;
    QList<Drawable *> CDXML_Objects;
    CML_Atom *curr_atom;
    CML_Bond *curr_bond;
    // variables for Undo
    int undo_index;
    DPoint *undo_start, *undo_end;
    double undo_dx, undo_dy;
    QStringList last_states;
    QString current_undo_file;
    // Presistent dialogs
    MolInfoDialog *mi;
    Text *tt, *tt_mw, *tt_ef, *tt_ea;
    // hack for setting ring thickness
    int thick_kludge;
    // has this document changed since last save?
    bool notSaved;
};

#endif
