view API/Objects/Army.cs @ 451:676f5ce04176

Re #379: Fix validation of requirements to check for unit * Add method to Army to differentiate "all requirements" from "requirements relevant to adding a unit"
author IBBoard <dev@ibboard.co.uk>
date Sat, 28 Jan 2012 16:57:59 +0000
parents d992758b0150
children 0a2068897793
line wrap: on
line source

// This file (Army.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.IO;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using IBBoard.WarFoundry.API;
using IBBoard.WarFoundry.API.Factories;
using ICSharpCode.SharpZipLib.Zip;
using IBBoard.WarFoundry.API.Objects.Requirement;
using IBBoard.Lang;
using IBBoard.Collections;

namespace IBBoard.WarFoundry.API.Objects
{
	/// <summary>
	/// Summary description for Army.
	/// </summary>
	public class Army : WarFoundryLoadedObject, ICostedWarFoundryObject
	{
		public static string GenerateDefaultName(Race race, int points, string ptsAbbrev)
		{
			return String.Format(race.ArmyDefaultName, Translation.GetTranslation("armySizePts", "{0}{1}", points, ptsAbbrev));
		}

		//private GameSystem system;
		private Race armyRace;
		private int maxPoints;
		private double pointsTotal;
		private Dictionary<Category, ArmyCategory> categories;

		public event ObjectAddDelegate UnitAdded;
		public event ObjectRemoveDelegate UnitRemoved;
		public event IntValChangedDelegate MaxPointsValueChanged;
		public event DoubleValChangedDelegate PointsValueChanged;
		public event MethodInvoker ArmyCompositionChanged;
		private DoubleValChangedDelegate PointsValueChangedMethod;
		
		public Army(Race race, string armyName, int maxArmyPoints) : this(race, armyName, maxArmyPoints, null)
		{
		}

		public Army(Race race, string armyName, int maxArmyPoints, ZipFile file) : base(armyName)
		{
			armyRace = race;
			Name = armyName;
			maxPoints = maxArmyPoints;
			PointsValueChangedMethod = new DoubleValChangedDelegate(PointsValueChangedHandler);
		}

		protected override string DefaultName()
		{
			return Army.GenerateDefaultName(Race, MaxPoints, GameSystem.GetPointsAbbrev(MaxPoints));
		}
		
		public ArmyCategory GetCategory(Category cat)
		{
			ArmyCategory armyCat = null;
			ArmyCategories.TryGetValue(cat, out armyCat);
			return armyCat;
		}
		
		private Dictionary<Category, ArmyCategory> ArmyCategories
		{
			get
			{
				if (categories==null)
				{
					categories = new Dictionary<Category, ArmyCategory>();
					Category[] raceCats = Race.Categories;
					ArmyCategory cat;
					int raceCatCount = raceCats.Length;

					for (int i = 0; i < raceCatCount; i++)
					{
						Category raceCat = raceCats[i];
						cat = new ArmyCategory(this, raceCat);
						categories[raceCat] = cat;
						cat.PointsValueChanged+= PointsValueChangedMethod;
						cat.UnitAdded+=new ObjectAddDelegate(Army_UnitAdded);
						cat.UnitRemoved+=new ObjectRemoveDelegate(Army_UnitRemoved);
					}
				}
				
				return categories;
			}
		}

		public ArmyCategory[] Categories
		{
			get 
			{
				return DictionaryUtils.ToArray<Category, ArmyCategory>(ArmyCategories);
			}
		}

		public Race Race
		{
			get { return armyRace; }
		}

		public GameSystem GameSystem
		{
			get { return (armyRace!=null ? armyRace.GameSystem : null); }
		}

		protected void OnUnitAdded(Unit unit)
		{
			if (UnitAdded != null)
			{
				UnitAdded(unit);
			}
		}

		protected void OnUnitRemoved(Unit unit)
		{
			if (UnitRemoved!=null)
			{
				UnitRemoved(unit);
			}
		}

		private void OnPointsValueChanged(double oldValue, double newValue)
		{
			if (PointsValueChanged!=null)
			{
				PointsValueChanged(this, oldValue, newValue);
			}
		}
		
