/*
 * CollisionApp.cpp
 *
 *  Created on: Feb 12, 2011
 *      Author: cpresser
 */

#include "CollisionApp.h"

//-------------------------------------------------------------------------------------
CollisionApp::CollisionApp(void):
        mSelected(0),
        mRayQuery(0),
        mBoxQuery(0)
{
}

//-------------------------------------------------------------------------------------
CollisionApp::~CollisionApp(void)
{
        if(!mRayQuery)
                mSceneMgr->destroyQuery(mRayQuery);

        if(!mBoxQuery)
                mSceneMgr->destroyQuery(mBoxQuery);

}

//override configure, so we don't need the dialog anymore.
bool CollisionApp::configure(){

        //check if there is a good configuration file
        if(!mRoot->restoreConfig()){
        //if not, show the dialog
                if(!mRoot->showConfigDialog()){
                        //the user hits cancel..
                        //quit
                        return false;
                }
        }

    // Here we choose to let the system create a default rendering window by passing 'true'
    mWindow = mRoot->initialise(true, "Collision Demonstration");
    return true;
}


//-------------------------------------------------------------------------------------
void CollisionApp::createScene(void)
{
        mSceneMgr->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25));


        // create the light
        Ogre::Light *light = mSceneMgr->createLight("Light1");
        light->setType(Ogre::Light::LT_POINT);
        light->setPosition(Ogre::Vector3(0, 150, 250));
        light->setDiffuseColour(Ogre::ColourValue::White);
        light->setSpecularColour(Ogre::ColourValue::White);

        // Create the floor
    //build a ground
    Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -50);
    Ogre::MeshManager::getSingleton().createPlane("Ground",
                Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                plane, LENGTH, LENGTH, 20, 20, true, 1, LENGTH/128, LENGTH/128, Ogre::Vector3::UNIT_Z);

    Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "Ground");
    Ogre::SceneNode *groundNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("GroundNode");
    groundNode->attachObject(entGround);

    entGround->setMaterialName("Examples/BeachStones");


        // add the cube
        Ogre::Entity *ent = mSceneMgr->createEntity("Cube", "cube.mesh");

    //create our own texture for this object

        //Create a MaterialPtr object
        Ogre::MaterialPtr renderMaterial = Ogre::MaterialManager::getSingleton().create("RedMat",
                        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

        Ogre::Material *material = renderMaterial.getPointer();
        //set the diffuse color (r, g, b, alpha)
        //I'm missing something for transparency to work
        material->setDiffuse(1, 0, 0, 1);

        //set the material for the entity
        ent->setMaterial(renderMaterial);

        //set up scene node for the cube
        Ogre::SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("CubeNode");
        node->attachObject(ent);
        node->scale(0.125, 0.125, 0.125);
        node->setPosition(0, 0, -100);


    //add a GameObject or two
    GameObject obj1;
    obj1.init(mSceneMgr, "Object1", Ogre::Vector3(20, 0, -100), "sphere.mesh",
                "Examples/Chrome");

    mMap["Object1"] = obj1;

    GameObject obj2;
    obj2.init(mSceneMgr, "Object2", Ogre::Vector3(-20, 0, -100), "ninja.mesh");


    mMap["Object2"] = obj2;


    //add a whole bunch of objects
    int n = 0;
    for(int i = 0; i < 5; i++){
        for(int j = 0; j < 5; j++){
                //make a name (append a number to a string using a string stream)
                std::stringstream sstr;
                sstr << "GridObject" << n;
                n++;

                Ogre::String name = sstr.str();

                GameObject objN;
                objN.init(mSceneMgr, name, Ogre::Vector3(i*20 - 50, j*20, -200),
                                "cube.mesh", "Examples/Rocky");

                mMap[name] = objN;
        }
    }
}
void CollisionApp::createFrameListener(void){
        BaseApplication::createFrameListener();

        //remove Ogre GUI elements
        mTrayMgr->hideFrameStats();
        mTrayMgr->hideLogo();

        //show the cursor
        mTrayMgr->showCursor();


        // Populate the camera container
        //mCamNode = mCamera->getParentSceneNode();

        // set the rotation and move speed
        mRotate = 0.13;
        mMove = SPEED;

        mMouse->setEventCallback(this);
        mKeyboard->setEventCallback(this);

        mDirection = Ogre::Vector3::ZERO;

        //Add scene query code here

}

