/**
© Florian Joncour, 2013-2018 florian@zetta-sys.com

Ce logiciel est un programme informatique faisant interface à la bibliothèque
Perspective3D, un outil de modélisation 3D à partir de vues orthographiques 2D.

Ce logiciel est régi par la licence CeCILL-C soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL-C telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme,  le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard  l'attention de l'utilisateur est attirée sur les risques
associés au chargement,  à l'utilisation,  à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant  des  connaissances  informatiques approfondies.  Les
utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL-C, et que vous en avez accepté les
termes.
**/

/* Vue 2D (affichage des fichiers DXF) */

#ifndef VUE2D_H
#define VUE2D_H

/* Espace d'affichage 2D. */

#include <QShortcut>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsRectItem>
#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDropEvent>
#include <QString>
#include <QList>

#include "animeQt.h"
#include "perspective_api.h"

class Scene2D;
class QGraphicsGroupItem;

class Vue2D: public QGraphicsView
{
        Q_OBJECT
    public:
        explicit Vue2D(const AnimationQt &anim, Scene2D *scene, QWidget *parent=0);
        ~Vue2D();

        const Scene2D *Scene2DPtr() const;

#ifdef SUPPORT_VISION2D
        bool ModeEdition() const;
#endif // SUPPORT_VISION2D

        void Zoom(int delta_i);
        void AffichageGlobalVue(); /* Affiche l'ensemble du plan */
        void EchelleAnime(qreal e);
//        QPoint toLocalPos(const QPoint &pos);
        bool CentreSurAnime(const QPointF &pos);
        bool CadrageAnim(const QRectF &rect); /* Adapte la vue à un rectangle. */
        void ReinitEchelle();
        void ReinitEchelleAnime();
        qreal EchelleActuelle();
        void ReinitMatriceAffichage();

    protected:
        void timerEvent(QTimerEvent *ev);
        void wheelEvent(QWheelEvent *event); /* Quand on touche à la molette de la souris... */
        void mouseDoubleClickEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
        void resizeEvent(QResizeEvent *event);
        void focusInEvent(QFocusEvent *event);
        void focusOutEvent(QFocusEvent *event);
        void dragEnterEvent(QDragEnterEvent *event);
//        void dropEvent(QDropEvent *event);
        void dragLeaveEvent(QDragLeaveEvent *event);

    signals:
        void InsertFichier(const QString & nfichier);

    private slots:
        void Zoom_p();
        void Zoom_m();

    private:
        const AnimationQt &animation;
        int id_timer;
        unsigned int n_boucle_anim_zoom;
        double val_zoom;
        QString Fichier_Insert;
        QVector<QShortcut*> ListeRaccourcis;
};

#ifdef SUPPORT_VISION2D
enum class ModeEdition2D : unsigned int
{
    NUL=0,
    EDITION1=1,
    EDITION2=2,
    REJETE_EDITION2=4
};
PENUM_DECL_OPS(ModeEdition2D)
#endif // SUPPORT_VISION2D

class Scene2D: public QGraphicsScene
{
        Q_OBJECT
    public:
        explicit Scene2D(const AnimationQt &anim, QRgb couleur_fond, QWidget *parent=0);
        ~Scene2D();

        void ChangeCouleurFond(QRgb couleur_fond);

        QGraphicsGroupItem *NouveauGroupeEnts();
        QGraphicsGroupItem *DernierGroupeEnts();
        void AjoutEntLigne(const Perspective3D::Pligne2D &ligne, int id_entite, int id_groupe);
        void AjoutEntEllipse(const Perspective3D::Pellipse2D &ellipse, int id_entite, int id_groupe);
        void AjoutEntTexte(const Perspective3D::PTexte2D &texte, int id_entite, int id_groupe);
        void AjoutEntPoint(const Perspective3D::Ppoint2D &point, int id_entite, int id_groupe, const QColor &couleur);
        void AjoutImage(const Perspective3D::PImage &image, const Perspective3D::Ppoint2D & position);

        bool GereNouveauRect(const QPointF &pos);
        void DessineRect(Perspective3D::vues2D_t vue, bool reinit=true);
        void ReinitRect(Perspective3D::vues2D_t vue);
        bool ConvVueMult();
        void NettoyageCadresOrigines(); /* Nettoyage de la scène hors plan. */
        void Nettoyage(); /* Nettoyage de la scène. */

