
#ifndef __WFX_SCENE_SPATIAL_H__
#define __WFX_SCENE_SPATIAL_H__

#include <WFX/WFXIncludes.h>

#include <WFX/scene/BoundingVolume.h>
#include <WFX/renderer/Camera.h>
#include <WFX/renderer/Drawable.h>
#include <WFX/math/Vector3.h>
#include <WFX/math/Matrix3.h>

namespace WFX {

    namespace renderer {
        class Renderer;
    }

    namespace scene {

        class SceneGraphVisitor;
    
        /**
         * class that represents spatial information
         */
        class Spatial : public WFX::renderer::Drawable {
            public:
                /**
                 * Ctor/Dtor
                 */
                Spatial();
                virtual ~Spatial() {
                    destroy();
                }
                
                /** detroy this spatial */
                virtual void destroy();
                
                /** scale node */
                void scale(Real r);
                /** translate node */
                void translate(math::Vector3& v); 
                void translate(math::Vector2& v);
                /** rotate node around x axis*/
                void rotateX(Real radians);
                /** rotate node around y axis*/
                void rotateY(Real radians);
                /** rotate node around z axis*/
                void rotateZ(Real radians);

                /** 
                 * updates this node
                 * Transforms are accumulated in the downward pass,
                 * Boundingvolume in the updward pass
                 * Leafnodes decide whether upward pass is needed
                 */
                virtual void updateDown();

                /** render */
                void onDraw(renderer::Renderer* Renderer);
                virtual void draw(renderer::Renderer* Renderer) = 0;
               
                /** accept a SceneGraphVisitor */
                virtual void accept(SceneGraphVisitor& v) = 0;
            protected:
                friend class SceneGraphTransformer;
                friend class SceneGraphSerializer;
                friend class WFXLoader;
                
                /** parent pointer */
                Spatial* Parent;
                
                /** 
                 * Local orientation , position and scale
                 */
                math::Matrix3 LocalRotation;
                math::Vector3 LocalTranslation;
                Real LocalScale;

                /**
                 * global  orientation , position and scale
                 */
                math::Matrix3 WorldRotation;
                math::Vector3 WorldTranslation;
                Real WorldScale;

                /** local BV */
                BoundingVolume* ModelBound;
                /** world BV */
                BoundingVolume* WorldBound;



                /** marks this node as inactive */
                bool ForceCull;
               
                /** flags to indicate whether this subtree is dirty */
                bool Dirty;                     // dirty at all

            public:
                /** set the Parent */
                inline void setParent(Spatial* p) {
                    Parent = p;
                }
                /** returns the parent */
                inline Spatial* getParent() {
                    return Parent;
                }
                
                /** sets the local Rotation */
                inline void setLocalRotation(math::Matrix3 v) {
                    LocalRotation = v;
                    markDirty();
                }
                /** sets the world Rotation */
                inline void setWorldRotation(math::Matrix3 v) {
                    WorldRotation = v;
                    markDirty();
                }
                /** returns the local Rotation */
                inline math::Matrix3& getLocalRotation() {
                    return LocalRotation;
                }
                /** returns the global Rotation */
                inline math::Matrix3& getWorldRotation() {
                    return WorldRotation;
                }

                /** sets the local Translation */
                inline void setLocalTranslation(math::Vector3 v) {
                    LocalTranslation = v;
                    markDirty();
                }
                /** sets the global Translation */
                inline void setWorldTranslation(math::Vector3 v) {
                    WorldTranslation = v;
                    markDirty();
                }
                /** returns the local Translation */
                inline math::Vector3& getLocalTranslation() {
                    return LocalTranslation;
                }
                /** returns the global Translation */
                inline math::Vector3& getWorldTranslation() {
                    return WorldTranslation;
                }

                /** sets the local Scale */
                inline void setLocalScale(Real v) {
                    LocalScale = v;
                    markDirty();
                }
                /** returns the local Scale */
                inline Real& getLocalScale() {
                    return LocalScale;
                }
                /** returns the global Scale */
                inline Real& getWorldScale() {
                    return WorldScale;
                }

                /** returns the WorldBound */
                inline BoundingVolume* getWorldBound() {
                    return WorldBound;
                }

                /** sets the ModelBound */
                void setModelBound(BoundingVolume* b);

                /** forceculled access */
                inline bool forceCulled() {
                    return ForceCull;
                }
                inline void setForceCull(bool b) {
                    ForceCull = b;
                }
                /** dirty flags */
                inline void markDirty() {
                    Dirty = true;
                    if (Parent) Parent->markDirty();
                }
                
                
        };

    }

}


#endif //include guard


