//-----------------------------------------------------------------------------
// <ManufacturerSpecific::LoadProductXML>
// Load the XML that maps manufacturer and product IDs to human-readable names
//-----------------------------------------------------------------------------
bool ManufacturerSpecific::LoadProductXML
(
)
{
	s_bXmlLoaded = true;

	// Parse the Z-Wave manufacturer and product XML file.
	string configPath;
	Options::Get()->GetOptionAsString( "ConfigPath", &configPath );

	string filename =  configPath + "manufacturer_specific.xml";

	TiXmlDocument* pDoc = new TiXmlDocument();
	if( !pDoc->LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
	{
		delete pDoc;
		Log::Write( LogLevel_Info, "Unable to load %s", filename.c_str() );
		return false;
	}

	TiXmlElement const* root = pDoc->RootElement();

	char const* str;
	char* pStopChar;

	TiXmlElement const* manufacturerElement = root->FirstChildElement();
	while( manufacturerElement )
	{
		str = manufacturerElement->Value();
		if( str && !strcmp( str, "Manufacturer" ) )
		{
			// Read in the manufacturer attributes
			str = manufacturerElement->Attribute( "id" );
			if( !str )
			{
				Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer id attribute", manufacturerElement->Row() );
				delete pDoc;
				return false;
			}
			uint16 manufacturerId = (uint16)strtol( str, &pStopChar, 16 );

			str = manufacturerElement->Attribute( "name" );
			if( !str )
			{
				Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer name attribute", manufacturerElement->Row() );
				delete pDoc;
				return false;
			}

			// Add this manufacturer to the map
			s_manufacturerMap[manufacturerId] = str;

			// Parse all the products for this manufacturer
			TiXmlElement const* productElement = manufacturerElement->FirstChildElement();
			while( productElement )
			{
				str = productElement->Value();
				if( str && !strcmp( str, "Product" ) )
				{
					str = productElement->Attribute( "type" );
					if( !str )
					{
						Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product type attribute", productElement->Row() );
						delete pDoc;
						return false;
					}
					uint16 productType = (uint16)strtol( str, &pStopChar, 16 );

					str = productElement->Attribute( "id" );
					if( !str )
					{
						Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product id attribute", productElement->Row() );
						delete pDoc;
						return false;
					}
					uint16 productId = (uint16)strtol( str, &pStopChar, 16 );

					str = productElement->Attribute( "name" );
					if( !str )
					{
						Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product name attribute", productElement->Row() );
						delete pDoc;
						return false;
					}
					string productName = str;

					// Optional config path
					string configPath;
					str = productElement->Attribute( "config" );
					if( str )
					{
						configPath = str;
					}

					// Add the product to the map
					Product* product = new Product( manufacturerId, productType, productId, productName, configPath );
					if ( s_productMap[product->GetKey()] != NULL )
					{
						Product *c = s_productMap[product->GetKey()];
						Log::Write( LogLevel_Info, "Product name collision: %s type %x id %x manufacturerid %x, collides with %s, type %x id %x manufacturerid %x", productName.c_str(), productType, productId, manufacturerId, c->GetProductName().c_str(), c->GetProductType(), c->GetProductId(), c->GetManufacturerId());
						delete product;
					}
					else
					{
						s_productMap[product->GetKey()] = product;
					}
				}

				// Move on to the next product.
				productElement = productElement->NextSiblingElement();
			}
		}

		// Move on to the next manufacturer.
		manufacturerElement = manufacturerElement->NextSiblingElement();
	}

	delete pDoc;
	return true;
}