/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>

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.
*/

#include "content_cao.h"
#include "inventory.h"
/*
	ItemCAO
*/

class ItemCAO : public ClientActiveObject
{
public:
	ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
		ClientActiveObject(0, gamedef, env),
		m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
		m_node(NULL),
		m_position(v3f(0,10*BS,0))
	{
		if(!gamedef && !env)
		{
			ClientActiveObject::registerType(getType(), create);
		}
	}

	~ItemCAO()
	{
	}

	inline u8 getType() const
	{	return ACTIVEOBJECT_TYPE_ITEM;	}

	static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
	{
		return new ItemCAO(gamedef, env);
	}

	void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
				IrrlichtDevice *irr)
	{
		if(m_node != NULL)
			return;

		//video::IVideoDriver* driver = smgr->getVideoDriver();

		scene::SMesh *mesh = new scene::SMesh();
		scene::IMeshBuffer *buf = new scene::SMeshBuffer();
		video::SColor c(255,255,255,255);
		video::S3DVertex vertices[4] =
		{
			/*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
			video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
			video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
			video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
			video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
			video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
			video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
			video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
		};
		u16 indices[] = {0,1,2,2,3,0};
		buf->append(vertices, 4, indices, 6);
		// Set material
		buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
		buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
		// Initialize with a generated placeholder texture
		buf->getMaterial().setTexture(0, tsrc->getTextureRaw(""));
		buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
		buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
		buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
		// Add to mesh
		mesh->addMeshBuffer(buf);
		buf->drop();
		m_node = smgr->addMeshSceneNode(mesh, NULL);
		mesh->drop();
		// Set it to use the materials of the meshbuffers directly.
		// This is needed for changing the texture in the future
		m_node->setReadOnlyMaterials(true);
		updateNodePos();

		/*
			Update image of node
		*/

		// Create an inventory item to see what is its image
		std::istringstream is(m_inventorystring, std::ios_base::binary);
		video::ITexture *texture = NULL;
		try{
			InventoryItem *item = NULL;
			item = InventoryItem::deSerialize(is, m_gamedef);
			infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
					<<m_inventorystring<<"\" -> item="<<item
					<<std::endl;
			if(item)
			{
				texture = item->getImage();
				delete item;
			}
		}
		catch(SerializationError &e)
		{
			infostream<<"WARNING: "<<__FUNCTION_NAME
					<<": error deSerializing inventorystring \""
					<<m_inventorystring<<"\""<<std::endl;
		}

		// Set meshbuffer texture
		buf->getMaterial().setTexture(0, texture);
	}

	void removeFromScene()
	{
		if(m_node == NULL)
			return;

		m_node->remove();
		m_node = NULL;
	}

	void updateLight(u8 light_at_pos)
	{
		if(m_node == NULL)
			return;

		u8 li = decode_light(light_at_pos);
		video::SColor color(255,li,li,li);
		setMeshColor(m_node->getMesh(), color);
	}

	v3s16 getLightPosition()
	{
		return floatToInt(m_position, BS);
	}

	void updateNodePos()
	{
		if(m_node == NULL)
			return;

		m_node->setPosition(m_position);
	}

	void step(float dtime, ClientEnvironment *env)
	{
		if(m_node)
		{
			/*v3f rot = m_node->getRotation();
			rot.Y += dtime * 120;
			m_node->setRotation(rot);*/
			LocalPlayer *player = env->getLocalPlayer();
			assert(player);
			v3f rot = m_node->getRotation();
			rot.Y = 180.0 - (player->getYaw());
			m_node->setRotation(rot);
		}
	}

	void processMessage(const std::string &data)
	{
		//infostream<<"ItemCAO: Got message"<<std::endl;
		std::istringstream is(data, std::ios::binary);
		// command
		u8 cmd = readU8(is);
		if(cmd == AO_Message_type::SetPosition)
		{
			// pos
			m_position = readV3F1000(is);
			updateNodePos();
		}
	}

	void initialize(const std::string &data)
	{
		infostream<<"ItemCAO: Got init data"<<std::endl;

		{
			std::istringstream is(data, std::ios::binary);
			// version
			u8 version = readU8(is);
			// check version
			if(version != 0)
				return;
			// pos
			m_position = readV3F1000(is);
			// inventorystring
			m_inventorystring = deSerializeString(is);
		}

		updateNodePos();

		/*
			Set infotext to item name if item cannot be deserialized
		*/
		try{
			InventoryItem *item = NULL;
			item = InventoryItem::deSerialize(m_inventorystring, m_gamedef);
			if(item){
				if(!item->isKnown())
					m_infotext = "Unknown item: '" + m_inventorystring + "'";
			}
			delete item;
		}
		catch(SerializationError &e)
		{
			m_infotext = "Unknown item: '" + m_inventorystring + "'";
		}
	}
	core::aabbox3d<f32>* getSelectionBox()
		{return &m_selection_box;}
	v3f getPosition()
		{return m_position;}

	std::string infoText()
		{return m_infotext;}

private:
	core::aabbox3d<f32> m_selection_box;
	scene::IMeshSceneNode *m_node;
	v3f m_position;
	std::string m_inventorystring;
	std::string m_infotext;
};

// Prototype
ItemCAO proto_ItemCAO(NULL, NULL);
