/** @file  IRRShared.h
 * @brief Shared utilities for the IRR and IRRMESH loaders
 */

#ifndef INCLUDED_AI_IRRSHARED_H
#define INCLUDED_AI_IRRSHARED_H

#include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h>
#include <cstdint>

struct aiMaterial;

namespace Assimp {

/** @brief Matrix to convert from Assimp to IRR and backwards
 */
extern const aiMatrix4x4 AI_TO_IRR_MATRIX;

// Default: 0 = solid, one texture
#define AI_IRRMESH_MAT_solid_2layer 0x10000

// Transparency flags
#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
#define AI_IRRMESH_MAT_trans_add 0x2

// Lightmapping flags
#define AI_IRRMESH_MAT_lightmap 0x2
#define AI_IRRMESH_MAT_lightmap_m2 (AI_IRRMESH_MAT_lightmap | 0x4)
#define AI_IRRMESH_MAT_lightmap_m4 (AI_IRRMESH_MAT_lightmap | 0x8)
#define AI_IRRMESH_MAT_lightmap_light (AI_IRRMESH_MAT_lightmap | 0x10)
#define AI_IRRMESH_MAT_lightmap_light_m2 (AI_IRRMESH_MAT_lightmap | 0x20)
#define AI_IRRMESH_MAT_lightmap_light_m4 (AI_IRRMESH_MAT_lightmap | 0x40)
#define AI_IRRMESH_MAT_lightmap_add (AI_IRRMESH_MAT_lightmap | 0x80)

// Standard NormalMap (or Parallax map, they're treated equally)
#define AI_IRRMESH_MAT_normalmap_solid (0x100)

// Normal map combined with vertex alpha
#define AI_IRRMESH_MAT_normalmap_tva \
    (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_vertex_alpha)

// Normal map combined with additive transparency
#define AI_IRRMESH_MAT_normalmap_ta \
    (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_add)

// Special flag. It indicates a second texture has been found
// Its type depends ... either a normal textue or a normal map
#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000

// ---------------------------------------------------------------------------
/** Base class for the Irr and IrrMesh importers.
 *
 *  Declares some irrlight-related xml parsing utilities and provides tools
 *  to load materials from IRR and IRRMESH files.
 */
class IrrlichtBase {
protected:
    IrrlichtBase() {
        // empty
    }

    ~IrrlichtBase() = default;

    /** @brief Data structure for a simple name-value property
     */
    template <class T>
    struct Property {
        std::string name;
        T value;
    };

    typedef Property<uint32_t> HexProperty;
    typedef Property<std::string> StringProperty;
    typedef Property<bool> BoolProperty;
    typedef Property<float> FloatProperty;
    typedef Property<aiVector3D> VectorProperty;
    typedef Property<int> IntProperty;

    /// XML reader instance
    XmlParser mParser;

    // -------------------------------------------------------------------
    /** Parse a material description from the XML
     *  @return The created material
     *  @param matFlags Receives AI_IRRMESH_MAT_XX flags
     */
    aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);

    // -------------------------------------------------------------------
    /** Read a property of the specified type from the current XML element.
     *  @param out Receives output data
     *  @param node XML attribute element containing data
     */
    void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
    void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
    void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
    void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
    void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
    void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
};

// ------------------------------------------------------------------------------------------------
// Unpack a hex color, e.g. 0xdcdedfff
inline void ColorFromARGBPacked(uint32_t in, aiColor4D &clr) {
    clr.a = ((in >> 24) & 0xff) / 255.f;
    clr.r = ((in >> 16) & 0xff) / 255.f;
    clr.g = ((in >> 8) & 0xff) / 255.f;
    clr.b = ((in)&0xff) / 255.f;
}

} // end namespace Assimp

#endif // !! INCLUDED_AI_IRRSHARED_H