Mercurial > repos > IBDev-IBBoard.WarFoundry.API
diff api/WarFoundryLoader.cs @ 0:520818033bb6
Initial commit of WarFoundry code
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Fri, 19 Dec 2008 15:57:51 +0000 |
parents | |
children | b9346894319c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/WarFoundryLoader.cs Fri Dec 19 15:57:51 2008 +0000 @@ -0,0 +1,664 @@ +// WarFoundryLoader.cs +// +// Copyright (C) 2007 IBBoard +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License version 2.1 of the License as published by the Free +// Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// + +using System; +using System.Collections.Generic; +using System.IO; +using IBBoard.Collections; +using IBBoard.IO; +using IBBoard.Logging; +using IBBoard.WarFoundry.API.Factories; +using IBBoard.WarFoundry.API.Objects; +using ICSharpCode.SharpZipLib.Zip; + +namespace IBBoard.WarFoundry.API +{ + public class WarFoundryLoader + { + private static WarFoundryLoader loader; + + /// <summary> + /// Gets the default <see cref="WarFoundryLoader"/> used to load WarFoundry data files. + /// </summary> + /// <returns> + /// The default <see cref="WarFoundryLoader"/> + /// </returns> + public static WarFoundryLoader GetDefault() + { + if (loader == null) + { + loader = new WarFoundryLoader(); + } + + return loader; + } + + private ICollection<DirectoryInfo> directories; + private ICollection<INativeWarFoundryFactory> factories; + private ICollection<INonNativeWarFoundryFactory> nonNativeFactories; + private Dictionary<string, GameSystem> systemsTable; + private Dictionary<string, Dictionary<string, Dictionary<string, Race>>> racesTable; //Keys are: System, Race, SubRace + private Dictionary<IWarFoundryFactory, SimpleSet<IWarFoundryObject>> loadedObjects; + + protected WarFoundryLoader() + { + directories = new List<DirectoryInfo>(); + factories = new List<INativeWarFoundryFactory>(); + nonNativeFactories = new List<INonNativeWarFoundryFactory>(); + loadedObjects = new Dictionary<IWarFoundryFactory,SimpleSet<IWarFoundryObject>>(); + } + + /// <summary> + /// Adds a directory to the collection of directories that will be searched for WarFoundry data files. + /// </summary> + /// <param name="directory"> + /// The <see cref="DirectoryInfo"/> to add to the list for searching for data files + /// </param> + public void AddLoadDirectory(DirectoryInfo directory) + { + if (!directories.Contains(directory)) + { + directories.Add(directory); + } + } + + /// <summary> + /// Removes a directory from the collection of directories that will be searched for WarFoundry data files. + /// </summary> + /// <param name="directory"> + /// A <see cref="DirectoryInfo"/> + /// </param> + public void RemoveLoadDirectory(DirectoryInfo directory) + { + if (directories.Contains(directory)) + { + directories.Remove(directory); + } + } + + /// <summary> + /// Registers a <see cref="INativeWarFoundryFactory"/> as a factory that can parse native data files. + /// </summary> + /// <param name="factory"> + /// The <see cref="INativeWarFoundryFactory"/> to register to parse native data files. + /// </param> + public void RegisterFactory(INativeWarFoundryFactory factory) + { + if (!factories.Contains(factory)) + { + factories.Add(factory); + } + } + + /// <summary> + /// Unregisters a <see cref="INativeWarFoundryFactory"/> so that it will no longer be used to try to parse native data files. + /// </summary> + /// <param name="factory"> + /// The <see cref="INativeWarFoundryFactory"/> to remove from the collection of factories that are used to try to parse native data files. + /// </param> + public void UnregisterFactory(INativeWarFoundryFactory factory) + { + if (factories.Contains(factory)) + { + factories.Remove(factory); + } + } + + /// <summary> + /// Registers a <see cref="INonNativeWarFoundryFactory"/> so that it will be used to try to parse non-native data files from other applications. + /// </summary> + /// <param name="factory"> + /// The <see cref="INonNativeWarFoundryFactory"/> to register to parse non-native data files. + /// </param> + public void RegisterNonNativeFactory(INonNativeWarFoundryFactory factory) + { + if (!nonNativeFactories.Contains(factory)) + { + nonNativeFactories.Add(factory); + } + } + + /// <summary> + /// Unregisters a <see cref="INonNativeWarFoundryFactory"/> so that it will no longer be used to try to parse non-native data files from other applications. + /// </summary> + /// <param name="factory"> + /// The <see cref="INonNativeWarFoundryFactory"/> to remove from the collection of factories that are used to try to parse non-native data files. + /// </param> + public void UnregisterNonNativeFactory(INonNativeWarFoundryFactory factory) + { + if (nonNativeFactories.Contains(factory)) + { + nonNativeFactories.Remove(factory); + } + } + + /// <summary> + /// Loads all of the data files in the registered directories. + /// </summary> + public void LoadFiles() + { + LogNotifier.Debug(GetType(), "Load files"); + PrepareForFileLoad(); + + foreach (DirectoryInfo directory in directories) + { + LogNotifier.Debug(GetType(), "Load from "+directory.FullName); + + foreach (FileInfo file in directory.GetFiles()) + { + LoadFile(file); + } + } + + ICollection<Race> races = new List<Race>(); + + 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); + } + } + + protected void PrepareForFileLoad() + { + //Just set up blank dictionaries for now - may try different and more complex handling in future + systemsTable = new Dictionary<string,GameSystem>(); + racesTable = new Dictionary<string,Dictionary<string,Dictionary<string,Race>>>(); + } + + /// <summary> + /// Loads a single file through the registered WarFoundryFactories, if a factory exists that supports the file format. + /// </summary> + /// <param name="file"> + /// A <see cref="FileInfo"/> for the file to attempt to load + /// </param> + protected void LoadFile(FileInfo file) + { + bool handled = false; + + if (!handled) + { + ICollection<IWarFoundryObject> objs = null; + IWarFoundryFactory loadFactory = null; + + if (nonNativeFactories.Count > 0) + { + LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file"); + + foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) + { + LogNotifier.Debug(GetType(), "Load using "+factory.GetType().AssemblyQualifiedName+"? " + (factory.CanHandleFileFormat(file) ? "yes" : "no")); + + if (factory.CanHandleFileFormat(file)) + { + objs = factory.CreateObjectsFromFile(file); + + if (objs!=null) + { + loadFactory = factory; + break; + } + } + } + } + + if (objs == null) + { + LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file"); + + foreach (INativeWarFoundryFactory factory in factories) + { + if (factory.CanHandleFileFormat(file)) + { + objs = factory.CreateObjectsFromFile(file); + + if (objs!=null) + { + loadFactory = factory; + break; + } + } + } + } + + if (objs!=null) + { + AddLoadedObjects(objs, loadFactory); + } + } + } + + private void AddLoadedObjects(ICollection<IWarFoundryObject> loadedObjs, IWarFoundryFactory factory) + { + SimpleSet<IWarFoundryObject> objs; + loadedObjects.TryGetValue(factory, out objs); + + if (objs == null) + { + objs = new SimpleSet<IWarFoundryObject>(); + loadedObjects.Add(factory, objs); + } + + objs.AddRange(loadedObjs); + } + + private void AddLoadedObject(IWarFoundryObject obj, IWarFoundryFactory factory) + { + SimpleSet<IWarFoundryObject> objs; + loadedObjects.TryGetValue(factory, out objs); + + if (objs == null) + { + objs = new SimpleSet<IWarFoundryObject>(); + loadedObjects.Add(factory, objs); + } + + objs.Add(obj); + } + + protected virtual ZipFile MakeZipFile(FileInfo file) + { + return new ZipFile(file.FullName); + } + + protected void StoreGameSystem(GameSystem system) + { + string sysid = system.ID.ToLower(); + + if (systemsTable.ContainsKey(sysid)) + { + LogNotifier.WarnFormat(GetType(), "System {0} ({1}) has already been loaded. Duplicate file ({3}) discarded", system.Name, system.ID, system.SourceFile.FullName); + } + else + { + systemsTable.Add(sysid, (GameSystem)system); + } + } + + + /// <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; + + if (race.GameSystem == null) + { + throw new InvalidOperationException("Race cannot have null game system. Game system should be loaded before race."); + } + + string systemID = race.GameSystem.ID.ToLower(); + racesTable.TryGetValue(systemID, out systemRaces); + + if (systemRaces==null) + { + systemRaces = new Dictionary<string,Dictionary<string,Race>>(); + racesTable.Add(systemID, systemRaces); + } + + Dictionary<string, Race> subRaces; + systemRaces.TryGetValue(race.ID.ToLower(), out subRaces); + + if (subRaces==null) + { + subRaces = new Dictionary<string,Race>(); + systemRaces.Add(race.ID.ToLower(), subRaces); + } + + if (subRaces.ContainsKey(race.SubID.ToLower())) + { + LogNotifier.WarnFormat(GetType(), "Race {0} ({1} - {2}) for system {3} ({4}) has already been loaded. Duplicate file ({5}) discarded", race.Name, race.ID, race.SubID, race.GameSystem.ID, race.GameSystem.Name, race.SourceFile.Name); + race = null; + } + else + { + subRaces.Add(race.SubID.ToLower(), race); + } + } + + /// <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> + /// An array of <see cref="GameSystem"/>s that are currently available. + /// </returns> + public GameSystem[] GetGameSystems() + { + if (systemsTable==null) + { + LoadFiles(); + } + + GameSystem[] systems = new GameSystem[systemsTable.Count]; + int iSys = 0; + + foreach (GameSystem sys in systemsTable.Values) + { + systems[iSys++] = sys; + } + + return systems; + } + + /// <summary> + /// Gets a single <see cref="GameSystem"/> with a given ID. + /// </summary> + /// <param name="systemID"> + /// The ID of the <see cref="GameSystem"/> to get, as a <see cref="System.String"/>. + /// </param> + /// <returns> + /// The <see cref="GameSystem"/> with the given ID, or <code>null</code> if one doesn't exist. + /// </returns> + public GameSystem GetGameSystem(string systemID) + { + if (systemsTable==null) + { + LoadFiles(); + } + + GameSystem system; + systemsTable.TryGetValue(systemID.ToLower(), out system); + return system; + } + + /// <summary> + /// Gets an array of the races for the specified <see cref="GameSystem"/>. + /// </summary> + /// <param name="system"> + /// The <see cref="GameSystem"/> to get the available races for. + /// </param> + /// <returns> + /// An array of <see cref="Race"/>s for the <see cref="GameSystem"/> + /// </returns> + public Race[] GetRaces(GameSystem system) + { + return GetRaces(system.ID); + } + + /// <summary> + /// Gets an array of the races for a game system by ID. + /// </summary> + /// <param name="systemID"> + /// The <see cref="System.String"/> ID of the game system to get races for + /// </param> + /// <returns> + /// An array of <see cref="Race"/>s for the specified game system + /// </returns> + public Race[] GetRaces(string systemID) + { + if (racesTable==null) + { + LoadFiles(); + } + + systemID = systemID.ToLower(); + + foreach (string key in racesTable.Keys) + { + Console.WriteLine(key); + } + + Dictionary<string, Dictionary<string, Race>> system; + racesTable.TryGetValue(systemID, out system); + + if (system==null) + { + return new Race[0]; + } + + int count = 0; + + foreach (Dictionary<string, Race> racesDict in system.Values) + { + count+= racesDict.Count; + } + + Race[] races = new Race[count]; + int i = 0; + + foreach (string raceID in system.Keys) + { + foreach (string raceSubId in system[raceID].Keys) + { + races[i++] = GetRace(systemID, raceID, raceSubId); + } + } + + return races; + } + + /// <summary> + /// Gets a single race for a given <see cref="GameSystem"/> by ID of the race. + /// </summary> + /// <param name="system"> + /// The <see cref="GameSystem"/> that the race is part of. + /// </param> + /// <param name="raceID"> + /// A <see cref="System.String"/> ID for the race to load. + /// </param> + /// <returns> + /// A <see cref="Race"/> with the specified ID from the <see cref="GameSystem"/>, or <code>null</code> if one doesn't exist. + /// </returns> + public Race GetRace(GameSystem system, string raceID) + { + return GetRace(system.ID, raceID); + } + + /// <summary> + /// Gets a single race for a given game system by ID of the game system and race. + /// </summary> + /// <param name="systemID"> + /// The <see cref="System.String"/> ID of the game system that the race is part of. + /// </param> + /// <param name="raceID"> + /// The <see cref="System.String"/> ID for the race to load. + /// </param> + /// <returns> + /// A <see cref="Race"/> with the specified ID from the game system with the specified ID, or <code>null</code> if there is no race or game system with those IDs. + /// </returns> + public Race GetRace(string systemID, string raceID) + { + return GetRace(systemID, raceID, ""); + } + + /// <summary> + /// Gets a single race for a given <see cref="GameSystem"/> by the race's ID and sub-race ID. + /// </summary> + /// <param name="system"> + /// The <see cref="GameSystem"/> that the race is part of. + /// </param> + /// <param name="raceID"> + /// The <see cref="System.String"/> ID for the race to load. + /// </param> + /// <param name="raceSubID"> + /// A <see cref="System.String"/> + /// </param> + /// <returns> + /// A <see cref="Race"/> + /// </returns> + public Race GetRace(GameSystem system, string raceID, string raceSubID) + { + return GetRace(system.ID, raceID, raceSubID); + } + + /// <summary> + /// Gets a single race for a given game system by the game system's ID and the race's ID and sub-race ID. + /// </summary> + /// <param name="systemID"> + /// The <see cref="System.String"/> ID of the game system that the race is part of. + /// </param> + /// <param name="raceID"> + /// The <see cref="System.String"/> ID for the race to load. + /// </param> + /// <param name="raceSubID"> + /// A <see cref="System.String"/> + /// </param> + /// <returns> + /// A <see cref="Race"/> + /// </returns> + public Race GetRace(string systemID, string raceID, string raceSubID) + { + if (racesTable==null) + { + LoadFiles(); + } + + Race race = null; + + systemID = systemID.ToLower(); + + Dictionary<string, Dictionary<string, Race>> races; + racesTable.TryGetValue(systemID, out races); + + if (races!=null) + { + Dictionary<string, Race> subraces; + races.TryGetValue(raceID, out subraces); + + if (subraces!=null) + { + subraces.TryGetValue(raceSubID, out race); + } + } + + return race; + } + + /// <summary> + /// Gets the IDs of all of the game systems currently available. + /// </summary> + /// <returns> + /// An array of <see cref="System.String"/>s representing the IDs of the game systems. + /// </returns> + public string[] GetGameSystemIDs() + { + if (systemsTable==null) + { + LoadFiles(); + } + + string[] keys = new string[systemsTable.Keys.Count]; + int i = 0; + + foreach (string key in systemsTable.Keys) + { + keys[i++] = key; + } + + return keys; + } + + /// <summary> + /// Gets the IDs of all of the races of a specified game system. + /// </summary> + /// <param name="system"> + /// The <see cref="GameSystem"/> to get the available races for. + /// </param> + /// <returns> + /// An array of <see cref="System.String"/>s representing the IDs of the races of the specified game system. + /// </returns> + public string[] GetSystemRaceIDs(GameSystem system) + { + return GetSystemRaceIDs(system.ID); + } + + /// <summary> + /// Gets the IDs of all of the races of a specified game system. + /// </summary> + /// <param name="systemID"> + /// The <see cref="System.String"/> ID of the game system to get the available races for. + /// </param> + /// <returns> + /// An array of <see cref="System.String"/>s representing the IDs of the races of the specified game system. + /// </returns> + public string[] GetSystemRaceIDs(string systemID) + { + if (racesTable == null) + { + LoadFiles(); + } + + Dictionary<string, Dictionary<string, Race>> races = racesTable[systemID.ToLower()]; + + if (races==null) + { + return new string[0]; + } + else + { + string[] keys = new string[races.Keys.Count]; + int i = 0; + + foreach (string key in races.Keys) + { + keys[i++] = key; + } + + return keys; + } + } + } +}