#include <iostream>
#include <Ogre.h>
#include <OgreCodec.h>
#include <OgreFileSystem.h>
#include <OgreFileSystemLayer.h>
#include <OgreMaterialManager.h>
#include <OgreShaderGenerator.h>

static void getSubmeshUVs(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
			  std::vector<Ogre::Vector2> &uvs, int index)
{
	int j;
	float *pReal;
	Ogre::HardwareVertexBufferSharedPtr vbuf;
	Ogre::VertexData *vertex_data = submesh->useSharedVertices ?
						mesh->sharedVertexData :
						submesh->vertexData;
	const Ogre::VertexElement *uvElem =
		vertex_data->vertexDeclaration->findElementBySemantic(
			Ogre::VES_TEXTURE_COORDINATES, index);
	int vertex_count = 0;
	if (submesh->useSharedVertices)
		vertex_count += mesh->sharedVertexData->vertexCount;
	else
		vertex_count += submesh->vertexData->vertexCount;
	if (!uvElem)
		return;
	OgreAssert(uvs.size() == 0 || uvs.size() == vertex_count,
		   "bad vertex count");
	uvs.resize(vertex_count);
	vbuf = vertex_data->vertexBufferBinding->getBuffer(uvElem->getSource());
	unsigned char *uv = static_cast<unsigned char *>(
		vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	for (j = 0; j < vertex_data->vertexCount; ++j) {
		uvElem->baseVertexPointerToElement(uv, &pReal);
		uvs[j] = Ogre::Vector2(pReal[0], pReal[1]);
		uv += vbuf->getVertexSize();
	}
	vbuf->unlock();
}

int main()
{
	Ogre::LogManager logMgr;
	logMgr.createLog("messages.log", true, true, true);
	Ogre::DefaultHardwareBufferManager bufferManager; // needed because we don't have a rendersystem
	Ogre::Root *ogre = new Ogre::Root("", "", "");
	Ogre::ConfigFile pluginsCfg;
	Ogre::FileSystemLayer fsLayer("Ogre3D");
	pluginsCfg.load(fsLayer.getConfigFilePath("plugins.cfg"));

	auto pluginDir = Ogre::FileSystemLayer::resolveBundlePath(pluginsCfg.getSetting("PluginFolder")+"/");
	ogre->loadPlugin(pluginDir + "/Codec_Assimp");
	Ogre::MaterialManager::getSingleton().initialise();
	Ogre::RTShader::ShaderGenerator::initialize();
	Ogre::DefaultTextureManager texMgr;

        auto& shadergen = Ogre::RTShader::ShaderGenerator::getSingleton();
        shadergen.setTargetLanguage("glsl"); // must be valid, but otherwise arbitrary
        shadergen.getRenderState(Ogre::MSN_SHADERGEN)->setLightCountAutoUpdate(false);
        shadergen.validateScheme(Ogre::MSN_SHADERGEN);

        auto codec = Ogre::Codec::getCodec("glb");

	Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
			"Characters", true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
			"characters", "FileSystem", "Characters", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
			"../characters", "FileSystem", "Characters", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
			"../../characters", "FileSystem", "Characters", true, true);
	Ogre::DataStreamPtr meshData = Ogre::ResourceGroupManager::getSingleton().openResource("shapes/male/edited-normal-male-base.glb", "Characters");
	Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual("shapes/male/edited-normal-male-base.glb", "Characters");
	codec->decode(meshData, mesh.get());
	std::vector<Ogre::Vector2> uvs;
	getSubmeshUVs(mesh.get(), mesh->getSubMesh(0), uvs, 0);
	std::cout << "UV0: " << uvs.size() << std::endl;
	uvs.clear();
	getSubmeshUVs(mesh.get(), mesh->getSubMesh(0), uvs, 1);
	std::cout << "UV1: " << uvs.size() << std::endl;
	return 0;
}
