/*
 Copyright (C) 2013 Erik Ogenvik

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software Foundation,
 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef EMBERTERRAIN_H_
#define EMBERTERRAIN_H_

#include "components/ogre/TerrainPageDataProvider.h"

#include <OgreTerrain.h>

#include <sigc++/signal.h>
#include <functional>

namespace Ember
{
namespace OgreView
{
namespace Terrain
{

/**
 * @brief Mainly used to override the default behaviour of Ogre::Terrain.
 *
 * This to better fit the way we handle materials (since we don't use the default materials
 * as generated by the Ogre::Terrain classes).
 */
class EmberTerrain: public Ogre::Terrain
{
public:

	/**
	 * @brief Ctor.
	 * @param unloader An unloader function, called upon destruction.
	 * @param sm
	 */
	EmberTerrain(std::function<void()>& unloader,
				 Ogre::SceneManager* sm,
				 sigc::signal<void, Ogre::TRect<Ogre::Real>>& terrainAreaUpdatedSignal,
				 sigc::signal<void, const Ogre::TRect<Ogre::Real>>& terrainShownSignal,
				 Ogre::TerrainMaterialGeneratorPtr materialGenerator);

	~EmberTerrain() override;

	/**
	 * Specifies the index of this page in the paging component.
	 * @param index The paging specific index.
	 */
	void setIndex(const IPageDataProvider::OgreIndex& index);

	/**
	 * @brief Gets the index of the page in the paging component.
	 * @return The index of the page.
	 */
	const IPageDataProvider::OgreIndex& getIndex() const;

	bool canHandleRequest(const Ogre::WorkQueue::Request* req, const Ogre::WorkQueue* srcQ) override;
	Ogre::WorkQueue::Response* handleRequest(const Ogre::WorkQueue::Request* req, const Ogre::WorkQueue* srcQ) override;
	bool canHandleResponse(const Ogre::WorkQueue::Response* res, const Ogre::WorkQueue* srcQ) override;
	void handleResponse(const Ogre::WorkQueue::Response* res, const Ogre::WorkQueue* srcQ) override;

	/**
	 * @brief Regenerates the material used by the page.
	 */
	void regenerateMaterial();

	/**
	 * Schedule a geometry update, using background workers.
	 * @param heightData
	 */
	void scheduleGeometryUpdate(std::shared_ptr<float> heightData);

protected:

	static const Ogre::uint16 WORKQUEUE_GEOMETRY_UPDATE_REQUEST;

	struct GeometryUpdateRequest
	{
		EmberTerrain* terrain;
		std::shared_ptr<float> heightData;
		//Rect dirtyRect;
		friend std::ostream& operator<<(std::ostream& o, const GeometryUpdateRequest& r)
		{ return o; }
	};

	/**
	 * @brief An unloader function, called upon destruction.
	 */
	std::function<void()> mUnloader;

	/**
	 * @brief The index of the page in the paging component.
	 */
	IPageDataProvider::OgreIndex mIndex;

	/**
	 * @brief Signal emitted when an area of the terrain has been updated.
	 * The argument is the area (in world coordinates) that was updated.
	 */
	sigc::signal<void, Ogre::TRect<Ogre::Real>> mTerrainAreaUpdatedSignal;

	/**
	 * @brief Signal emitted when a page has been shown for the first time.
	 * The argument is the area (in world coordinates) that was shown.
	 */
	sigc::signal<void, const Ogre::TRect<Ogre::Real>> mTerrainShownSignal;


};

}
}
}
#endif /* EMBERTERRAIN_H_ */