        bool SupprimeDernierGroupe();

        void SupprimeElement(QGraphicsItem *item);

        inline bool ValideElement(const QGraphicsItem *item) const
        {
            return ((item!=nullptr) && item->scene() == this);
        }

#ifdef SUPPORT_VISION2D
        void PermutationModeEdition();
        void ForceModeEdition(bool etat);
        bool ModeEdition() const;
        bool ModeEdition2() const;
        bool RejeteModeEdition2() const;
#endif // SUPPORT_VISION2D

        bool ImportGroupeEntitesPerspective(const Perspective3D::PGroupeEnts2D *groupe_p, int id_groupe);
        bool ImportScenePerspective(const Perspective3D::PScene2D *scene2d_perspective, bool nettoyage=true);
        const QPen Stylo_trait(bool cache, const QColor &couleur) const;

        inline const QPen Stylo_trait(bool cache, const Perspective3D::PCouleur &couleur) const
        {
            return Stylo_trait(cache, QColor(couleur.R(), couleur.V(), couleur.B()));
        }

        inline const QGraphicsView *GraphicView() const
        {
            return views().first();
        }

        inline QGraphicsView *GraphicViewNonConst() const
        {
            return views().first();
        }

        void DefOrigine(Perspective3D::vues2D_t vue);
        /* On demande l'assignation d'une nouvelle origine (définie à la main par l'utilisateur). */

        void AnimRectSelection(const QRectF &cadre_vue, Perspective3D::vues2D_t vue);

        bool AnnuleDessinRectCourant();
        /* Annule le tracé d'un rectangle */

        void Ajout_RectSelection(const QRectF &rect, Perspective3D::vues2D_t vue, bool courant=false);
        /* Ajoute un rectangle de sélection pour les vues. */

        void AnimOrigine(const QPointF &point, Perspective3D::vues2D_t vue);
        /* Ajoute une origine avec une animation de la souris. */

        void AjoutOrigine(const QPointF &point, Perspective3D::vues2D_t vue);
        /* Ajoute une origine pour la vue donnée en argument. */

        void ReinitOrigine(Perspective3D::vues2D_t vue);

        bool RectVueDefini(Perspective3D::vues2D_t vue) const;
        /* Renvoi true si le rectange d'une vue est défini, sinon false. */

        bool OrigineDefinie(Perspective3D::vues2D_t vue) const;
        /* Renvoi true si l'origine est définie, sinon false. */

        int NbVuesDefinies() const;
        /* Renvoi le nombre de vues valides. */

        inline bool VuesDefinies() const
        {
            int score = NbVuesDefinies();
            return (score == 1 || score == 3);
        }

#ifdef SUPPORT_VISION2D
        inline const QColor& CouleurTrace() const { return couleur_trace; }
        inline void defCouleurTrace(const QColor &couleur) { couleur_trace = couleur; }

        inline float TailleGrille() const { return taille_grille; }
        inline void defTailleGrille(float v) { taille_grille = v; }
//        void GereAffichageGrille(bool affiche_grille);
        void drawBackground(QPainter *painter, const QRectF &rect);
#endif // SUPPORT_VISION2D

        inline void defMenuContextuel(bool etat)
        {
            MenuContextuel = etat;
        }

        const QGraphicsRectItem *RectVueConst(Perspective3D::vues2D_t vue) const;

        inline const QPointF &OrigineFace() const { return origineFace; }
        inline const QPointF &OrigineCote() const { return origineCote; }
        inline const QPointF &OrigineHaut() const { return origineHaut; }

        int CompteurEntites() const;

        inline unsigned int NombreGroupes() const
        {
            return GroupesEntites.size();
        }

#ifdef DEBUG
        bool ControleIdsEntites(const Perspective3D::PScene2D *scene_p3d) const; /* Contrôle la validité de l'ensemble des entités de la scène et la synchro avec la PScene2D. */
#endif // DEBUG

    protected:
//        void changed(const QList<QRectF> &region);
        void mousePressEvent(QGraphicsSceneMouseEvent *event);
        void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
        void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
        void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
        void wheelEvent(QGraphicsSceneWheelEvent *event);
        void focusInEvent(QFocusEvent *event);
        void focusOutEvent(QFocusEvent *event);

