view api/Objects/Race.cs @ 151:1d13820b3d96

Fixes #176: Bug when saving recently edited army * Add loaded file cleanup to AbstractWarFoundryFactory * Add override of method with Zip reference closing to WarFoundryXmlFactory WarFoundry now no longer ends up with trailing handles to files, although why they only caused problems in some situations is unknown Also: * Some line ending fixes (curse cross-platform development and different line terminators!)
author IBBoard <dev@ibboard.co.uk>
date Sat, 26 Sep 2009 18:48:36 +0000
parents d39de20f2ba1
children a54da5a8b5bb
line wrap: on
line source

// This file (Race.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2007, 2008, 2009 IBBoard.
//
// The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using IBBoard.IO;
using IBBoard.WarFoundry.API.Factories;

namespace IBBoard.WarFoundry.API.Objects
{
	public class Race : WarFoundryStagedLoadingObject
	{		
		public static string SYSTEM_DEFAULT_RACE_ID = "GameDefault"; 
		
		private string subID;
		private GameSystem system;
		private Dictionary<Category, Dictionary<string, UnitType>> unitTypesByCat;
		private Dictionary<string, UnitType> unitTypes = new Dictionary<string,UnitType>();
		private Dictionary<string, EquipmentItem> equipment = new Dictionary<string,EquipmentItem>();
		private Dictionary<string, Ability> abilities = new Dictionary<string,Ability>();
		private Dictionary<string, Category> categories = new Dictionary<string,Category>();
		
		public Race(string raceID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : this(raceID, "", raceName, gameSystem, creatingFactory)
		{
		}
		
		public Race(string raceID, string raceSubID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : base(raceID + (raceSubID!="" ? "_"+raceSubID : ""), raceName, creatingFactory)
		{
			subID = (raceSubID == null ? "" : raceSubID);
			system = gameSystem;
		}

		public string SubID
		{
			get { return subID; }
			set { subID = (value == null ? "" : value.Trim()); }
		}

		public GameSystem GameSystem
		{
			get { return system; }
			set
			{
				if (value == null)
				{
					throw new ArgumentException("Game system for a race cannot be null");
				}
				
				system = value;
			}
		}
		
		public void AddCategory(Category cat)
		{
			categories[cat.ID] = cat;
		}

		/// <summary>
		/// Gets a category from its ID. Attempts to get the category from the race's overrides, or else it falls back to getting the Game System's category with that ID.
		/// </summary>
		/// <param name="id">
		/// The ID of the category to get
		/// </param>
		/// <returns>
		/// The <code>Category</code> with the specified ID, or null if one doesn't exist. 
		/// </returns>
		public Category GetCategory(string id)
		{
			EnsureFullyLoaded();
			Category cat = null;
			categories.TryGetValue(id, out cat);
			
			if (cat == null)
			{
				cat = GameSystem.GetCategory(id);
			}
						
			return cat;
		}

		public Category[] Categories
		{
			get 
			{ 
				EnsureFullyLoaded();
				Category[] cats;
				
				if (!HasCategoryOverrides())
				{
					cats = GameSystem.Categories;
				}
				else
				{
					cats = DictionaryUtils.ToArray<string, Category>(categories);
				}
				
				return cats;
			}
		}

		public bool HasCategoryOverrides()
		{
			EnsureFullyLoaded();
			return categories.Count > 0;
		}

		public void AddEquipmentItem(EquipmentItem item)
		{
			//TODO: Throw DuplicateItemException
			equipment.Add(item.ID, item);
		}

		public EquipmentItem GetEquipmentItem(string id)
		{
			EnsureFullyLoaded();
			return DictionaryUtils.GetValue(equipment, id);
		}
		
		public List<EquipmentItem> GetEquipmentList()
		{
			EnsureFullyLoaded();
			List<EquipmentItem> items = new List<EquipmentItem>();
			
			foreach (EquipmentItem item in equipment.Values)
			{
				items.Add(item);
			}
			
			return items;
		}

		public void AddUnitType(UnitType type)
		{
			CacheUnitType(type);
			unitTypes.Add(type.ID, type);
		}

		public UnitType[] GetUnitTypes(Category cat)
		{		
			EnsureFullyLoaded();
			BuildUnitTypesByCategoryCache();
			Dictionary<string, UnitType> unitTypesDictionary;
			unitTypesByCat.TryGetValue(cat, out unitTypesDictionary);
			UnitType[] unitTypesArray;
			
			if (unitTypesDictionary == null)
			{
				unitTypesArray = new UnitType[0];
			}
			else
			{
				unitTypesArray = DictionaryUtils.ToArray<string, UnitType>(unitTypesDictionary);
			}
			
			return unitTypesArray;
		}

		private void CacheUnitType(UnitType unit)
		{
			BuildUnitTypesByCategoryCache();
			Dictionary<string,UnitType> catUnitTypes;
			unitTypesByCat.TryGetValue(unit.MainCategory, out catUnitTypes);

			if (catUnitTypes == null)
			{
				throw new InvalidFileException(String.Format("Unit type {0} with name {1} is a unit of an undefined category", unit.ID, unit.Name));
			}

			catUnitTypes.Add(unit.ID, unit);
		}
		
		private void BuildUnitTypesByCategoryCache()
		{
			if (unitTypesByCat == null)
			{
				DoBuildUnitTypesByCategoryCache();
			}
		}

		private void DoBuildUnitTypesByCategoryCache()
		{
			unitTypesByCat = new Dictionary<Category,Dictionary<string,UnitType>>();
				
			foreach (Category category in Categories)
			{ 
				unitTypesByCat.Add(category, new Dictionary<string, UnitType>());
			}
			
			foreach (UnitType unit in unitTypes.Values)
			{
				CacheUnitType(unit);
			}
		}

		public UnitType GetUnitType(string id)
		{
			EnsureFullyLoaded();
			return DictionaryUtils.GetValue(unitTypes, id);
		}
		
		public List<Ability> GetAbilityList()
		{
			EnsureFullyLoaded();
			List<Ability> items = new List<Ability>();
			items.AddRange(abilities.Values);			
			return items;
		}
		
		public void AddAbility(Ability newAbility)
		{
			//TODO: Throw DuplicateItemException
			abilities.Add(newAbility.ID, newAbility);
		}

		[Obsolete("Use AddAbility method instead")]
		public void SetAbilities(Dictionary<string, Ability> newAbilities)
		{
			foreach (Ability ability in newAbilities.Values)
			{
				AddAbility(ability);
			}
		}
				
		public Ability GetAbility(string id)
		{
			EnsureFullyLoaded();
			return DictionaryUtils.GetValue(abilities, id);
		}
		
		protected virtual Dictionary<string, UnitType> RaceUnitTypes
		{
			get { return RaceRawUnitTypes; }
			set	{ RaceRawUnitTypes = value; }
		}
		
		protected virtual Dictionary<string, EquipmentItem> RaceEquipment
		{
			get { return RaceRawEquipment; }
			set { RaceRawEquipment = value; }
		}
		
		protected virtual Dictionary<string, Ability> RaceAbilities
		{
			get { return RaceRawAbilities; }
			set { RaceRawAbilities = value; }
		}
		
		protected Dictionary<string, UnitType> RaceRawUnitTypes
		{
			get { return unitTypes; }
			set	{ unitTypes = value; }
		}
		
		protected Dictionary<string, EquipmentItem> RaceRawEquipment
		{
			get { return equipment; }
			set { equipment = value; }
		}
		
		protected Dictionary<string, Ability> RaceRawAbilities
		{
			get { return abilities; }
			set { abilities = value; }
		}
	}
}