diff api/WarFoundryLoader.cs @ 14:0770e5cbba7c

Closes #21 - File loading in order * Reworked LoadFiles to smaller methods for readability (also re #10) and structure * Now determine expected load return before loading then load all "expected GameSystem" before "expected Race" * Make "can load as race/game system/army" methods public in interface Re #22 - Get errored file loading * Created FileLoadFailure class and made LoadFiles return a list of them Also * Some code cleanup * Change to DictionaryUtils calls
author IBBoard <dev@ibboard.co.uk>
date Sun, 25 Jan 2009 14:03:20 +0000
parents 613bc5eaac59
children 306558904c2a
line wrap: on
line diff
--- a/api/WarFoundryLoader.cs	Thu Jan 22 20:26:08 2009 +0000
+++ b/api/WarFoundryLoader.cs	Sun Jan 25 14:03:20 2009 +0000
@@ -152,49 +152,22 @@
 		/// <summary>
 		/// Loads all of the data files in the registered directories.
 		/// </summary>
-		public void LoadFiles()
+		/// <returns>
+		/// A <see cref="Dictionary"/> of files that failed to load mapped against the message that their failure returned
+		/// </returns>
+		public List<FileLoadFailure> LoadFiles()
 		{
 			LogNotifier.Debug(GetType(), "Load files");
 			PrepareForFileLoad();
-			
-			foreach (DirectoryInfo directory in directories)
-			{
-				if (directory.Exists)
-				{
-					LogNotifier.Debug(GetType(), "Load from "+directory.FullName);
-				
-					foreach (FileInfo file in directory.GetFiles())
-					{
-						LoadFile(file);
-					}
-				}
-				else
-				{
-					LogNotifier.WarnFormat(GetType(), "Load for {0} failed because directory didn't exist", directory.FullName);
-				}
-			}
-			
-			ICollection<Race> races = new List<Race>(); 
+			Dictionary<FileInfo, IWarFoundryFactory> loadableRaces = new Dictionary<FileInfo, IWarFoundryFactory>();
+			Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems = new Dictionary<FileInfo, IWarFoundryFactory>();
+			List<FileLoadFailure> failedLoads = FillLoadableFiles(loadableRaces, loadableGameSystems);
+			failedLoads.AddRange(LoadGameSystems(loadableGameSystems));
+			failedLoads.AddRange(LoadRaces(loadableRaces));
+
+			LogNotifier.Debug(GetType(), failedLoads.Count + " failed file loads");
 			
-			foreach (SimpleSet<IWarFoundryObject> objs in loadedObjects.Values)
-			{			
-				foreach (IWarFoundryObject obj in  objs)
-				{
-					if (obj is Race)
-					{
-						races.Add((Race)obj);
-					}
-					else if (obj is GameSystem)
-					{
-						StoreGameSystem((GameSystem)obj);
-					}
-				}
-			}
-			
-			foreach (Race race in races)
-			{
-				StoreRace(race);
-			}					
+			return failedLoads;
 		}
 		
 		protected void PrepareForFileLoad()
@@ -203,6 +176,179 @@
 			systemsTable = new Dictionary<string,GameSystem>();
 			racesTable = new Dictionary<string,Dictionary<string,Dictionary<string,Race>>>();
 		}
