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

#include "GameObject.h"
#include <sstream>

#include "Constants.h"
#include "Ball.h"
#include "Block.h"
#include "Wall.h"
#include "Paddle.h"

unsigned int GameObject::s_id = 0;

GameObject::GameObject(): m_sceneMgr(0),
        m_entity(0),
        m_node(0),
        m_name(),
        m_isInitialized(false),
        m_isSelected(false),
        m_direction(0, 0, 0),
        m_oldPosition(0, 0, 0),
        m_queryFlag(0),
        m_speed(0)
{
        m_id = s_id++;
}



void GameObject::init(Ogre::SceneManager *sceneMgr,
                Ogre::String name,
                Ogre::Vector3 position,
                Ogre::String mesh,
                Ogre::String material)
{
        //don't initialize more than once
        if(m_isInitialized)
                return;

        m_sceneMgr = sceneMgr;
        m_isInitialized = true;
        m_name = name;

        //set up the entity
        m_entity = m_sceneMgr->createEntity(name, mesh);

        //set up the scene node
        m_node = m_sceneMgr->getRootSceneNode()->createChildSceneNode(name + "Node");
        m_node->attachObject(m_entity);

        //set the position
        m_position = position;
        m_node->setPosition(m_position);
        m_oldPosition = position;

        //scale to HEIGHT
        Ogre::AxisAlignedBox box = m_entity->getBoundingBox();
        Ogre::Vector3 boxSize = box.getSize();

        //std::cerr << "ORIGINAL SIZE " << boxSize.y << std::endl;

        Ogre::Real scaleAmt = HEIGHT/boxSize.y;
        m_node->scale(scaleAmt, scaleAmt, scaleAmt);


        //std::cerr << "NEW SIZE " << scaleAmt*boxSize.y << std::endl;

        //set the material if any
        if(material != ""){
                m_entity->setMaterialName(material);
        }

        m_isInScene = true;
}

GameObject::~GameObject() {

}

bool GameObject::update(const Ogre::FrameEvent & evt)
{
        //don't do anything if the object has not been initialized
        if(!m_isInitialized){
                return true;
        }

        //at least move this thing
        m_oldPosition = m_node->getPosition();
        m_position = m_oldPosition + (m_direction * m_speed * evt.timeSinceLastFrame);

        //check bounds?

        m_node->setPosition(m_position);

        return true;
}

void GameObject::setDirection(Ogre::Vector3 direction)
{
        m_direction = direction;
}



Ogre::Vector3 & GameObject::getDirection()
{
        return m_direction;
}



bool GameObject::isSelected()
{
        return m_isSelected;
}



bool GameObject::isInitialized()
{
        return m_isInitialized;
}



void GameObject::setSelected(bool select)
{
        m_isSelected = select;
        m_node->showBoundingBox(select);
}

Ogre::String GameObject::getName()
{
        if(!m_isInitialized)
                return "";

        return m_name;
}

Ogre::String GameObject::getEntityName()
{
        if(!m_isInitialized)
                return "";

        return m_entity->getName();
}

Ogre::String GameObject::getNodeName()
{
        if(!m_isInitialized)
                return "";

        return m_node->getName();
}

Ogre::AxisAlignedBox GameObject::getTransformedBoundingBox()
{
        return m_node->_getWorldAABB();
}

void GameObject::stepBack(){
        m_node->setPosition(m_oldPosition);
}

Ogre::uint32 GameObject::getQueryFlag(){
        return m_queryFlag;
}

unsigned int GameObject::getId(){
        return m_id;
}

Ogre::String GameObject::getIdString(){
        std::stringstream sStream;
        sStream << "_" << m_id;
        return Ogre::String(sStream.str());
}

void GameObject::setInScene(bool in){
        //we want to add it and it isn't there
        if(in && !m_isInScene){
                m_sceneMgr->getRootSceneNode()->addChild(m_node);
                m_isInScene = true;
        }
        //we want to remove it and it is there
        else if(!in && m_isInScene){
                m_sceneMgr->getRootSceneNode()->removeChild(m_node);
                m_isInScene = false;

        }
}

bool GameObject::getInScene(){
        return m_isInScene;
}

Ogre::Entity *GameObject::getEntity(){
        return m_entity;
}

Ogre::SceneNode *GameObject::getSceneNode(){
        return m_node;
}

Ogre::Real GameObject::getSpeed(){
        return m_speed;
}

void GameObject::setSpeed(Ogre::Real speed){
        m_speed = speed;
}

void GameObject::collidesWith(GameObject *hit, bool useDir, Ogre::Vector3 dir){
        //std::cerr << "General Collision" << std::endl;
        Ogre::uint32 qFlag = hit->getQueryFlag();
        //if it hits a ball
        if(qFlag == BALL_QUERY_FLAG){
                Ball *ball = static_cast<Ball*>(hit);
                collidesWithBall(ball, useDir, dir);
        }

        //if it is hit by a block/brick
        else if(qFlag == BLOCK_QUERY_FLAG){

                Block *block = static_cast<Block*>(hit);
                collidesWithBlock(block, useDir, dir);
        }

        //if it is hit by any wall
        else if(qFlag & WALL_QUERY_FLAGS){

                Wall *wall = static_cast<Wall*>(hit);
                collidesWithWall(wall, useDir, dir);
        }

        //if it is hit by a paddle
        else if(qFlag == PADDLE_QUERY_FLAG){

                Paddle *paddle = static_cast<Paddle*>(hit);
                collidesWithPaddle(paddle, useDir, dir);
        }

}

void GameObject::collidesWithBall(Ball *hit, bool useDir, Ogre::Vector3 dir){
}

void GameObject::collidesWithWall(Wall *hit, bool useDir, Ogre::Vector3 dir){
}

void GameObject::collidesWithPaddle(Paddle *hit, bool useDir, Ogre::Vector3 dir){
}

void GameObject::collidesWithBlock(Block *hit, bool useDir, Ogre::Vector3 dir){
}


/*
 * Get the objects current position
 */
Ogre::Vector3 GameObject::getPosition(){
        return m_position;
}

void GameObject::setPosition( Ogre::Vector3 pos){
        //m_oldPosition = m_position;
        m_position = pos;
        m_node->setPosition(m_position);
}


void GameObject::dumpInfo(){
        std::cerr << getName() << std::endl;
        std::cerr << "\tNode Name: " << getNodeName() << std::endl;
        std::cerr << "\tEntity Name: " << getEntityName() << std::endl;
        std::cerr << "\tPosition: " << getPosition() << std::endl;
        std::cerr << "\tOld Position: " << m_oldPosition << std::endl;
        std::cerr << "\tDirection: " << getDirection() << std::endl;
        std::cerr << "\tSpeed: " << getSpeed() << std::endl;
        std::cerr << "\tQuery Flag: " << getQueryFlag() << std::endl;

        std::cerr << "---------------------------" << std::endl;
}