map<uint, terrainFactory> setFactories(Poco::XML::Node* node)
{
	using namespace Poco;

	map<uint, terrainFactory> factories;
	
	XML::NodeIterator childIterator(node, XML::NodeFilter::SHOW_ELEMENT);
	XML::Node* tileNode = childIterator.nextNode();
	while (tileNode)
	{
		if (tileNode->nodeName() == "tile")
		{
			ScopedNamedNodeMap tileAttributes(tileNode->attributes());

			stringstream id(tileAttributes->getNamedItem("id")->getNodeValue());
			uint tileId = 0;
			id >>tileId;

			auto propertiesNode = tileNode->firstChild()->nextSibling();
			auto propertyNode = propertiesNode->firstChild()->nextSibling();
			if (propertyNode->hasAttributes())
			{
				ScopedNamedNodeMap attributes(propertyNode->attributes());
				setFactory(factories, tileId, attributes->getNamedItem("value")->nodeValue());
			}
			else
			{
				throw FileFormatException("TMX file malformed: tile>>properties should have a child, but does not.");
			}
		}
		
		tileNode = childIterator.nextNode();
	}
GameMap::UniquePtr TiledMapParser::parse()
{
	using namespace Poco;

	loadMapImages(fileInfo);
	
	ifstream in(Constants::MapPath + fileInfo.getTmxFileName());
	if (!in.good())
	{
		throw FileLoadException("Unable to load the Tiled tmx file: " + Constants::MapPath + fileInfo.getTmxFileName());
	}

	XML::InputSource src(in);
	
	XML::DOMParser parser;
	AutoPtr<XML::Document> doc = parser.parse(&src);

	MapProperties properties;
	std::map<uint, terrainFactory> terrainFactories;

	GameMap::NavGraphList navGraph;

	XML::NodeIterator iterator(doc, XML::NodeFilter::SHOW_ELEMENT);
	XML::Node* node = iterator.nextNode();
	while (node)
	{
		if (node->nodeName() == "map")
		{
			if (!node->hasAttributes()) throw FileFormatException("The Tiled map file is formatted incorrectly: there are no map attributes.");

			// Load the properties.
			properties = processMapProperties(node);
		
			ScopedNodeList childNodes = node->childNodes();
			for (int i = 0; i < childNodes->length(); ++i)
			{
				auto childNode = childNodes->item(i);
				if (childNode->nodeName() == "tileset")
				{
					terrainFactories = setFactories(childNode);
				}
				else if (childNode->nodeName() == "layer")
				{
					processTerrain(navGraph, terrainFactories, childNode, properties);
				}
			}
		}
		else
		{
			// Postconditions:
			Assert<FileFormatException>(properties.rows != 0, "Properties not loaded from Tiled map file.");
			Assert<FileFormatException>(!navGraph.empty(), "NavGraph not loaded from Tiled map file.");

			// Everything has been processed, so no need to continue iteration.
			break;
		}

		node = iterator.nextNode();
	}

	GameMap::UniquePtr gameMap = make_unique<GameMap>(properties.rows, properties.columns, 
			properties.tileHeight, properties.tileWidth, move(navGraph));
	return move(gameMap);
}