+
+		private List<FileLoadFailure> FillLoadableFiles(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems)
+		{			
+			List<FileLoadFailure> fails = new List<FileLoadFailure>();
+			
+			foreach (DirectoryInfo directory in directories)
+			{				
+				if (directory.Exists)
+				{
+					List<FileLoadFailure> directoryFails = FillLoadableFilesForDirectory(loadableRaces, loadableGameSystems, directory);
+					fails.AddRange(directoryFails);
+				}
+				else
+				{
+					LogNotifier.WarnFormat(GetType(), "Load for {0} failed because directory didn't exist", directory.FullName);
+				}
+			}
+			
+			return fails;
+		}
+
+		private List<FileLoadFailure> FillLoadableFilesForDirectory(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems, DirectoryInfo directory)
+		{
+			List<FileLoadFailure> fails = new List<FileLoadFailure>();
+			LogNotifier.Debug(GetType(), "Load from "+directory.FullName);
+		
+			foreach (FileInfo file in directory.GetFiles())
+			{
+				IWarFoundryFactory factory = GetGameSystemRaceLoadingFactoryForFile(file);
+				
+				if (factory != null)
+				{
+					loadableGameSystems.Add(file, factory);
+				}
+				else
+				{
+					factory = GetRaceLoadingFactoryForFile(file);
+	
+					if (factory!=null)
+					{
+						loadableRaces.Add(file, factory);
+					}
+					else
+					{
+						fails.Add(new FileLoadFailure(file, "FileNotHandled", "File not handled as a Race or Game System definition: {0}"));
+					}
+				}
+			}
+
+			return fails;
+		}
+
+		private IWarFoundryFactory GetGameSystemRaceLoadingFactoryForFile(FileInfo file)
+		{
+			IWarFoundryFactory loadingFactory = null;
+			
+			foreach (INonNativeWarFoundryFactory factory in nonNativeFactories)
+			{
+				if (factory.CanHandleFileAsGameSystem(file))
+				{
+					loadingFactory = factory;
+					break;
+				}
+			}
+
+			if (loadingFactory == null)
+			{
+				foreach (INativeWarFoundryFactory factory in factories)
+				{
+					if (factory.CanHandleFileAsGameSystem(file))
+					{
+						loadingFactory = factory;
+						break;
+					}
+				}
+			}
+
+			return loadingFactory;
+		}
+
+		private IWarFoundryFactory GetRaceLoadingFactoryForFile(FileInfo file)
+		{
+			IWarFoundryFactory loadingFactory = null;
+			
+			foreach (INonNativeWarFoundryFactory factory in nonNativeFactories)
+			{
+				if (factory.CanHandleFileAsRace(file))
+				{
+					loadingFactory = factory;
+					break;
+				}
+			}
+
+			if (loadingFactory == null)
+			{
+				foreach (INativeWarFoundryFactory factory in factories)
+				{
+					if (factory.CanHandleFileAsRace(file))
+					{
+						loadingFactory = factory;
+						break;
+					}
+				}
+			}
+
+			return loadingFactory;
+		}
+
+		private List<FileLoadFailure> LoadGameSystems(Dictionary<FileInfo, IWarFoundryFactory> gameSystemFiles)
+		{
+			List<FileLoadFailure> fails = new List<FileLoadFailure>();
+
+			
+			foreach (FileInfo file in gameSystemFiles.Keys)
+			{
+				try
+				{
+					bool loaded = LoadObject(file, gameSystemFiles[file]);
+	
+					if (!loaded)
+					{
+						fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}"));
+					}
+				}
+				catch (Exception ex)
+				{
+					fails.Add(new FileLoadFailure(file, ex.Message));
+				}
+			}
+			
+			return fails;
+		}
+
+		private List<FileLoadFailure> LoadRaces(Dictionary<FileInfo, IWarFoundryFactory> raceFiles)
+		{
+			List<FileLoadFailure> fails = new List<FileLoadFailure>();
+			
+			foreach (FileInfo file in raceFiles.Keys)
+			{
+				try
+				{
+					bool loaded = LoadObject(file, raceFiles[file]);
+	
+					if (!loaded)
+					{
+						fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}"));
+					}
+				}
+				catch (Exception ex)
+				{
+					fails.Add(new FileLoadFailure(file, ex.Message));
+				}
+			}
+			
+			return fails;
+		}
+
+		private bool LoadObject(FileInfo file, IWarFoundryFactory factory)
+		{
+			bool loaded = false;
+			
+			LogNotifier.DebugFormat(GetType(), "Loading {0} using {1}", file.FullName, factory.GetType().Name);
+			ICollection<IWarFoundryObject> objects = factory.CreateObjectsFromFile(file);
+			
+			if (objects.Count > 0)
+			{
+				AddLoadedObjects(objects, factory);
+				loaded = true;
+			}
+
+			return loaded;
+		}
+		
 		
 		/// <summary>
 		/// Loads a single file through the registered WarFoundryFactories, if a factory exists that supports the file format.
@@ -210,60 +356,66 @@
 		/// <param name="file">
 		/// A <see cref="FileInfo"/> for the file to attempt to load
 		/// </param>
-		protected void LoadFile(FileInfo file)
+		/// <returns>
+		/// An ICollection of IWarFoundryObjects loaded from <code>file</code>
+		/// </returns>
+		public ICollection<IWarFoundryObject> LoadFile(FileInfo file)
 		{
-			bool handled = false;
+			ICollection<IWarFoundryObject> objs = null;			
+			IWarFoundryFactory loadFactory = null;
 			
-			if (!handled)
+			if (nonNativeFactories.Count > 0)
 			{
-				ICollection<IWarFoundryObject> objs = null;
-				IWarFoundryFactory loadFactory = null;
+				LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file");
 				
-				if (nonNativeFactories.Count > 0)
+				foreach (INonNativeWarFoundryFactory factory in nonNativeFactories)
 				{
-					LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file");
+					bool canLoad = factory.CanHandleFileFormat(file);
+					LogNotifier.Debug(GetType(), "Load using "+factory.GetType().FullName+"? " + (canLoad ? "yes" : "no"));
 					
-					foreach (INonNativeWarFoundryFactory factory in nonNativeFactories)
+					if (canLoad)
 					{
-						LogNotifier.Debug(GetType(), "Load using "+factory.GetType().AssemblyQualifiedName+"? " + (factory.CanHandleFileFormat(file) ? "yes" : "no"));
+						objs = factory.CreateObjectsFromFile(file);
 						
-						if (factory.CanHandleFileFormat(file))
+						if (objs!=null)
 						{
-							objs = factory.CreateObjectsFromFile(file);
-							
-							if (objs!=null)
-							{
-								loadFactory = factory;
-								break;
-							}
-						}			         
-					}
+							loadFactory = factory;
+							break;
+						}
+					}			         
 				}