		private double TotalPoints
		{
			get { return pointsTotal; }
			set
			{
				double oldPoints = pointsTotal;
				pointsTotal = value;

				if (oldPoints!=pointsTotal)
				{
					OnPointsValueChanged(oldPoints, pointsTotal);
				}
			}
		}
		
		public double Points
		{
			get { return TotalPoints; }
		}
		
		public void AddUnit(Unit unit)
		{
			Category category = unit.UnitType.MainCategory;
			AddUnit(unit, category);
		}
		
		public void AddUnit(Unit unit, Category category)
		{			
			ArmyCategory armyCat = GetCategory(category);
			armyCat.AddUnit(unit);
		}
		
		public void RemoveUnit(Unit unit)
		{
			unit.Category.RemoveUnit(unit);
		}

		public Unit[] GetUnits(Category cat)
		{
			return GetUnits(this.GetCategory(cat));
		}

		public Unit[] GetUnits(ArmyCategory cat)
		{
			return cat.GetUnits();
		}

		public Unit[] GetUnits()
		{
			List<Unit> fullList = new List<Unit>();

			foreach(ArmyCategory cat in Categories)
			{
				fullList.AddRange(cat.GetUnits());
			}

			return fullList.ToArray();
		}

		public int MaxPoints
		{
			get { return maxPoints; }
			set 
			{
				if (value > 0)
				{
					int oldPoints = maxPoints;
					maxPoints = value;

					if (MaxPointsValueChanged != null)
					{
						MaxPointsValueChanged(this, oldPoints, maxPoints);
					}

					if (HasDefaultName())
					{
						OnNameChanged("", Name);
					}
				}
			}
		}

		private void PointsValueChangedHandler(WarFoundryObject obj, double oldVal, double newVal)
		{
			if (obj is ArmyCategory)
			{
				double points = 0;

				foreach (ArmyCategory cat in Categories)
				{
					points+= cat.Points;
				}

				TotalPoints = points;
			}
		}

		public int GetUnitTypeCount(UnitType unitType)
		{
			int count = 0;

			foreach (ArmyCategory cat in Categories)
			{
				count+= cat.GetUnitTypeCount(unitType);
			}

			return count;
		}

		private void Army_UnitAdded(WarFoundryObject val)
		{
			Unit unit = (Unit)val;
			OnUnitAdded(unit);
			OnArmyCompositionChanged();
			unit.UnitEquipmentAmountChanged += HandleUnitUnitEquipmentAmountChanged;
			unit.UnitSizeChanged += HandleUnitUnitSizeChanged;
		}

		private void Army_UnitRemoved(WarFoundryObject val)
		{
			Unit unit = (Unit)val;
			OnUnitRemoved(unit);
			OnArmyCompositionChanged();
			unit.UnitEquipmentAmountChanged -= HandleUnitUnitEquipmentAmountChanged;
			unit.UnitSizeChanged -= HandleUnitUnitSizeChanged;
		}

		private void HandleUnitUnitEquipmentAmountChanged (WarFoundryObject obj, double oldValue, double newValue)
		{
			OnArmyCompositionChanged();
		}

		private void HandleUnitUnitSizeChanged (WarFoundryObject obj, int oldValue, int newValue)
		{
			OnArmyCompositionChanged();
		}

		public ICollection<IRequirement> GetRequirements ()
		{
			return Race.GetRequirements();
		}

		public ICollection<IRequirement> GetAddingUnitRequirements(UnitType addingType)
		{
			Unit[] units = GetUnits();
			SimpleSet<UnitType> unitTypes = new SimpleSet<UnitType>();
			unitTypes.Add(addingType);

			foreach (Unit unit in units)
			{
				unitTypes.Add(unit.UnitType);
			}

			SimpleSet<IRequirement> requirements = new SimpleSet<IRequirement>();

			foreach (UnitType unitType in unitTypes)
			{
				requirements.AddRange(unitType.GetRequirements());
			}

			return requirements;
		}

		internal void OnArmyCompositionChanged()
		{
			if (ArmyCompositionChanged != null)
			{
				ArmyCompositionChanged();
			}
		}
	}
}