bool CollisionApp::frameRenderingQueued(const Ogre::FrameEvent& evt){
        if (mWindow->isClosed())
                return false;
        if (mShutDown)
                return false;

        mKeyboard->capture();
        mMouse->capture();
        mTrayMgr->frameRenderingQueued(evt);


        //update the camera, man.
        mCameraMan->frameRenderingQueued(evt);


        //Add scene query code here



        //update them all
        //we probably only need to update the selected ones, but this will work
        std::map<Ogre::String, GameObject>::iterator it;
        for(it = mMap.begin(); it != mMap.end(); it++){
                (*it).second.update(evt);
        }
        return true;
}


// OIS::KeyListener
bool CollisionApp::keyPressed( const OIS::KeyEvent& evt ){

    switch (evt.key)
    {
    case OIS::KC_ESCAPE:
        mShutDown = true;
        break;
    case OIS::KC_I:
        mDirection.z = -mMove;
        break;

    case OIS::KC_K:
        mDirection.z = mMove;
        break;

    case OIS::KC_J:
        mDirection.x = -mMove;
        break;

    case OIS::KC_L:
        mDirection.x = mMove;
        break;

    case OIS::KC_U:
        mDirection.y = mMove;
        break;

    case OIS::KC_O:
        mDirection.y = -mMove;
        break;

    default:
        break;
    }
    //set the direction for  selected object
    if(mSelected){
        mSelected->setDirection(mDirection);
    }

    mCameraMan->injectKeyDown(evt);
        return true;
}


bool CollisionApp::keyReleased( const OIS::KeyEvent& evt ){

        switch (evt.key)
        {
        case OIS::KC_I:
            mDirection.z = 0;
            break;

        case OIS::KC_K:
            mDirection.z = 0;
            break;

        case OIS::KC_J:
            mDirection.x = 0;
            break;

        case OIS::KC_L:
            mDirection.x = 0;
            break;

    case OIS::KC_U:
        mDirection.y = 0;
        break;

    case OIS::KC_O:
        mDirection.y = 0;
        break;


        default:
            break;
        }


    //set the direction for  selected object
    if(mSelected){
        mSelected->setDirection(mDirection);
    }

    mCameraMan->injectKeyUp(evt);
        return true;
}

// OIS::MouseListener
bool CollisionApp::mouseMoved( const OIS::MouseEvent& evt ){
        if (evt.state.buttonDown(OIS::MB_Right))
        {

            mCameraMan->injectMouseMove(evt);
        }
        mTrayMgr->injectMouseMove(evt);

        return true;
}

bool CollisionApp::mousePressed( const OIS::MouseEvent& evt, OIS::MouseButtonID id ){

        //get the object that was clicked

        if (evt.state.buttonDown(OIS::MB_Right))
        {
                mCameraMan->injectMouseDown(evt, id);
        }

    mTrayMgr->injectMouseDown(evt, id);
        return true;
}

bool CollisionApp::mouseReleased( const OIS::MouseEvent& evt, OIS::MouseButtonID id ){
        if (evt.state.buttonDown(OIS::MB_Right))
        {
                mCameraMan->injectMouseUp(evt, id);
        }
        //add scene query code here

    mTrayMgr->injectMouseUp(evt, id);
        return true;
}



#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char *argv[])
#endif
{
        // Create application object
        CollisionApp app;

        try {
                app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
                MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
                std::cerr << "An exception has occurred: " <<
                                e.getFullDescription().c_str() << std::endl;
#endif
        }

        return 0;
}

#ifdef __cplusplus
}
#endif