+			}
+			
+			if (objs == null)
+			{
+				LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file");
 				
-				if (objs == null)
+				foreach (INativeWarFoundryFactory factory in factories)
 				{
-					LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file");
-					
-					foreach (INativeWarFoundryFactory factory in factories)
+					if (factory.CanHandleFileFormat(file))
 					{
-						if (factory.CanHandleFileFormat(file))
+						objs = factory.CreateObjectsFromFile(file);
+						
+						if (objs!=null)
 						{
-							objs = factory.CreateObjectsFromFile(file);
-							
-							if (objs!=null)
-							{
-								loadFactory = factory;
-								break;
-							}
+							loadFactory = factory;
+							break;
 						}
 					}
 				}
-					
-				if (objs!=null)
-				{
-					AddLoadedObjects(objs, loadFactory);
-				}
+			}
+				
+			if (objs!=null)
+			{
+				AddLoadedObjects(objs, loadFactory);
 			}
+			else
+			{
+				LogNotifier.Debug(GetType(), "Loading of "+file.FullName+" failed");
+				objs = new List<IWarFoundryObject>();
+			}
+
+			return objs;
 		}
 		
 		private void AddLoadedObjects(ICollection<IWarFoundryObject> loadedObjs, IWarFoundryFactory factory)
@@ -278,20 +430,22 @@
 			}
 				
 			objs.AddRange(loadedObjs);
+			StoreObjects(loadedObjs);
 		}
-		
-		private void AddLoadedObject(IWarFoundryObject obj, IWarFoundryFactory factory)
+
+		private void StoreObjects(ICollection<IWarFoundryObject> loadedObjects)
 		{
-			SimpleSet<IWarFoundryObject> objs;
-			loadedObjects.TryGetValue(factory, out objs);
-			
-			if (objs == null)
+			foreach (IWarFoundryObject loadedObject in loadedObjects)
 			{
-				objs = new SimpleSet<IWarFoundryObject>();
-				loadedObjects.Add(factory, objs);
+				if (loadedObject is GameSystem)
+				{
+					StoreGameSystem((GameSystem)loadedObject);
+				}
+				else if (loadedObject is Race)
+				{
+					StoreRace((Race)loadedObject);
+				}
 			}
-				
-			objs.Add(obj);
 		}
 		
 		protected virtual ZipFile MakeZipFile(FileInfo file)
@@ -313,24 +467,6 @@
 			}
 		}
 		
-		
-		/// <summary>
-		/// Stores a loaded <see cref="GameSystem"/> that has been generated outside the core loading structure.
-		/// 
-		/// Note: Calls to this function should be made before calls to StoreRace(Race, IWarFoundryFactory).
-		/// </summary>
-		/// <param name="system">
-		/// The <see cref="GameSystem"/> to register as loaded.
-		/// </param>
-		/// <param name="factory">
-		/// The <see cref="IWarFoundryFactory"/> that created it.
-		/// </param>
-		public void StoreGameSystem(GameSystem system, IWarFoundryFactory factory)
-		{
-			AddLoadedObject(system, factory);	
-			StoreGameSystem(system);
-		}
-		
 		protected void StoreRace(Race race)
 		{
 			Dictionary<string, Dictionary<string, Race>> systemRaces;
@@ -370,23 +506,6 @@
 		}
 		
 		/// <summary>
-		/// Stores a loaded <see cref="Race"/> that has been generated outside the core loading structure.
-		/// 
-		/// Note: Calls to this function should ensure that the relevant <see cref="GameSystem"> has been created first.
-		/// </summary>
-		/// <param name="race">
-		/// The <see cref="Race"/> to register as loaded.
-		/// </param>
-		/// <param name="factory">
-		/// The <see cref="IWarFoundryFactory"/> that created it
-		/// </param>
-		public void StoreRace(Race race, IWarFoundryFactory factory)
-		{
-			AddLoadedObject(race, factory);
-			StoreRace(race);
-		}
-		
-		/// <summary>
 		/// Gets all <see cref="GameSystem"/>s that are currently available, determined by those that can be loaded with the current <see cref="IWarFoundryFactory"/>s. 
 		/// </summary>
 		/// <returns>
@@ -399,15 +518,7 @@
 				LoadFiles();
 			}
 			
-			GameSystem[] systems = new GameSystem[systemsTable.Count];
-			int iSys = 0;
-			
-			foreach (GameSystem sys in systemsTable.Values)
-			{
-				systems[iSys++] = sys;
-			}
-			
-			return systems;
+			return DictionaryUtils.ToArray<string, GameSystem>(systemsTable);
 		}
 
 		/// <summary>