/*
 * GameObject.h
 *
 *  Created on: Feb 16, 2011
 *      Author: cpresser
 */

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

#include <OgreSceneManager.h>
#include <OgreEntity.h>
#include <OgreFrameListener.h>
#include <OgreString.h>

//forward class declarations, so we don;t have to include everything here.
class Ball;
class Wall;
class Paddle;
class Block;

class GameObject {
public:
        /*
         * The height that every sceneObject will be scaled to.
         */
        static const Ogre::Real HEIGHT = 1;

        /*
         * Every game object gets its own id from this pool
         */
        static unsigned int s_id;

        /*
         * Create an empty uninitialized GameObject
         */
        GameObject();

        /*
         * Destroy the GameObject
         */
        virtual ~GameObject();

        /**
         * Initialize the game object so it can be used as part of a scene.
         * This method will most likely be called when you create a scene.
         * Only call this method once for an object.
         *
         * Parameters:
         *       sceneMgr: the scene manager to add to
         *   name: the name of the new object
         *   position: where to place this object
         *   mesh: the name of the mesh to use with this object
         *   material: (optional) the name of the material to be used with
         *      this object
         *
        */
        virtual void init(Ogre::SceneManager *sceneMgr,
                        Ogre::String name,
                        Ogre::Vector3 position,
                        Ogre::String mesh,
                        Ogre::String material = "");


        /**
         * Update the game object in the scene.
         * This method will most likely be called when the rest of the
         * scene is updated e.g. from the frameRenderingQueued method.
         *
         * Parameters:
         *    evt: The frame event sent for the update.
         *
         * Returns false if the object has removed itself from the scene and
         *   needs to be removed from the game.
         */
        virtual bool update(const Ogre::FrameEvent& evt);

        /**
         * Returns true if this object has been initialized.
         */
        virtual bool isInitialized();

        /**
         * Get this objects direction vector as a reference.
         *
         * The fact that it returns a reference means that the
         * method call can be used to change the stored direction.
         *
         */
        virtual Ogre::Vector3 &getDirection();

        /**
         * Set this object's direction.
         *
         * Parameter:
         *    direction: the new direction for this object
         */
        virtual void setDirection(Ogre::Vector3 direction);

        /**
         * Set whether or not this object is selected.
         *
         * Parameter:
         *   select: if true select the object, if false deselect it.
         */
        virtual void setSelected(bool select);

        /**
         * Return true if this object is selected, false otherwise
         */
        virtual bool isSelected();

        /**
         * Return the name of this object.
         */
        virtual Ogre::String getName();

        /**
         * Return the name of this object's Entity.
         */
        virtual Ogre::String getEntityName();

        /**
         * Return the name of this object's SceneNode.
         */
        virtual Ogre::String getNodeName();

        /**
         * Return the unique id of this object
         */
        virtual unsigned int getId();

        /**
         * Get the scaled bounding box for this object
         */
        virtual Ogre::AxisAlignedBox getTransformedBoundingBox();

        /**
         * Move one step back. This will undo a collision.
         */
        virtual void stepBack();

        /*
         * Returns this objects query flag
         */
        virtual Ogre::uint32 getQueryFlag();

        /*
         * Set whether the object is currently attached to the scene
         */
        virtual void setInScene(bool in);

        /*
         * Replace this object from scene (if it was removed)
         */
        virtual bool getInScene();

        /*
         * Get the entity pointer
         */
        virtual Ogre::Entity *getEntity();

        /*
         * Get the scene node pointer
         */
        virtual Ogre::SceneNode *getSceneNode();

        /*
         * Get the speed
         */
        virtual Ogre::Real getSpeed();

        /*
         * Set the speed
         */
        virtual void setSpeed(Ogre::Real speed);


        /*
         * Get the objects current position
         */
        virtual Ogre::Vector3 getPosition();

        /*
         * Set the objects current position
         */
        virtual void setPosition( Ogre::Vector3 pos);


        /*
         * Called when this collides with another object.
         * Parameters:
         *   hit: the object that hit this one
         *   useDir: use the direction passed as a parameter
         *   dir: pass a direction of impact
         */
        virtual void collidesWith(GameObject *hit, bool useDir = false,
                        Ogre::Vector3 dir = Ogre::Vector3::ZERO);

        /*
         * Called when this collides with a Ball object.
         * This method does nothing.
         * Override it to handle this type of collision.
         * Parameters:
         *   hit: the object that hit this one
         *   useDir: use the direction passed as a parameter
         *   dir: pass a direction of impact
         */
        virtual void collidesWithBall(Ball *hit, bool useDir = false,
                        Ogre::Vector3 dir = Ogre::Vector3::ZERO);

        /*
         * Called when this collides with a Wall object.
         * This method does nothing.
         * Override it to handle this type of collision.
         * Parameters:
         *   hit: the object that hit this one
         *   useDir: use the direction passed as a parameter
         *   dir: pass a direction of impact
         */

        virtual void collidesWithWall(Wall *hit, bool useDir = false,
                        Ogre::Vector3 dir = Ogre::Vector3::ZERO);

        /*
         * Called when this collides with a Paddle object.
         * This method does nothing.
         * Override it to handle this type of collision.
         * Parameters:
         *   hit: the object that hit this one
         *   useDir: use the direction passed as a parameter
         *   dir: pass a direction of impact
         */

        virtual void collidesWithPaddle(Paddle *hit, bool useDir = false,
                        Ogre::Vector3 dir = Ogre::Vector3::ZERO);

        /*
         * Called when this collides with a Block object.
         * This method does nothing.
         * Override it to handle this type of collision.
         * Parameters:
         *   hit: the object that hit this one
         *   useDir: use the direction passed as a parameter
         *   dir: pass a direction of impact
         */

        virtual void collidesWithBlock(Block *hit, bool useDir = false,
                        Ogre::Vector3 dir = Ogre::Vector3::ZERO);

        virtual void dumpInfo();

protected:
        /*
         * Gets the id as a string
         */
        virtual Ogre::String getIdString();

        /**
         * A pointer to the SceneManager object to which this object belongs.
         */
         Ogre::SceneManager *m_sceneMgr;

        /**
         * A pointer to the Entity object representing the geometry in the scene graph.
         */
        Ogre::Entity *m_entity;

        /**
         * A pointer to the SceneNode object representing the transforms in the scene graph.
         */
        Ogre::SceneNode *m_node;

        /*
         * This object's unique name.
         */
        Ogre::String m_name;

        /**
         * Indicates the object has been initialized so it can be used in a scene.
         */
        bool m_isInitialized;

        /**
         * Indicates the object is selected.
         */
        bool m_isSelected;

        /**
         * Indicates the direction this object should be moving
         */
        Ogre::Vector3 m_direction;

        /*
         * Get the current position this object was
         */
        Ogre::Vector3 m_position;

        /*
         * Get the previous position this object was
         */
        Ogre::Vector3 m_oldPosition;


        /*
         * A query flag for this type of object
         */
        Ogre::uint32 m_queryFlag;

        /*
         * This object's id.
         */
        unsigned int m_id;

        /*
         * Is the object currently attached to the scene?
         */
        bool m_isInScene;


        /*
         * The speed of this object
         */
        Ogre::Real m_speed;

};

#endif /* GAMEOBJECT_H_ */