gui: type safe resources part 2

- separate collections for fonts, images, animations
- no more ugly casts
- fix crash if main ui.xml did not define any resources but include did
- don't stop loading resources if one "type" attribute is missing

Change-Id: I70c1c9ca66ca65d9fba1ba3eded34f3d8a07488e
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 18ddf9c..cd5e340 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -208,8 +208,7 @@
 	if (name.empty())
 		return NULL;
 	else
-		return (FontResource*) PageManager::FindResource(name);
-	// TODO: make resource lookup type-safe
+		return PageManager::GetResources()->FindFont(name);
 }
 
 ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
@@ -218,8 +217,7 @@
 	if (name.empty())
 		return NULL;
 	else
-		return (ImageResource*) PageManager::FindResource(name);
-	// TODO: make resource lookup type-safe
+		return PageManager::GetResources()->FindImage(name);
 }
 
 AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
@@ -228,8 +226,7 @@
 	if (name.empty())
 		return NULL;
 	else
-		return (AnimationResource*) PageManager::FindResource(name);
-	// TODO: make resource lookup type-safe
+		return PageManager::GetResources()->FindAnimation(name);
 }
 
 bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
@@ -649,7 +646,7 @@
 
 PageSet::PageSet(char* xmlFile)
 {
-	mResources = NULL;
+	mResources = new ResourceManager;
 	mCurrentPage = NULL;
 	mOverlayPage = NULL;
 
@@ -742,7 +739,7 @@
 	LOGINFO("Loading resources...\n");
 	child = parent->first_node("resources");
 	if (child)
-		mResources = new ResourceManager(child, package);
+		mResources->LoadResources(child, package);
 
 	LOGINFO("Loading variables...\n");
 	child = parent->first_node("variables");
@@ -937,9 +934,9 @@
 	return 0;
 }
 
-Resource* PageSet::FindResource(std::string name)
+const ResourceManager* PageSet::GetResources()
 {
-	return mResources ? mResources->FindResource(name) : NULL;
+	return mResources;
 }
 
 Page* PageSet::FindPage(std::string name)
@@ -1307,17 +1304,9 @@
 	}
 }
 
-Resource* PageManager::FindResource(std::string name)
+const ResourceManager* PageManager::GetResources()
 {
-	return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
-}
-
-Resource* PageManager::FindResource(std::string package, std::string name)
-{
-	PageSet* tmp;
-
-	tmp = FindPackage(name);
-	return (tmp ? tmp->FindResource(name) : NULL);
+	return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
 }
 
 int PageManager::SwitchToConsole(void)
diff --git a/gui/pages.hpp b/gui/pages.hpp
index 8eec9a9..50155d0 100644
--- a/gui/pages.hpp
+++ b/gui/pages.hpp
@@ -88,7 +88,7 @@
 	Page* FindPage(std::string name);
 	int SetPage(std::string page);
 	int SetOverlay(Page* page);
-	Resource* FindResource(std::string name);
+	const ResourceManager* GetResources();
 
 	// Helper routine for identifing if we're the current page
 	int IsCurrentPage(Page* page);
@@ -131,8 +131,7 @@
 	// Used for actions and pages
 	static int ChangePage(std::string name);
 	static int ChangeOverlay(std::string name);
-	static Resource* FindResource(std::string name);
-	static Resource* FindResource(std::string package, std::string name);
+	static const ResourceManager* GetResources();
 
 	// Used for console-only mode
 	static int SwitchToConsole(void);
diff --git a/gui/resources.cpp b/gui/resources.cpp
index e0016fc..1e2e7f9 100644
--- a/gui/resources.cpp
+++ b/gui/resources.cpp
@@ -258,21 +258,32 @@
 	mSurfaces.clear();
 }
 
-Resource* ResourceManager::FindResource(std::string name)
+FontResource* ResourceManager::FindFont(const std::string& name) const
 {
-	std::vector<Resource*>::iterator iter;
-
-	for (iter = mResources.begin(); iter != mResources.end(); iter++)
-	{
-		if (name == (*iter)->GetName())
-			return (*iter);
-	}
+	for (std::vector<FontResource*>::const_iterator it = mFonts.begin(); it != mFonts.end(); ++it)
+		if (name == (*it)->GetName())
+			return *it;
 	return NULL;
 }
 
-ResourceManager::ResourceManager(xml_node<>* resList, ZipArchive* pZip)
+ImageResource* ResourceManager::FindImage(const std::string& name) const
 {
-	LoadResources(resList, pZip);
+	for (std::vector<ImageResource*>::const_iterator it = mImages.begin(); it != mImages.end(); ++it)
+		if (name == (*it)->GetName())
+			return *it;
+	return NULL;
+}
+
+AnimationResource* ResourceManager::FindAnimation(const std::string& name) const
+{
+	for (std::vector<AnimationResource*>::const_iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
+		if (name == (*it)->GetName())
+			return *it;
+	return NULL;
+}
+
+ResourceManager::ResourceManager()
+{
 }
 
 void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip)
