// This file is part of ThriceBall.
//
// Author: Kai Hillenbrand (AnTeevY)
// © Copyright, 2009 by Kai Hillenbrand, http://www.anteevy.de

// --------------------------------------------------

#pragma once
#ifndef BASEFRAMELISTENER_H
#define BASEFRAMELISTENER_H

#define OIS_DYNAMIC_LIB

// extern includes
#include "Ogre.h"
#include "OgreStringConverter.h"
#include "OgreException.h"
#include "OIS/OIS.h"

// --------------------------------------------------

using namespace Ogre;

class CBaseFrameListener: public FrameListener, public WindowEventListener
{
protected:
	void updateStats(void)
	{
		static String currFps = "Current FPS: ";
		static String avgFps = "Average FPS: ";
		static String bestFps = "Best FPS: ";
		static String worstFps = "Worst FPS: ";
		static String tris = "Triangle Count: ";
		static String batches = "Batch Count: ";

		// update stats when necessary
		try {
			OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
			OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
			OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
			OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");

			const RenderTarget::FrameStats& stats = m_pWindow->getStatistics();
			guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
			guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
			guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
				+" "+StringConverter::toString(stats.bestFrameTime)+" ms");
			guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
				+" "+StringConverter::toString(stats.worstFrameTime)+" ms");

			OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
			guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));

			OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
			guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));

			OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
			guiDbg->setCaption(m_sDebugText);
		}
		catch(...) { /* ignore */ }
	}

public:
	CBaseFrameListener(RenderWindow* win, bool bufferedKeys = false, bool bufferedMouse = false,
			     bool bufferedJoy = false ) :
		m_pWindow(win), m_pDebugOverlay(0), m_pInputManager(0), m_pMouse(0), m_pKeyboard(0)
	{
		using namespace OIS;

		m_pDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");

		// create OIS input
		LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
		ParamList pl;
		size_t windowHnd = 0;
		std::ostringstream windowHndStr;

		win->getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;
		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

		m_pInputManager = InputManager::createInputSystem( pl );

		// create all devices
		m_pKeyboard = static_cast<Keyboard*>(m_pInputManager->createInputObject( OISKeyboard, bufferedKeys ));
		m_pMouse = static_cast<Mouse*>(m_pInputManager->createInputObject( OISMouse, bufferedMouse ));
		
		windowResized(m_pWindow);	// set initial mouse clipping size
		showDebugOverlay(false);	// hide the debug overlay
		WindowEventUtilities::addWindowEventListener(m_pWindow, this);	// register as a Window listener
	}

	// adjust mouse clipping area
	virtual void windowResized(RenderWindow* rw)
	{
		unsigned int width, height, depth;
		int left, top;
		rw->getMetrics(width, height, depth, left, top);

		const OIS::MouseState &ms = m_pMouse->getMouseState();
		ms.width = width;
		ms.height = height;
	}

	// unattach OIS before window shutdown (very important under Linux)
	virtual void windowClosed(RenderWindow* rw)
	{
		// only close for window that created OIS (the main window in these demos)
		if(rw == m_pWindow)
		{
			if(m_pInputManager)
			{
				m_pInputManager->destroyInputObject(m_pMouse);
				m_pInputManager->destroyInputObject(m_pKeyboard);
				m_pMouse = 0;
				m_pKeyboard = 0;

				OIS::InputManager::destroyInputSystem(m_pInputManager);
				m_pInputManager = 0;
			}
		}
	}

	virtual ~CBaseFrameListener()
	{
		// remove ourself as a Window listener
		WindowEventUtilities::removeWindowEventListener(m_pWindow, this);
		windowClosed(m_pWindow);

		m_pMouse = 0;
		m_pKeyboard = 0;
	}

	void showDebugOverlay(bool show)
	{
		if (m_pDebugOverlay)
		{
			if (show)
				m_pDebugOverlay->show();
			else
				m_pDebugOverlay->hide();
		}
	}

	bool frameStarted(const FrameEvent& evt){return true;}					// done by CFrameListener
	bool frameEnded(const FrameEvent& evt){updateStats(); return true;}

	// own functions which will be overwritten by CFrameListener
	virtual void setVisDebData(NxOgre::VisualDebugger* visDeb, Ogre::SceneNode* visDebNode){}

protected:
	// OGRE variables
	RenderWindow* m_pWindow;
	Overlay* m_pDebugOverlay;
	std::string m_sDebugText;	

	// OIS Input devices
	OIS::InputManager	*m_pInputManager;
	OIS::Mouse			*m_pMouse;
	OIS::Keyboard		*m_pKeyboard;
};

#endif
