/**
© 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.
**/

/* Objet: Gère l'interface 3D (exploite vue3d) dans l'un des onglets de la fenêtre principale (à l'exception du premier qui est dédié à l'affichage 2D. */

#ifndef INTERFACE3D_H
#define INTERFACE3D_H

#include <QThread>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QComboBox>
#include <QLabel>
#include <QListWidget>

#include "Qt/Conversion.h"
#include "BarreOutils3D.h"

#include "API/perspective_api.h"

#include "vue3d.h"
#include "wnotifications.h"
#include "animeQt.h"
#include "animelogo.h"
#include "proprietes3d.h"
#include "th_perspective.h"

//#define ACTIVE_PROPRIETES3D_DOCK /* Si activé, la fenêtre des propriétés 3D sera dans une fenêtre à part. */

struct ProprietesPlan_t
{
        ProprietesPlan_t() : ignore(true), param_gen1(0), id_ral(-1), type_affichage(0), vue_reference(Perspective3D::vues2D_t::VUEMULT) {}

        bool ignore;
        QString fichier_plan;
        QRectF rectFace;
        QRectF rectCote;
        QRectF rectHaut;
        QPointF origineFace;
        QPointF origineCote;
        QPointF origineHaut;
        qreal param_gen1;
        unsigned int id_ral;
        int type_affichage;
        Perspective3D::vues2D_t vue_reference;
};
typedef struct ProprietesPlan_t ProprietesPlan_t;

class Modele3DInst
{
    public:
        Modele3DInst(Th_Perspective *th_p);
        Modele3DInst(Th_ImportSTL3D *th_imp);
        Modele3DInst(Perspective3D::PScene3D *s);
        Modele3DInst(const Modele3DInst &c);
        ~Modele3DInst();

        void Destruct();

        void defMode2D(bool etat);
        inline bool Mode2D() const { return mode_2d; }

        bool ArretGeneration(); /* Force l'arrêt de la génération */

        bool FinGeneration() const; /* Contrôle si la génération est toujours en cours... */
        bool ValideGeneration() const;
        bool ThreadEnCours() const;

        bool AfficheAnimeLogo() const;

        puint Avancement() const;

        Perspective3D::Perspective *Perspective() const;
        const Perspective3D::Perspective *PerspectiveConst() const;
        Perspective3D::PScene3D *SceneP3D() const;
        const Perspective3D::PScene3D *SceneP3DConst() const;

    private:
        Th_Perspective *th_Perspective;
        Perspective3D::Perspective *inst_perspective;
        Th_ImportSTL3D *th_import_stl;
        Perspective3D::PScene3D *inst_scene3d;
        bool mode_2d;
};

class Interface3d: public QWidget
{
        Q_OBJECT
    public:
        explicit Interface3d(const AnimationQt &anime, const Modele3DInst &scene, unsigned int id_onglet, const PGL::Params_GL &params_gl, const PGL::Params_Perspective_GL &params_pgl, int id_style=1, unsigned int mode_affichage_3d=PGL_MODE_AFFICHAGE_DEFAUT, bool gen_barre_outils_3d=true, bool affichage_points_accroche=false, bool affiche_proprietes3d_init_=false, Perspective3D::vues2D_t vue_reference_affichage=Perspective3D::vues2D_t::VUEMULT, QWidget *parent=0);
        ~Interface3d();

        Q_DISABLE_COPY(Interface3d)

        void AttendInitialisationGL() const;

        Perspective3D::Perspective *Perspective() const;
        Perspective3D::PScene3D *SceneP3D() const;
        const Perspective3D::PScene3D *SceneP3DConst() const;

        bool AffichageDefinifPret() const;

        VueModele3D *Vue_Modele() const;
        void TransfertModele(); /* Transfert du modèle Perspective3D -> Perspective_GL. */

        void RegenProjections(Perspective3D::vues2D_t projs, Perspective3D::infos3d_t infos, int tailletxt_pct, bool regen=true);

        inline bool defEtatShaders(bool etat)
        {
            return VueModele->defEtatShaders(etat);
        }

        inline const std::string& InitialisationShaders(const char *source_vertex_shader, const char *source_pixel_shader, unsigned int contexte)
        {
            AttendInitialisationGL();
            return VueModele->InitialisationShadersModele(source_vertex_shader, source_pixel_shader, contexte);
        }

