/*
	OgreNewt library - connecting Ogre and Newton!

	Demo09_PlayerController
*/
#include "OgreNewtonApplication.h"
#include "OgreNewtonFrameListener.h"

#include <OgreNewt.h>
#include <OgreNewt_BasicFrameListener.h>


OgreNewtonApplication::OgreNewtonApplication(void)
{
	// create OgreNewt world.
	m_World = new OgreNewt::World();
    mPlayer = NULL;

	mEntityCount = 0;

}

OgreNewtonApplication::~OgreNewtonApplication(void)
{
	// destroy world.
    if( mPlayer )
        delete mPlayer;
	delete m_World;
}



void OgreNewtonApplication::createScene()
{
/*
	// setup CEGUI
	mGUIRenderer = new CEGUI::OgreCEGUIRenderer( mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr );
	new CEGUI::System( mGUIRenderer );

	// load up CEGUI stuff...
	try
	{
		using namespace CEGUI;
		CEGUI::Logger::getSingleton().setLoggingLevel( CEGUI::Informative );

		CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
        CEGUI::System::getSingleton().setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
        CEGUI::System::getSingleton().setDefaultFont((CEGUI::utf8*)"BlueHighway-10");

		CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton().createWindow( (CEGUI::utf8*)"DefaultWindow", (CEGUI::utf8*)"root_wnd" );
		CEGUI::System::getSingleton().setGUISheet( sheet );

		//makeGUI();
		//setupGUI();
	
	}
	catch (CEGUI::Exception)
	{}
*/

	// sky box.
	mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
	
	// shadows on!
	mSceneMgr->setShadowTechnique( Ogre::SHADOWTYPE_STENCIL_ADDITIVE );


	// floor object!
	Entity* floor;
	SceneNode* floornode;

//	const char *levelName = "simple_terrain.mesh";
//	const char *levelName = "castle.mesh";
	const char *levelName = "chiropteradm.mesh";
//	const char *levelName = "playground.mesh";

	floor = mSceneMgr->createEntity("Floor", levelName );
	
	floornode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "FloorNode" );
	floornode->attachObject( floor );
	floor->setCastShadows( false );


	//Ogre::Vector3 siz(100.0, 10.0, 100.0);
	char serializeCollisionName[256];
	strcpy (serializeCollisionName, levelName);
	strtok (serializeCollisionName, ".");
	strcat (serializeCollisionName, ".col");

	FILE* file = fopen (serializeCollisionName, "rb");
	if (!file) {
		// serialize the mesh so that next time loads faster
		OgreNewt::CollisionSerializer saveLevelCollision; 
		OgreNewt::CollisionPtr tmpSphape = OgreNewt::CollisionPtr(new OgreNewt::CollisionPrimitives::TreeCollision( m_World, floor, true, 0 ));
		saveLevelCollision.exportCollision(tmpSphape, serializeCollisionName);
		file = fopen (serializeCollisionName, "rb");
	}
	
	// load level collision from serialized file
	FileHandleDataStream streamFile (file);
	OgreNewt::CollisionSerializer loadLevelCollision; 
	OgreNewt::CollisionPtr col = loadLevelCollision.importCollision(streamFile, m_World);
	fclose (file);

	OgreNewt::Body* bod = new OgreNewt::Body( m_World, col );
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
	delete col;
#endif
	
	//floornode->setScale( siz );
	bod->attachNode( floornode );
	bod->setPositionOrientation( Ogre::Vector3(0.0f, 0.0f, 0.0f), Ogre::Quaternion::IDENTITY );

    makePlayer();

	// position camera
	mCamera->setPosition(0.0f, 1.0f, 0.0f);
	

	// set the near and far clip plane
	mCamera->setNearClipDistance(0.2f);
	mCamera->setFarClipDistance(1000.0f);


	//make a light
	Ogre::Light* light;

	light = mSceneMgr->createLight( "Light1" );
	light->setType( Ogre::Light::LT_POINT );
	light->setPosition( Ogre::Vector3(0.0, 100.0, 100.0) );
}


void OgreNewtonApplication::createFrameListener()
{
	// It is important that the Physics update is updated before anything
	mNewtonListener = new OgreNewt::BasicFrameListener( mWindow, m_World, 100 );
	mRoot->addFrameListener(mNewtonListener);

	mFrameListener = new OgreNewtonFrameListener( mWindow, mCamera, mSceneMgr, m_World, mPlayer);
	mRoot->addFrameListener(mFrameListener);

}

void OgreNewtonApplication::destroyScene()
{
/*
	CEGUI::System* sys = CEGUI::System::getSingletonPtr();
	delete sys;

	// CEGUI Cleanup
	delete mGUIRenderer;
*/
}


OgreNewt::Body* OgreNewtonApplication::makeSimpleBox( const Ogre::Vector3& size, const Ogre::Vector3& pos, const Ogre::Quaternion& orient )
{
	Entity* box1;
	SceneNode* box1node;

	box1 = mSceneMgr->createEntity( "Entity"+Ogre::StringConverter::toString(mEntityCount++), "box.mesh" );
	box1node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	box1node->attachObject( box1 );
	box1node->setScale( size );

	OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Box( m_World, size, 0 ));
	OgreNewt::Body* bod = new OgreNewt::Body( m_World, col );


	// base mass on the size of the object.
	Ogre::Real mass = size.x * size.y * size.z * 2.5;
	// calculate the inertia based on box formula and mass
	Ogre::Vector3 inertia, offset;
    col->calculateInertialMatrix(inertia, offset);

#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
	delete col;
#endif
				
	bod->attachNode( box1node );
	bod->setMassMatrix( mass, mass*inertia );
    bod->setCenterOfMass(offset);
	bod->setStandardForceCallback();

	box1->setMaterialName( "Simple/BumpyMetal" );


	bod->setPositionOrientation( pos, orient );

	return bod;
}

void OgreNewtonApplication::makePlayer()
{
    Entity* ellipsoid;
    SceneNode* node;

    ellipsoid = mSceneMgr->createEntity( "PlayerControllerEntity", "ellipsoid.mesh");
    node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    node->attachObject( ellipsoid );
	Ogre::Vector3 size (1.0f, 2.5f, 1.0f);
    node->setScale(size);
    
    OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Ellipsoid( m_World, size * 0.5f, 0 ));
    OgreNewt::Body* bod = new OgreNewt::Body( m_World, col );
    Ogre::Vector3 inertia, offset;
    col->calculateInertialMatrix(inertia, offset);
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
	delete col;
#endif
    bod->attachNode(node);
    bod->setMassMatrix( 50, 50*inertia );
    bod->setCenterOfMass(offset);
    bod->setStandardForceCallback();

    ellipsoid->setMaterialName("Simple/dirt01");

//  bod->setPositionOrientation(Ogre::Vector3(0,20,20), Ogre::Quaternion::IDENTITY);
//	bod->setPositionOrientation(Ogre::Vector3(6.74f, -6.0f, -8.2f), Ogre::Quaternion::IDENTITY);
	bod->setPositionOrientation(Ogre::Vector3(0.0f, 1.0f, 0.0f), Ogre::Quaternion::IDENTITY);

	// set teh play to alway be actibe
	bod->setAutoSleep(0);
    mPlayer = new OgreNewt::PlayerController(bod, 0.4);

}