
#ifndef TMECA_H_INCLUDED
#define TMECA_H_INCLUDED

/*
OBJET       classe d'un mecanisme obj

DATE        02/2025

AUTEUR      philippe Thebaud

COMMENTAIRE
*/

#include <GL/glew.h>
#include <string>
#include <fstream>
#include <vector>
//#include <deque>

#include "../ECO/OUtils.h"
#include "../ECO/OTexturelist.h"
#include "../ECO/OMesh_obj.h"

#include "../ECO/defered/ODshGeo.h"
#include "../ECO/defered/ODshColor.h"
//
#include "common.h"
//#include "Tmesh_obj.h"


#include "Tdetector.h"

// code flux load save
#define FLUX_MECA   "meca"

// code des animations (privé)
enum {
    MEC_ANI_NULL, MEC_ANI_OBJ, MEC_ANI_DET, MEC_ANI_ANI, MEC_ANI_ACT, MEC_ANI_CYC
};
const std::string gl_code_ani[] = {
    "nul", "obj", "det", "ani", "act", "cyc"
};
// etat animation
enum { MEC_ANIM_NULL, MEC_ANIM_END, MEC_ANIM_RUN };
// etat mecanisme
//enum { MEC_BLOQUE, MEC_VERROUILLE, MEC_FERME, MEC_OUVERT }; // ancien
enum { MEC_VERROUILLE, MEC_FERME, MEC_OUVERT, MEC_BLOQUE };     // correspond aux autres etats (eteint=1 allumé=2 ...)
// retourn erreur sur anim_start
enum { MEC_ERROR_NULL, MEC_ERROR_ANIM_RUN, MEC_ERROR_BLOQUE, MEC_ERROR_VERROUILLE, MEC_ERROR_REFANIMATION, MEC_ERROR_REFACTION };



enum {
    MEC_ACT_NULL, MEC_ACT_ANIM, MEC_ACT_LIGHT, MEC_ACT_LOOT, MEC_ACT_RUMMAGE, MEC_ACT_STATE, MEC_ACT_STATE_WAIT
};

const std::string gl_meca_verbe[] = {
    "null", "anim", "light", "loot", "rummage", "state", "statewait"
};

// anim     : lance une animation > anim/coff_00/ouvrir
// light    : éclaire une zone (light=0.1 > light=1) > light/zone/index/etat
// loot     : ouvre un sac apres victoire au combat > loot
// rummage  : ouvre un coffre, un conteneur, pour le fouiller > rummage
// state    : change l'état de la cible > state/code meca/2
// statewait : etat attendu pour lancer l'action suivante



class Tmeca
{
public:
	Tmeca();
	~Tmeca();

    void        anim();
	int         anim_start(std::string commande);
	int         anim_start_cycle(std::string commande);
	void        anim_stop();

	void        create(std::string flux);
    void        create(std::ifstream& flux);

	void        draw(ODshGeo& dshGeo);
	void        draw(ODshGeo& dshGeo, ODshColor& dshColor);

    std::string getAction();
    int         getAction_exist(std::string ref);
    std::string getAction_sub(size_t idx);
    int         getAction_waiting();
    //
    int         getAnim(std::string commande);
    bool        getAnim_end();
    bool        getAnim_cycle_end();
    int         getAnim_state();
    size_t      getAnimation_size();
    std::string getAnimation_str(size_t idx);
    //
    OVec3_f&    getBound_min();
    OVec3_f&    getBound_max();
    OVec3_f     getBound_min(size_t part);
    OVec3_f     getBound_max(size_t part);
    std::string getCode();
    std::string getFile();
    void        getIn(OVec3_f& pos);
    std::string getName(size_t part = 0);
	OMat4&      getModel(size_t part = 0);
	size_t      getNbPart();
	OVec3_f&    getPos();                   // position globale
	OVec3_f&    getRot();
	OVec3_f&    getScale();
	bool        getSelect();
	int         getState();
	int         getState_waiting();
	OVec3_f&    getSubPos(size_t part = 0);    // sous-position de la partie
	OVec3_f&    getSubRot(size_t part = 0);
	bool        getVisible();

    void        incPos(float px, float py, float pz); // modif pos et rot des instances selectionnées
    void        incRot(float rx, float ry, float rz);

	void        save(std::ofstream& flux);
	void        setAction(std::string str);
	void        setAction_waiting(int value);
	void        setModel(OVec3_f& pos, OVec3_f& rot, OVec3_f scale = OVec3_f(1,1,1));
	void		setPos(OVec3_f& pos);
	void		setRot(OVec3_f& rot);
	void        setScale(OVec3_f& scale);
	void        setState_waiting(int value);
	void        setSelect();
	void        setSelect(bool mode);
	void        setState(int value);
	void        setVisible(bool mode);

	// proprietes
	static void P_setBoundScaleFactor(float value);

private:

    void        _add_frame(std::vector<std::string>& strList, std::vector<float>& axe);

    void        _clear_model();
    bool        _composition();

    bool        _load_animation(std::ifstream& flux);
    bool        _load_material(std::ifstream& flux);
    bool        _load_mesh(std::ifstream& flux);
    bool        _load_readLine(std::istream& flux);
    void        _load_skipLine(std::istream& flux);

    int         _setAction(std::string action);
    void        _setFin();
    void        _setModel();
    void        _setPartie(int refAction);

    void        _vao();

protected:

    bool        m_visible;
    std::string m_code, m_path, m_file;
    OVec3_f     m_pos, m_rot, m_scale;
    bool        m_cull_face, m_select;

    std::vector<s_obj_material> material;
    Tdetector   detector;
    OVec3_f     m_bound_min, m_bound_max;

    // --- parties du mecanisme

    struct s_partie
    {
        std::string nom;
        std::vector<s_obj_part> meshPart;
        std::vector<s_emissive> emissive;

        OVec3_f     bound_min, bound_max;
        OVec3_f     decalPos,decalRot;
        //
        OVec3_f     axePos;
        OVec3_f     axeRot;
        OVec3_f     axeScale;
        OMat4       model;
        std::string str_axeRef;
        size_t      axeRef = 0;
        //
        std::vector<float>  px;
        std::vector<float>  py;
        std::vector<float>  pz;
        std::vector<float>  rx;
        std::vector<float>  ry;
        std::vector<float>  rz;
        std::vector<float>  sx;
        std::vector<float>  sy;
        std::vector<float>  sz;
    };

    std::deque<s_partie> partie;

    // animation

    std::string m_action;
    std::vector<std::string> m_action_lst; // temporaire
    int         m_state, m_state_waiting, m_action_waiting;
    //
    int         m_etat_animation;
    size_t      m_frame, m_frame_end;
    int         m_loop;

    std::vector<std::string>    lstAnimation;
    std::vector<std::string>    lstAction;

    // suite d'animation

    std::vector<std::string>    lstCycle;

    struct s_cycle
    {
        std::string nom;
        size_t      loop = 0, idx;
        std::vector<std::string> commande;
    };
    s_cycle     m_cycle;  // 1 seul à la fois !

};

#endif