@@ -285,14 +296,18 @@
 	while (child != NULL)
 	{
 		xml_attribute<>* attr = child->first_attribute("type");
-		if (!attr)
-			break;
 
-		Resource* res = NULL;
-		std::string type = attr->value();
+		bool error = false;
+		std::string type = attr ? attr->value() : "*unspecified*";
 		if (type == "font")
 		{
-			res = new FontResource(child, pZip);
+			FontResource* res = new FontResource(child, pZip);
+			if (res->GetResource())
+				mFonts.push_back(res);
+			else {
+				error = true;
+				delete res;
+			}
 		}
 		else if (type == "image")
 		{
@@ -300,7 +315,13 @@
 			xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect");
 			if (retain_aspect_ratio)
 				retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it
-			res = new ImageResource(child, pZip, retain);
+			ImageResource* res = new ImageResource(child, pZip, retain);
+			if (res->GetResource())
+				mImages.push_back(res);
+			else {
+				error = true;
+				delete res;
+			}
 		}
 		else if (type == "animation")
 		{
@@ -308,14 +329,21 @@
 			xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect");
 			if (retain_aspect_ratio)
 				retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it
-			res = new AnimationResource(child, pZip, retain);
+			AnimationResource* res = new AnimationResource(child, pZip, retain);
+			if (res->GetResourceCount())
+				mAnimations.push_back(res);
+			else {
+				error = true;
+				delete res;
+			}
 		}
 		else
 		{
 			LOGERR("Resource type (%s) not supported.\n", type.c_str());
+			error = true;
 		}
 
-		if (res == NULL || !res->loadedOK())
+		if (error)
 		{
 			std::string res_name;
 			if (child->first_attribute("name"))
@@ -327,12 +355,6 @@
 				LOGERR("Resource (%s)-(%s) failed to load\n", type.c_str(), res_name.c_str());
 			} else
 				LOGERR("Resource type (%s) failed to load\n", type.c_str());
-
-			delete res;
-		}
-		else
-		{
-			mResources.push_back(res);
 		}
 
 		child = child->next_sibling("resource");
@@ -341,10 +363,12 @@
 
 ResourceManager::~ResourceManager()
 {
-	std::vector<Resource*>::iterator iter;
+	for (std::vector<FontResource*>::iterator it = mFonts.begin(); it != mFonts.end(); ++it)
+		delete *it;
 
-	for (iter = mResources.begin(); iter != mResources.end(); iter++)
-		delete *iter;
+	for (std::vector<ImageResource*>::iterator it = mImages.begin(); it != mImages.end(); ++it)
+		delete *it;
 
-	mResources.clear();
+	for (std::vector<AnimationResource*>::iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
+		delete *it;
 }
diff --git a/gui/resources.hpp b/gui/resources.hpp
index 69d2427..83fc7a5 100644
--- a/gui/resources.hpp
+++ b/gui/resources.hpp
@@ -18,7 +18,6 @@
 
 public:
 	std::string GetName() { return mName; }
-	virtual bool loadedOK() = 0;
 
 private:
 	std::string mName;
@@ -47,8 +46,6 @@
 	void* GetResource() { return this ? mFont : NULL; }
 	int GetHeight() { return gr_getMaxFontHeight(this ? mFont : NULL); }
 
-	virtual bool loadedOK() { return mFont != NULL; }
-
 protected:
 	void* mFont;
 	Type m_type;
@@ -65,8 +62,6 @@
 	int GetWidth() { return gr_get_width(this ? mSurface : NULL); }
 	int GetHeight() { return gr_get_height(this ? mSurface : NULL); }
 
-	virtual bool loadedOK() { return mSurface != NULL; }
-
 protected:
 	gr_surface mSurface;
 };
@@ -83,7 +78,6 @@
 	int GetWidth() { return gr_get_width(this ? GetResource() : NULL); }
 	int GetHeight() { return gr_get_height(this ? GetResource() : NULL); }
 	int GetResourceCount() { return mSurfaces.size(); }
-	virtual bool loadedOK() { return !mSurfaces.empty(); }
 
 protected:
 	std::vector<gr_surface> mSurfaces;
@@ -92,15 +86,19 @@
 class ResourceManager
 {
 public:
-	ResourceManager(xml_node<>* resList, ZipArchive* pZip);
+	ResourceManager();
 	virtual ~ResourceManager();
 	void LoadResources(xml_node<>* resList, ZipArchive* pZip);
 
 public:
-	Resource* FindResource(std::string name);
+	FontResource* FindFont(const std::string& name) const;
+	ImageResource* FindImage(const std::string& name) const;
+	AnimationResource* FindAnimation(const std::string& name) const;
 
 private:
-	std::vector<Resource*> mResources;
+	std::vector<FontResource*> mFonts;
+	std::vector<ImageResource*> mImages;
+	std::vector<AnimationResource*> mAnimations;
 };
 
 #endif  // _RESOURCE_HEADER