        void ReinitAffichage(); /* Réinitialisation de l'affichage. */

        inline void TermineShaderPost() { VueModele->TermineShaderPost(); }
        inline void ExecShaderPost() { VueModele->ExecShaderPost(); }
        inline void defTempoShaderPost(int t) { VueModele->defTempoShaderPost(t); }

        inline void defIdOnglet(int id) { IdOnglet = id; }

        void defIdCouleurSolide(int index);
        void defOpacite(int val);
        void DefEclairageDynamique(bool etat);
        void defAffichageAccroche(bool etat);
        bool InitAnimationSolide();
        void InitTimer(); /* Redéfini le fil d'exécution qui génère le modèle. */
        void defTypeAffichage(int type); /* Change le type d'affichage */

        void defModeAffichage(bool mode_ortho, bool force_redim, Perspective3D::vues2D_t vue);
        void defLissageAffichage3D(bool etat);

        bool ArretGeneration();

        void defImprimante3D(bool active, float x, float y, float z);

        inline bool ProprietesVisible() const
        {
            return Proprietes->isVisible();
        }

        inline bool OuvreProprietes()
        {
            if (Proprietes->isVisible()) { return false; }
            Proprietes->show();
            return true;
        }

        inline bool FermeProprietes() { return (Proprietes->isVisible() ? Proprietes->close() : false); }
        void GereProprietes(bool force_fermeture=false);

        ProprietesPlan_t &ProprietesPlanNonConst();
        const ProprietesPlan_t &ProprietesPlan();

        void AnimeRotationScene() const;

        void SelectionPoint(int index, bool active_proprietes=true, bool centre_point=true);
        void SelectionSegment(int index, bool active_proprietes=true, bool centre_segment=true);
        void SelectionSurface(int index, bool active_proprietes=true, bool anim_surface=false, bool reinit=true);
        void SelectionSolide(int index);

        void SupprimeRestaurePoint(int index, bool regen=true);
        void SupprimeRestaureLigne(int index, bool regen=true);
        void SupprimeRestaureSurface(int index, bool regen=true);
        void SupprimeRestaureSolide(int index, bool regen=true);

        bool ChangeEtatBarreOutils(bool etat);

        void GereEtatBoutonsOutils3D();
        void defCouleurFond(QRgb c, bool animation=false);

        void defCouleursScene(QRgb couleur_sommets, QRgb couleur_segments, QRgb couleur_imprimante, QRgb couleur_reperes_sommets, QRgb couleur_reperes_segments, QRgb couleur_reperes_faces);

        void ForceModeAffichage(int index, bool sauvegarde_mode_affichage=false);

        void ForceSelectionCouleur(int index, bool sauvegarde_couleur=false);

        void ForceVue(Perspective3D::vues2D_t vue);

    protected:
        void ControleErreursPerspective();
        /* Contrôle le résultat de la génération et avertir l'utilisateur si il y a un truc qui s'est mal passé. */

        void ControleErreursImport();

        void ChangeStyleOutils3D(const QColor &couleur_fond);
        bool GenBarreOutils3D(QWidget *parent=nullptr);
        bool RetireBarreOutils3D();

    private:
        void Construct(const AnimationQt &anime, const PGL::Params_GL &params_gl, const PGL::Params_Perspective_GL &params_pgl, int id_style=1, unsigned int mode_affichage_3d=PGL_MODE_AFFICHAGE_DEFAUT, bool gen_barre_outils_3d=true, bool affichage_points_accroche=false, Perspective3D::vues2D_t vue_reference_affichage=Perspective3D::vues2D_t::VUEMULT);

        Modele3DInst InstanceModele;
        VueModele3D *VueModele;

        WNotifications *Notifications;

        ProprietesPlan_t proprietes_plan;

        bool etat_barre_outils;
        const bool affiche_proprietes3d_init;
        QColor copie_couleur_fond;

        Perspective3D::PStdVectInts Corbeille_Surfaces;
        Perspective3D::PStdVectInts Corbeille_Lignes;
        Perspective3D::PStdVectInts Corbeille_Points;
        Perspective3D::PStdVectInts Corbeille_Solides;

        VectElementsSuppr VectSuppr;

