#pragma once

#include "Mat4.h"
#include "ReferenceCounter.h"

namespace Framework
{
    struct MouseEvent3D;
    struct KeyboardEvent;
    class Render3D; //! Render3D.h

    //! An object that can be drawn by the Screen3D class.
    class Drawable3D : public virtual ReferenceCounter
    {
    protected:
        Vec3<float> pos;   //! Position of the object
        Vec3<float> angle; //! Rotation angles for x, y and z
        Mat4<float> welt;  //! World translation matrix
        float radius;      //! The radius of a sphere that encloses the entire object
        bool alpha; //! Stores whether the object contains partially or fully
                    //! transparent areas
        bool rend;
        float size;

    public:
        //! Constructor
        DLLEXPORT Drawable3D();
        DLLEXPORT virtual ~Drawable3D();
        //! Sets the position of the drawing in the world
        //! \param p The position
        DLLEXPORT void setPosition(const Vec3<float>& p);
        //! Sets the position of the drawing in the world
        //! \param x The x position
        //! \param y The y position
        //! \param z The z position
        DLLEXPORT void setPosition(float x, float y, float z);
        //! Sets the position of the drawing in the world
        //! \param x The x position
        DLLEXPORT void setX(float x);
        //! Sets the position of the drawing in the world
        //! \param y The y position
        DLLEXPORT void setY(float y);
        //! Sets the position of the drawing in the world
        //! \param z The z position
        DLLEXPORT void setZ(float z);
        //! Sets the rotation of the drawing in the world
        //! \param d The rotation around the x, y and z axes
        DLLEXPORT void setRotation(const Vec3<float>& d);
        //! Sets the rotation of the drawing in the world
        //! \param xWinkel The rotation around the x axis
        //! \param yWinkel The rotation around the y axis
        //! \param zWinkel The rotation around the z axis
        DLLEXPORT void setRotation(float xWinkel, float yWinkel, float zWinkel);
        //! Sets the rotation of the drawing in the world
        //! \param winkel The rotation around the x axis
        DLLEXPORT void setRotationX(float winkel);
        //! Sets the rotation of the drawing in the world
        //! \param winkel The rotation around the y axis
        DLLEXPORT void setRotationY(float winkel);
        //! Sets the rotation of the drawing in the world
        //! \param winkel The rotation around the z axis
        DLLEXPORT void setRotationZ(float winkel);
        //! Sets whether the object contains partially or fully transparent
        //! areas \param a true if partially or fully transparent areas exist
        DLLEXPORT void setAlpha(bool a);
        //! Sets the scaling
        DLLEXPORT void setSize(float size);
        //! Calculates the matrices of all bones in the drawing's skeleton
        //! \param viewProj The multiplied camera matrices
        //! \param matBuffer An array of matrices to fill
        //! \return The number of matrices the drawing requires
        DLLEXPORT virtual int calculateMatrices(
            const Mat4<float>& viewProj, Mat4<float>* matBuffer);
        //! Processes a mouse event
        //! \param me The mouse event to process
        DLLEXPORT virtual void doMouseEvent(MouseEvent3D& me);
        //! Processes a keyboard event
        //! \param te The keyboard event to process
        DLLEXPORT virtual void doKeyboardEvent(KeyboardEvent& te);
        //! Processes elapsed time
        //! \param tickval The time in seconds since the last call of this
        //! function \return true if the object changed, false otherwise.
        DLLEXPORT virtual bool tick(double tickval);
        //! Returns whether the object contains partially or fully transparent areas
        DLLEXPORT bool hasAlpha() const;
        //! Returns the radius of a sphere that encloses the entire model
        DLLEXPORT inline float getRadius() const;
        //! Returns a point representing the position of the drawing in the world
        DLLEXPORT const Vec3<float>& getPos() const;
        //! Returns the X position of the drawing in the world
        DLLEXPORT float getX() const;
        //! Returns the Y position of the drawing in the world
        DLLEXPORT float getY() const;
        //! Returns the Z position of the drawing in the world
        DLLEXPORT float getZ() const;
        //! Returns a vector representing the rotation of the drawing in the world.
        //! x is the rotation around the X axis in radians, etc.
        DLLEXPORT const Vec3<float>& getRotation() const;
        //! Returns the rotation around the X axis in radians
        DLLEXPORT float getXRotation() const;
        //! Returns the rotation around the Y axis in radians
        DLLEXPORT float getYRotation() const;
        //! Returns the rotation around the Z axis in radians
        DLLEXPORT float getZRotation() const;
        //! Returns the matrix that translates the drawing into world space
        DLLEXPORT const Mat4<float>& getMatrix() const;
        //! Calculates a point in world coordinates from a point in local drawing
        //! coordinates by applying rotation, scaling and translation
        DLLEXPORT Vec3<float> applyWorldTransformation(
            const Vec3<float>& modelPos) const;
    };
} // namespace Framework