        QGraphicsRectItem *rectFace;
        QGraphicsRectItem *rectCote;
        QGraphicsRectItem *rectHaut;
        QGraphicsRectItem *rectTripleVues;

        QPointF origineFace;
        QPointF origineCote;
        QPointF origineHaut;

//        void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);

    private:
        QPoint ConvCoordsSceneEcran(const QGraphicsRectItem *rect, bool p1) const;
        QPoint ConvCoordsSceneEcran(const QGraphicsEllipseItem *el) const;

        QGraphicsRectItem *RectVue(Perspective3D::vues2D_t vue) const;
        QGraphicsEllipseItem *EllipseVue(Perspective3D::vues2D_t vue) const;

        qreal TailleOrigineVue(Perspective3D::vues2D_t vue);
        /* Renvoi la taille pour tracer l'origine de la vue donner en argument. */

        void ModifOpaciteRect(QGraphicsRectItem *rect, float val);

        void ModifOpacite(Perspective3D::vues2D_t vue, float val);

        void DessineOrigine(double x, double y, Perspective3D::vues2D_t vue);
        /* Trace l'ellipse d'une origine */

        bool DebutAxe(double x, double y);
        /* Début du traçage de la ligne d'axe (trait de construction). */

        bool P2Axe(const QPointF &p);
        /* Redéfini le p2 de la ligne d'axe */

        bool P1Axe(const QPointF &p);
        /* Redéfini le p1 de la ligne d'axe */

        bool FinAxe();
        /* Supprime la ligne d'axe */

        Qt::GlobalColor CouleurVue(Perspective3D::vues2D_t vue) const;
        /* Renvoi la couleur correspondant à la vue donnée en argument */

        QPointF MilieuLigne(const QLineF &l) const;
        /* Renvoi le point au milieu d'une ligne */

        QPointF PerpendiculairePL(double x, double y, const QLineF &l) const;
        /* Renvoi le point perpendiculaire à la ligne donnée en argument depuis le point. */

        QPointF PointAccrochage(const QPointF &pos) const;
        /* Renvoi un point d'accorchage sur une entitée au plus proche de la position donnée en argument */

        void ValideRectSelection();

#ifdef SUPPORT_VISION2D
        void DepartTrace(const QPointF &pos_scene, const QPoint &pos_ecran);
#endif // SUPPORT_VISION2D

        const AnimationQt &animation;
        bool MenuContextuel;
        bool AccrochageObjets;
        Perspective3D::vues2D_t idVue;
        char etatRect;
        bool etatOrigine;
//        QPointF pos_clic;

#ifdef SUPPORT_VISION2D
        QColor couleur_trace;
#endif // SUPPORT_VISION2D

        QPointF posRect_orig;
        QGraphicsRectItem *rectCourant;

        QGraphicsEllipseItem *EllipseorigineCourante;
        QPointF origineCourante;

        QList<QGraphicsGroupItem*> GroupesEntites;

        QGraphicsLineItem *axeDessin; /* Ligne d'axe (trait de construction) */

        QGraphicsEllipseItem *EllipseorigineFace;
        QGraphicsEllipseItem *EllipseorigineCote;
        QGraphicsEllipseItem *EllipseorigineHaut;

#ifdef SUPPORT_VISION2D
        ModeEdition2D mode_edition;
        bool init_ligne;
        QPointF point_precedent_edition;
        QList<QPoint> points_edition;
        QGraphicsGroupItem *lignes_affichage_edition;
        float taille_grille;
#endif // SUPPORT_VISION2D

    signals:
        void NouveauRect(Perspective3D::vues2D_t idVue);
        void NouvelleOrigine(Perspective3D::vues2D_t idVue);
        void SupprimeOrigine(Perspective3D::vues2D_t idVue);
        void AfficheMenu(QPoint pos);
        void GenModele(bool);
        void TexteCoords(const QString &texte);
        void NouvelleScene();

//        void ValideSelection();

#ifdef SUPPORT_VISION2D
        void DoubleClicScene(bool mode);
        void NouveauTraceVision2D(const QList<QPoint>&, const QPointF &);
#endif // SUPPORT_VISION2D
};

#endif // VUE2D_H