        QVBoxLayout *Layout_principal;

        QWidget *WBarreOutils3D;
        QWidget *WOutils3D;
        QFrame *Separateur_Outils;
        QHBoxLayout *layout_h_barre_outils3d, *layout_h_outils3d;
        QLabel *lbl_type_affichage;
        QLabel *lbl_RAL;
        BarreOutils3D *Outils3D;
        QComboBox *cmb_TypeAffichage;
        QComboBox *cmb_SelCouleur;
        QSpacerItem *horizontalSpacer1, *horizontalSpacer2, *horizontalSpacer3;
        QVBoxLayout *verticalLayout_3D;

#ifdef ACTIVE_PROPRIETES3D_DOCK
        Proprietes3D_dock *Proprietes;
#else
        Proprietes3D_widget *Proprietes;
#endif // ACTIVE_PROPRIETES3D_DOCK

        const AnimationQt &animation;
        AnimeLogo *animelogo;

        int id_timer;
        int IdOnglet;

        void SurligneCouleur(PGL::PCouleur_GL &c, unsigned int n=1) const;
        void RestaureCouleur(PGL::PCouleur_GL &c, unsigned int n=1) const;

        int NormaliseId(int id, const Perspective3D::PStdVectInts &vect) const;
        /* Normalise un id de vecteur d'après les ids contenus dans un second vecteur qui contient les ids à ignorer.
            Les ids qui suivent un id à ignorer sont décrémentés. */

        unsigned int NSommetsCorbeillePoints(int index) const;
        unsigned int NSegmentsCorbeilleLigne(int index) const;
        unsigned int NTrianglesCorbeilleSurfaces(int index) const;
        unsigned int NSurfacesCorbeilleSolides(int index) const;

    signals:
        void ImprimeModele();
        void ExportImageModele();
#ifdef SUPPORT_GIF
        void EnregistreAnimationModele();
#endif
        void ExportModele();
        void ExportModele_2D();
        void GenPatron();
        void ExportScript(const ProprietesPlan_t &, const Perspective3D::Perspective &);
        void FinGeneration(int id_onglet);

        void ConfigAffichage(int);

    private slots:
        void showEvent(QShowEvent *event);
        void closeEvent(QCloseEvent *ev);
        void timerEvent(QTimerEvent *ev);

#ifdef ACTIVE_QPAINTER_POST_VUE3D
        void PaintPostGL();
#endif // ACTIVE_QPAINTER_POST_VUE3D

        void SelectionAffichage(int index);
        void SelectionCouleur(int index);
        void SelectionPoint_sig(int index, bool active_proprietes=true, bool centre_point=true);
        void SelectioneSegment_sig(int index, bool active_proprietes=true, bool centre_segment=true);
        void SelectionSurface_sig(int index, bool active_proprietes=true, bool anim_surface=false, bool reinit=true);
        void VueFace() const;
        void VueArriere() const;
        void VueCote() const;
        void VueCoteGauche() const;
        void VueHaut() const;
        void VueDessous() const;
        void VuePerspective() const;
        void VuePerspectiveInv() const;
        void GereProprietes_sig();
        void TypeAffichage_sig(int id);

        void ExportScript_sig();

        bool SupprimeSurface(int id, bool regen=true, bool gere_vectsuppr=true); /* Supprime une surface. */
        void RestaureSurface(unsigned int n=1, bool regen=true); /* Restaure les n dernières surfaces dans la corbeille */

        bool SupprimePoint(int id, bool regen=true, bool gere_vectsuppr=true); /* Supprime un point dont l'id est donné en argument. */
        void RestaurePoint(unsigned int n=1, bool regen=true); /* Restaure les n derniers points supprimés. */

        bool SupprimeLigne(int id, bool regen=true, bool gere_vectsuppr=true); /* Supprime une ligne dont l'id est donné en argument. */
        void RestaureLigne(unsigned int n=1, bool regen=true); /* Restaure les n dernières lignes supprimés */

        bool SupprimeSolide(int id, bool regen=true, bool gere_vectsuppr=true);
        void RestaureSolide(unsigned int n=1, bool regen=true);

        void Restaure(); /* Annule la suppression des derniers éléments. */

        void RegenModele(bool regen_projections=true);
};
#endif // INTERFACE3D_H
