changeset 495:55b39514cbf8

Fixes #424: Basic HTML export is broken on Windows * Update to use new triple-valued AddMapping call for relative URIs Also: * Fix up double indents
author IBBoard <dev@ibboard.co.uk>
date Sat, 01 Sep 2012 12:04:03 +0100
parents 4f01fdc3bb41
children 00d6cf940c3c
files API/Exporters/WarFoundryHtmlExporter.cs
diffstat 1 files changed, 356 insertions(+), 353 deletions(-) [+]
line diff
     1.1 --- a/API/Exporters/WarFoundryHtmlExporter.cs	Mon Aug 06 20:50:59 2012 +0100
     1.2 +++ b/API/Exporters/WarFoundryHtmlExporter.cs	Sat Sep 01 12:04:03 2012 +0100
     1.3 @@ -1,7 +1,6 @@
     1.4  // This file (WarFoundryHtmlExporter.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard
     1.5  // 
     1.6  // 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.
     1.7 -
     1.8  using System;
     1.9  using System.Collections.Generic;
    1.10  using System.IO;
    1.11 @@ -16,376 +15,380 @@
    1.12  
    1.13  namespace IBBoard.WarFoundry.API.Exporters
    1.14  {
    1.15 -		/// <summary>
    1.16 -		/// Custom exporter that exports an army as a basic HTML file
    1.17 -		/// </summary>
    1.18 -		public class WarFoundryHtmlExporter : IWarFoundryExporter
    1.19 +	/// <summary>
    1.20 +	/// Custom exporter that exports an army as a basic HTML file
    1.21 +	/// </summary>
    1.22 +	public class WarFoundryHtmlExporter : IWarFoundryExporter
    1.23 +	{
    1.24 +		private static WarFoundryHtmlExporter exporter;
    1.25 +		private delegate string GetStatCellTextDelegate(Stat stat);
    1.26 +		
    1.27 +		public static WarFoundryHtmlExporter GetDefault()
    1.28  		{
    1.29 -				private static WarFoundryHtmlExporter exporter;
    1.30 -				private delegate string GetStatCellTextDelegate(Stat stat);
    1.31 +			if (exporter == null)
    1.32 +			{
    1.33 +				exporter = new WarFoundryHtmlExporter();
    1.34 +			}
    1.35 +			
    1.36 +			return exporter;
    1.37 +		}
    1.38  		
    1.39 -				public static WarFoundryHtmlExporter GetDefault()
    1.40 +		private WarFoundryHtmlExporter()
    1.41 +		{
    1.42 +			//Hide constructor
    1.43 +		}
    1.44 +		
    1.45 +		public void ExportArmy(Army army, string path)
    1.46 +		{
    1.47 +			XmlDocument doc = new XmlDocument();
    1.48 +			XmlResourceResolver resolver = new XmlResourceResolver(Assembly.GetExecutingAssembly());
    1.49 +			string uriPre = "http://www.w3.org/TR/xhtml1/DTD/";
    1.50 +			string resPre = "IBBoard.WarFoundry.schemas.";
    1.51 +			resolver.AddMapping("-//W3C//ENTITIES Latin 1 for XHTML//EN", uriPre + "xhtml-lat1.ent", resPre + "xhtml-lat1.ent");
    1.52 +			resolver.AddMapping("-//W3C//ENTITIES Symbols for XHTML//EN", uriPre + "xhtml-symbol.ent", resPre + "xhtml-symbol.ent");
    1.53 +			resolver.AddMapping("-//W3C//ENTITIES Special for XHTML//EN", uriPre + "xhtml-special.ent", resPre + "xhtml-special.ent");
    1.54 +			resolver.AddMapping("-//W3C//DTD XHTML 1.0 Strict//EN", uriPre + "xhtml1-strict.dtd", resPre + "xhtml1-strict.dtd");
    1.55 +			doc.XmlResolver = resolver;
    1.56 +			doc.AppendChild(doc.CreateDocumentType("html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", null));
    1.57 +			XmlElement html = doc.CreateElement("html");
    1.58 +			doc.AppendChild(html);
    1.59 +			XmlElement head = doc.CreateElement("head");
    1.60 +			html.AppendChild(head);
    1.61 +			XmlElement title = doc.CreateElement("title");
    1.62 +			title.InnerXml = army.Name;
    1.63 +			head.AppendChild(title);
    1.64 +			XmlElement metaCharset = doc.CreateElement("meta");
    1.65 +			metaCharset.SetAttribute("http-equiv", "Content-Type");
    1.66 +			metaCharset.SetAttribute("content", "text/html;charset=UTF-8");
    1.67 +			head.AppendChild(metaCharset);
    1.68 +			XmlElement style = doc.CreateElement("style");
    1.69 +			style.InnerText = "table, th, td { border: 1px solid #000; border-spacing: 0; border-collapse: collapse; margin: 0 }\n"
    1.70 +				+ "table table { width: 100%; border-width: 0; margin: -2px }\n"
    1.71 +				+ "table table td { border-width:0 1px }";
    1.72 +			head.AppendChild(style);
    1.73 +			XmlElement body = doc.CreateElement("body");
    1.74 +			html.AppendChild(body);
    1.75 +			XmlElement header = doc.CreateElement("h1");
    1.76 +			header.InnerText = Translation.GetTranslation("armyHtmlOutputBodyHeader", "{0} - {1}pts", army.Name, army.Points);
    1.77 +			body.AppendChild(header);
    1.78 +			
    1.79 +			foreach (XmlElement table in CreateTables(army, doc))
    1.80 +			{
    1.81 +				if (!IsTableOnlyHeader(table))
    1.82  				{
    1.83 -						if (exporter == null)
    1.84 +					body.AppendChild(table);
    1.85 +				}
    1.86 +			}
    1.87 +
    1.88 +			File.WriteAllText(path, doc.OuterXml);
    1.89 +		}
    1.90 +
    1.91 +		private bool IsTableOnlyHeader(XmlElement table)
    1.92 +		{
    1.93 +			return table.ChildNodes.Count == 1;
    1.94 +		}
    1.95 +		
    1.96 +		private XmlElement[] CreateTables(Army army, XmlDocument doc)
    1.97 +		{
    1.98 +			Dictionary<string, XmlElement> tables = new Dictionary<string, XmlElement>();
    1.99 +			
   1.100 +			foreach (SystemStats statSets in army.GameSystem.SystemStats)
   1.101 +			{
   1.102 +				tables[statSets.ID] = CreateTable(statSets, doc);
   1.103 +			}
   1.104 +			
   1.105 +			foreach (Unit unit in army.GetUnits())
   1.106 +			{
   1.107 +				CreateUnitRow(unit, tables[GetFirstStatType(unit)]);
   1.108 +			}
   1.109 +			
   1.110 +			return DictionaryUtils.ToArray(tables);
   1.111 +		}
   1.112 +
   1.113 +		private static string GetFirstStatType(Unit unit)
   1.114 +		{
   1.115 +			string[] unitStatIDs = unit.UnitStatsArrayIDs;
   1.116 +			return GetFirstStatType(unitStatIDs);
   1.117 +		}
   1.118 +		
   1.119 +		public static string GetFirstStatType(string[] unitStatIDs)
   1.120 +		{
   1.121 +			return unitStatIDs[0];
   1.122 +		}
   1.123 +		
   1.124 +		private XmlElement CreateTable(SystemStats stats, XmlDocument doc)
   1.125 +		{
   1.126 +			XmlElement table = doc.CreateElement("table");
   1.127 +			XmlElement headerRow = doc.CreateElement("tr");
   1.128 +			table.AppendChild(headerRow);
   1.129 +			XmlElement name = doc.CreateElement("th");
   1.130 +			name.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitName", "name");
   1.131 +			headerRow.AppendChild(name);
   1.132 +			
   1.133 +			XmlElement unitTypeName = doc.CreateElement("th");
   1.134 +			unitTypeName.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitTypeName", "type name");
   1.135 +			headerRow.AppendChild(unitTypeName);
   1.136 +			
   1.137 +			foreach (StatSlot stat in stats.StatSlots)
   1.138 +			{
   1.139 +				XmlElement statHeader = doc.CreateElement("th");
   1.140 +				statHeader.InnerText = stat.Name;
   1.141 +				headerRow.AppendChild(statHeader);
   1.142 +			}
   1.143 +			
   1.144 +			XmlElement notes = doc.CreateElement("th");
   1.145 +			notes.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitNotes", "name");
   1.146 +			;
   1.147 +			headerRow.AppendChild(notes);
   1.148 +			
   1.149 +			XmlElement points = doc.CreateElement("th");
   1.150 +			points.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitPoints", "name");
   1.151 +			;
   1.152 +			headerRow.AppendChild(points);
   1.153 +			
   1.154 +			return table;
   1.155 +		}
   1.156 +		
   1.157 +		private XmlElement CreateUnitRow(Unit unit, XmlElement tableElem)
   1.158 +		{
   1.159 +			XmlDocument doc = tableElem.OwnerDocument;
   1.160 +			XmlElement row = doc.CreateElement("tr");
   1.161 +			tableElem.AppendChild(row);
   1.162 +			Stat[][] memberStats = unit.UnitStatsArraysWithName;
   1.163 +			string[] statTypeIDs = unit.UnitStatsArrayIDs;
   1.164 +			string defaultStatType = GetFirstStatType(statTypeIDs);
   1.165 +			int statRowCount = 0;
   1.166 +			bool hasOther = false;
   1.167 +			
   1.168 +			foreach (string statTypeID in statTypeIDs)
   1.169 +			{
   1.170 +				if (statTypeID.Equals(defaultStatType))
   1.171 +				{
   1.172 +					statRowCount++;
   1.173 +				}
   1.174 +				else if (!hasOther)
   1.175 +				{
   1.176 +					statRowCount++;
   1.177 +					hasOther = true;
   1.178 +				}
   1.179 +			}
   1.180 +			
   1.181 +			XmlElement name = doc.CreateElement("td");
   1.182 +			name.InnerText = unit.Name;
   1.183 +			SetRowSpan(name, statRowCount);
   1.184 +			row.AppendChild(name);
   1.185 +			CreateStatsBlock(row, memberStats, statTypeIDs);
   1.186 +
   1.187 +			StringBuilder sb = new StringBuilder();
   1.188 +			UnitEquipmentItem[] unitEquipment = unit.GetEquipment();
   1.189 +			
   1.190 +			if (unitEquipment.Length > 0)
   1.191 +			{
   1.192 +				bool addSeparator = false;
   1.193 +				
   1.194 +				foreach (UnitEquipmentItem equip in unitEquipment)
   1.195 +				{
   1.196 +					if (!addSeparator)
   1.197 +					{
   1.198 +						addSeparator = true;
   1.199 +					}
   1.200 +					else
   1.201 +					{
   1.202 +						sb.Append(", ");
   1.203 +					}
   1.204 +
   1.205 +					string amountString;
   1.206 +					double amount = UnitEquipmentUtil.GetEquipmentAmount(unit, equip);
   1.207 +
   1.208 +					if (UnitEquipmentUtil.GetEquipmentAmountIsRatio(unit, equip))
   1.209 +					{
   1.210 +
   1.211 +						if (amount == 100)
   1.212  						{
   1.213 -								exporter = new WarFoundryHtmlExporter();
   1.214 +							amountString = GetEquipmentAmountAllTranslation(unit);
   1.215  						}
   1.216 +						else
   1.217 +						{
   1.218 +							int number = UnitEquipmentUtil.GetEquipmentAmountTaken(unit, equip);
   1.219 +							amountString = GetEquipmentAmountRatioTranslation(amount, number);
   1.220 +						}
   1.221 +					}
   1.222 +					else
   1.223 +					{
   1.224 +						if (amount == -1)
   1.225 +						{
   1.226 +							amountString = GetEquipmentAmountAllTranslation(unit);
   1.227 +						}
   1.228 +						else
   1.229 +						{
   1.230 +							amountString = GetEquipmentAmountNumberTranslation((int)amount);
   1.231 +						}
   1.232 +					}
   1.233 +
   1.234 +					sb.Append(Translation.GetTranslation("armyHtmlExportEquipAmountRatio", "{0} for {1}", equip.Name, amountString));
   1.235 +				}
   1.236 +				
   1.237 +				sb.Append(". ");
   1.238 +			}
   1.239  			
   1.240 -						return exporter;
   1.241 +			ICollection<Ability> abilities = unit.Abilities;
   1.242 +			
   1.243 +			if (abilities.Count > 0)
   1.244 +			{
   1.245 +				bool addSeparator = false;
   1.246 +				
   1.247 +				foreach (Ability ability in abilities)
   1.248 +				{
   1.249 +					if (!addSeparator)
   1.250 +					{
   1.251 +						addSeparator = true;
   1.252 +					}
   1.253 +					else
   1.254 +					{
   1.255 +						sb.Append(", ");
   1.256 +					}
   1.257 +					
   1.258 +					sb.Append(ability.Name);
   1.259  				}
   1.260 +				
   1.261 +				sb.Append(". ");
   1.262 +			}
   1.263 +			
   1.264 +			XmlElement notes = doc.CreateElement("td");
   1.265 +			notes.InnerText = sb.ToString();
   1.266 +			SetRowSpan(notes, statRowCount);
   1.267 +			row.AppendChild(notes);
   1.268 +			
   1.269 +			XmlElement points = doc.CreateElement("td");
   1.270 +			points.InnerText = unit.Points.ToString();
   1.271 +			SetRowSpan(points, statRowCount);
   1.272 +			row.AppendChild(points);
   1.273 +			
   1.274 +			return row;
   1.275 +		}
   1.276  		
   1.277 -				private WarFoundryHtmlExporter()
   1.278 +		private static void SetRowSpan(XmlElement xmlElement, int statRowCount)
   1.279 +		{
   1.280 +			if (statRowCount > 1)
   1.281 +			{
   1.282 +				xmlElement.SetAttribute("rowspan", statRowCount.ToString());
   1.283 +			}
   1.284 +		}
   1.285 +		
   1.286 +		private void CreateStatsBlock(XmlElement unitRow, Stat[][] memberStats, string[] statTypeIDs)
   1.287 +		{
   1.288 +			XmlDocument doc = unitRow.OwnerDocument;
   1.289 +			string defaultStatType = GetFirstStatType(statTypeIDs);
   1.290 +			
   1.291 +			Stat[] defaultStatLine = memberStats[0];
   1.292 +			int defaultStatLineCount = defaultStatLine.Length;
   1.293 +			AddStatCell(defaultStatLine[0].SlotValueString, unitRow);
   1.294 +			
   1.295 +			for (int i = 1; i < defaultStatLineCount; i++)
   1.296 +			{
   1.297 +				string statText = GetDefaultStatCellText(defaultStatLine[i]);
   1.298 +				AddStatCell(statText, unitRow);
   1.299 +			}
   1.300 +			
   1.301 +			int statCount = statTypeIDs.Length;
   1.302 +			
   1.303 +			if (statCount > 1)
   1.304 +			{
   1.305 +				XmlElement unitTable = (XmlElement)unitRow.ParentNode;
   1.306 +				Dictionary<string, XmlElement> statParents = CreateStatsParentElements(statTypeIDs, unitTable);
   1.307 +				
   1.308 +				for (int i = 1; i < statCount; i++)
   1.309  				{
   1.310 -						//Hide constructor
   1.311 +					Stat[] statLine = memberStats[i];
   1.312 +					string statTypeID = statTypeIDs[i];
   1.313 +					XmlElement tableElement = DictionaryUtils.GetValue(statParents, statTypeID);
   1.314 +					int statLineCount = statLine.Length;
   1.315 +					XmlElement statRow = doc.CreateElement("tr");
   1.316 +					tableElement.AppendChild(statRow);
   1.317 +					GetStatCellTextDelegate statCellTextDelegate = (statTypeID.Equals(defaultStatType) ? new GetStatCellTextDelegate(GetDefaultStatCellText) : new GetStatCellTextDelegate(GetOtherStatCellText));
   1.318 +					AddStatCell(statLine[0].SlotValueString, statRow);
   1.319 +				
   1.320 +					for (int j = 1; j < statLineCount; j++)
   1.321 +					{
   1.322 +						string statText = statCellTextDelegate(statLine[j]);
   1.323 +						AddStatCell(statText, statRow);
   1.324 +					}
   1.325  				}
   1.326 +				
   1.327 +				if (statParents.Count > 1)
   1.328 +				{
   1.329 +					AddOtherUnitStatTables(statParents, unitTable, defaultStatLineCount);
   1.330 +				}
   1.331 +			}
   1.332 +		}
   1.333  		
   1.334 -				public void ExportArmy(Army army, string path)
   1.335 +		private static void AddOtherUnitStatTables(Dictionary<string, XmlElement> statParents, XmlElement unitTable, int defaultStatLineCount)
   1.336 +		{
   1.337 +			XmlDocument doc = unitTable.OwnerDocument;
   1.338 +			XmlElement otherStatsRow = doc.CreateElement("tr");
   1.339 +			unitTable.AppendChild(otherStatsRow);
   1.340 +			XmlElement otherStatsCell = doc.CreateElement("td");
   1.341 +			otherStatsCell.SetAttribute("colspan", defaultStatLineCount.ToString());
   1.342 +			otherStatsRow.AppendChild(otherStatsCell);
   1.343 +			
   1.344 +			foreach (XmlElement tableElem in statParents.Values)
   1.345 +			{
   1.346 +				if (tableElem != unitTable)
   1.347  				{
   1.348 -						XmlDocument doc = new XmlDocument();
   1.349 -						XmlResourceResolver resolver = new XmlResourceResolver(Assembly.GetExecutingAssembly());
   1.350 -						resolver.AddMapping("-//W3C//ENTITIES Latin 1 for XHTML//EN", "IBBoard.API.schemas.xhtml1-lat1.ent");
   1.351 -						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent", "IBBoard.API.schemas.xhtml1-lat1.ent");
   1.352 -						resolver.AddMapping("-//W3C//ENTITIES Symbols for XHTML//EN", "IBBoard.API.schemas.xhtml1-symbol.ent");
   1.353 -						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent", "IBBoard.API.schemas.xhtml1-symbol.ent");
   1.354 -						resolver.AddMapping("-//W3C//ENTITIES Special for XHTML//EN", "IBBoard.API.schemas.xhtml1-special.ent");
   1.355 -						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent", "IBBoard.API.schemas.xhtml1-special.ent");
   1.356 -						resolver.AddMapping("-//W3C//DTD XHTML 1.0 Strict//EN", "IBBoard.WarFoundry.schemas.xhtml1-strict.dtd");
   1.357 -						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", "IBBoard.WarFoundry.schemas.xhtml1-strict.dtd");
   1.358 -						doc.XmlResolver = resolver;
   1.359 -						doc.AppendChild(doc.CreateDocumentType("html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", null));
   1.360 -						XmlElement html = doc.CreateElement("html");
   1.361 -						doc.AppendChild(html);
   1.362 -						XmlElement head = doc.CreateElement("head");
   1.363 -						html.AppendChild(head);
   1.364 -						XmlElement title = doc.CreateElement("title");
   1.365 -						title.InnerXml = army.Name;
   1.366 -						head.AppendChild(title);
   1.367 -						XmlElement metaCharset = doc.CreateElement("meta");
   1.368 -						metaCharset.SetAttribute("http-equiv", "Content-Type");
   1.369 -						metaCharset.SetAttribute("content", "text/html;charset=UTF-8");
   1.370 -						head.AppendChild(metaCharset);
   1.371 -						XmlElement style = doc.CreateElement("style");
   1.372 -						style.InnerText = "table, th, td { border: 1px solid #000; border-spacing: 0; border-collapse: collapse; margin: 0 }\n"
   1.373 -								+ "table table { width: 100%; border-width: 0; margin: -2px }\n"
   1.374 -								+ "table table td { border-width:0 1px }";
   1.375 -						head.AppendChild(style);
   1.376 -						XmlElement body = doc.CreateElement("body");
   1.377 -						html.AppendChild(body);
   1.378 -						XmlElement header = doc.CreateElement("h1");
   1.379 -						header.InnerText = Translation.GetTranslation("armyHtmlOutputBodyHeader", "{0} - {1}pts", army.Name, army.Points);
   1.380 -						body.AppendChild(header);
   1.381 +					otherStatsCell.AppendChild(tableElem);
   1.382 +				}
   1.383 +			}
   1.384 +		}
   1.385 +
   1.386 +		private Dictionary<string, XmlElement> CreateStatsParentElements(string[] statTypeIDs, XmlElement parentTable)
   1.387 +		{
   1.388 +			Dictionary<string, XmlElement> statParents = new Dictionary<string, XmlElement>();
   1.389 +			XmlDocument doc = parentTable.OwnerDocument;
   1.390 +			string defaultStatTypeID = GetFirstStatType(statTypeIDs);
   1.391 +			statParents[defaultStatTypeID] = parentTable;
   1.392  			
   1.393 -						foreach (XmlElement table in CreateTables(army, doc))
   1.394 -						{
   1.395 -								if (!IsTableOnlyHeader(table))
   1.396 -								{
   1.397 -										body.AppendChild(table);
   1.398 -								}
   1.399 -						}
   1.400 +			foreach (string statTypeID in statTypeIDs)
   1.401 +			{
   1.402 +				if (!statParents.ContainsKey(statTypeID))
   1.403 +				{
   1.404 +					XmlElement tableElement = doc.CreateElement("table");
   1.405 +					statParents[statTypeID] = tableElement;
   1.406 +				}
   1.407 +			}
   1.408 +			
   1.409 +			return statParents;
   1.410 +		}
   1.411  
   1.412 -						File.WriteAllText(path, doc.OuterXml);
   1.413 -				}
   1.414 +		private string GetDefaultStatCellText(Stat stat)
   1.415 +		{
   1.416 +			return Translation.GetTranslation("armyHtmlExportDefaultStatCellText", "{0}", stat.SlotValueString, stat.ParentSlotName);
   1.417 +		}
   1.418  
   1.419 -				private bool IsTableOnlyHeader(XmlElement table)
   1.420 -				{
   1.421 -						return table.ChildNodes.Count == 1;
   1.422 -				}
   1.423 +		private string GetOtherStatCellText(Stat stat)
   1.424 +		{
   1.425 +			return Translation.GetTranslation("armyHtmlExportOtherStatCellText", "{1}: {0}", stat.SlotValueString, stat.ParentSlotName);
   1.426 +		}
   1.427  		
   1.428 -				private XmlElement[] CreateTables(Army army, XmlDocument doc)
   1.429 -				{
   1.430 -						Dictionary<string, XmlElement> tables = new Dictionary<string, XmlElement>();
   1.431 -			
   1.432 -						foreach (SystemStats statSets in army.GameSystem.SystemStats)
   1.433 -						{
   1.434 -								tables[statSets.ID] = CreateTable(statSets, doc);
   1.435 -						}
   1.436 -			
   1.437 -						foreach (Unit unit in army.GetUnits())
   1.438 -						{
   1.439 -								CreateUnitRow(unit, tables[GetFirstStatType(unit)]);
   1.440 -						}
   1.441 -			
   1.442 -						return DictionaryUtils.ToArray(tables);
   1.443 -				}
   1.444 -
   1.445 -				private static string GetFirstStatType(Unit unit)
   1.446 -				{
   1.447 -						string[] unitStatIDs = unit.UnitStatsArrayIDs;
   1.448 -						return GetFirstStatType(unitStatIDs);
   1.449 -				}
   1.450 +		private static void AddStatCell(string statValue, XmlElement row)
   1.451 +		{
   1.452 +			XmlElement statCell = row.OwnerDocument.CreateElement("td");
   1.453 +			statCell.InnerText = statValue;
   1.454 +			row.AppendChild(statCell);
   1.455 +		}
   1.456  		
   1.457 -				public static string GetFirstStatType(string[] unitStatIDs)
   1.458 -				{
   1.459 -						return unitStatIDs[0];
   1.460 -				}
   1.461 +		private string GetEquipmentAmountRatioTranslation(double amount, int number)
   1.462 +		{
   1.463 +			return Translation.GetTranslation("armyHtmlExportEquipAmountPercentage", "{0}% ({1})", amount, number);
   1.464 +		}
   1.465  		
   1.466 -				private XmlElement CreateTable(SystemStats stats, XmlDocument doc)
   1.467 -				{
   1.468 -						XmlElement table = doc.CreateElement("table");
   1.469 -						XmlElement headerRow = doc.CreateElement("tr");
   1.470 -						table.AppendChild(headerRow);
   1.471 -						XmlElement name = doc.CreateElement("th");
   1.472 -						name.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitName", "name");
   1.473 -						headerRow.AppendChild(name);
   1.474 -			
   1.475 -						XmlElement unitTypeName = doc.CreateElement("th");
   1.476 -						unitTypeName.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitTypeName", "type name");
   1.477 -						headerRow.AppendChild(unitTypeName);
   1.478 -			
   1.479 -						foreach (StatSlot stat in stats.StatSlots)
   1.480 -						{
   1.481 -								XmlElement statHeader = doc.CreateElement("th");
   1.482 -								statHeader.InnerText = stat.Name;
   1.483 -								headerRow.AppendChild(statHeader);
   1.484 -						}
   1.485 -			
   1.486 -						XmlElement notes = doc.CreateElement("th");
   1.487 -						notes.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitNotes", "name");
   1.488 -						;
   1.489 -						headerRow.AppendChild(notes);
   1.490 -			
   1.491 -						XmlElement points = doc.CreateElement("th");
   1.492 -						points.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitPoints", "name");
   1.493 -						;
   1.494 -						headerRow.AppendChild(points);
   1.495 -			
   1.496 -						return table;
   1.497 -				}
   1.498 +		private string GetEquipmentAmountNumberTranslation(int amount)
   1.499 +		{
   1.500 +			return Translation.GetTranslation("armyHtmlExportEquipAmountNumber", "{0}", amount);
   1.501 +		}
   1.502  		
   1.503 -				private XmlElement CreateUnitRow(Unit unit, XmlElement tableElem)
   1.504 -				{
   1.505 -						XmlDocument doc = tableElem.OwnerDocument;
   1.506 -						XmlElement row = doc.CreateElement("tr");
   1.507 -						tableElem.AppendChild(row);
   1.508 -						Stat[][] memberStats = unit.UnitStatsArraysWithName;
   1.509 -						string[] statTypeIDs = unit.UnitStatsArrayIDs;
   1.510 -						string defaultStatType = GetFirstStatType(statTypeIDs);
   1.511 -						int statRowCount = 0;
   1.512 -						bool hasOther = false;
   1.513 -			
   1.514 -						foreach (string statTypeID in statTypeIDs)
   1.515 -						{
   1.516 -								if (statTypeID.Equals(defaultStatType))
   1.517 -								{
   1.518 -										statRowCount++;
   1.519 -								} else if (!hasOther)
   1.520 -								{
   1.521 -										statRowCount++;
   1.522 -										hasOther = true;
   1.523 -								}
   1.524 -						}
   1.525 -			
   1.526 -						XmlElement name = doc.CreateElement("td");
   1.527 -						name.InnerText = unit.Name;
   1.528 -						SetRowSpan(name, statRowCount);
   1.529 -						row.AppendChild(name);
   1.530 -						CreateStatsBlock(row, memberStats, statTypeIDs);
   1.531 -
   1.532 -						StringBuilder sb = new StringBuilder();
   1.533 -						UnitEquipmentItem[] unitEquipment = unit.GetEquipment();
   1.534 -			
   1.535 -						if (unitEquipment.Length > 0)
   1.536 -						{
   1.537 -								bool addSeparator = false;
   1.538 -				
   1.539 -								foreach (UnitEquipmentItem equip in unitEquipment)
   1.540 -								{
   1.541 -										if (!addSeparator)
   1.542 -										{
   1.543 -												addSeparator = true;
   1.544 -										} else
   1.545 -										{
   1.546 -												sb.Append(", ");
   1.547 -										}
   1.548 -
   1.549 -										string amountString;
   1.550 -										double amount = UnitEquipmentUtil.GetEquipmentAmount(unit, equip);
   1.551 -
   1.552 -										if (UnitEquipmentUtil.GetEquipmentAmountIsRatio(unit, equip))
   1.553 -										{
   1.554 -
   1.555 -												if (amount == 100)
   1.556 -												{
   1.557 -														amountString = GetEquipmentAmountAllTranslation(unit);
   1.558 -												} else
   1.559 -												{
   1.560 -														int number = UnitEquipmentUtil.GetEquipmentAmountTaken(unit, equip);
   1.561 -														amountString = GetEquipmentAmountRatioTranslation(amount, number);
   1.562 -												}
   1.563 -										} else
   1.564 -										{
   1.565 -												if (amount == -1)
   1.566 -												{
   1.567 -														amountString = GetEquipmentAmountAllTranslation(unit);
   1.568 -												} else
   1.569 -												{
   1.570 -														amountString = GetEquipmentAmountNumberTranslation((int)amount);
   1.571 -												}
   1.572 -										}
   1.573 -
   1.574 -										sb.Append(Translation.GetTranslation("armyHtmlExportEquipAmountRatio", "{0} for {1}", equip.Name, amountString));
   1.575 -								}
   1.576 -				
   1.577 -								sb.Append(". ");
   1.578 -						}
   1.579 -			
   1.580 -						ICollection<Ability> abilities = unit.Abilities;
   1.581 -			
   1.582 -						if (abilities.Count > 0)
   1.583 -						{
   1.584 -								bool addSeparator = false;
   1.585 -				
   1.586 -								foreach (Ability ability in abilities)
   1.587 -								{
   1.588 -										if (!addSeparator)
   1.589 -										{
   1.590 -												addSeparator = true;
   1.591 -										} else
   1.592 -										{
   1.593 -												sb.Append(", ");
   1.594 -										}
   1.595 -					
   1.596 -										sb.Append(ability.Name);
   1.597 -								}
   1.598 -				
   1.599 -								sb.Append(". ");
   1.600 -						}
   1.601 -			
   1.602 -						XmlElement notes = doc.CreateElement("td");
   1.603 -						notes.InnerText = sb.ToString();
   1.604 -						SetRowSpan(notes, statRowCount);
   1.605 -						row.AppendChild(notes);
   1.606 -			
   1.607 -						XmlElement points = doc.CreateElement("td");
   1.608 -						points.InnerText = unit.Points.ToString();
   1.609 -						SetRowSpan(points, statRowCount);
   1.610 -						row.AppendChild(points);
   1.611 -			
   1.612 -						return row;
   1.613 -				}
   1.614 -		
   1.615 -				private static void SetRowSpan(XmlElement xmlElement, int statRowCount)
   1.616 -				{
   1.617 -						if (statRowCount > 1)
   1.618 -						{
   1.619 -								xmlElement.SetAttribute("rowspan", statRowCount.ToString());
   1.620 -						}
   1.621 -				}
   1.622 -		
   1.623 -				private void CreateStatsBlock(XmlElement unitRow, Stat[][] memberStats, string[] statTypeIDs)
   1.624 -				{
   1.625 -						XmlDocument doc = unitRow.OwnerDocument;
   1.626 -						string defaultStatType = GetFirstStatType(statTypeIDs);
   1.627 -			
   1.628 -						Stat[] defaultStatLine = memberStats[0];
   1.629 -						int defaultStatLineCount = defaultStatLine.Length;
   1.630 -						AddStatCell(defaultStatLine[0].SlotValueString, unitRow);
   1.631 -			
   1.632 -						for (int i = 1; i < defaultStatLineCount; i++)
   1.633 -						{
   1.634 -								string statText = GetDefaultStatCellText(defaultStatLine[i]);
   1.635 -								AddStatCell(statText, unitRow);
   1.636 -						}
   1.637 -			
   1.638 -						int statCount = statTypeIDs.Length;
   1.639 -			
   1.640 -						if (statCount > 1)
   1.641 -						{
   1.642 -								XmlElement unitTable = (XmlElement)unitRow.ParentNode;
   1.643 -								Dictionary<string, XmlElement> statParents = CreateStatsParentElements(statTypeIDs, unitTable);
   1.644 -				
   1.645 -								for (int i = 1; i < statCount; i++)
   1.646 -								{
   1.647 -										Stat[] statLine = memberStats[i];
   1.648 -										string statTypeID = statTypeIDs[i];
   1.649 -										XmlElement tableElement = DictionaryUtils.GetValue(statParents, statTypeID);
   1.650 -										int statLineCount = statLine.Length;
   1.651 -										XmlElement statRow = doc.CreateElement("tr");
   1.652 -										tableElement.AppendChild(statRow);
   1.653 -										GetStatCellTextDelegate statCellTextDelegate = (statTypeID.Equals(defaultStatType) ? new GetStatCellTextDelegate(GetDefaultStatCellText) : new GetStatCellTextDelegate(GetOtherStatCellText));
   1.654 -										AddStatCell(statLine[0].SlotValueString, statRow);
   1.655 -				
   1.656 -										for (int j = 1; j < statLineCount; j++)
   1.657 -										{
   1.658 -												string statText = statCellTextDelegate(statLine[j]);
   1.659 -												AddStatCell(statText, statRow);
   1.660 -										}
   1.661 -								}
   1.662 -				
   1.663 -								if (statParents.Count > 1)
   1.664 -								{
   1.665 -										AddOtherUnitStatTables(statParents, unitTable, defaultStatLineCount);
   1.666 -								}
   1.667 -						}
   1.668 -				}
   1.669 -		
   1.670 -				private static void AddOtherUnitStatTables(Dictionary<string, XmlElement> statParents, XmlElement unitTable, int defaultStatLineCount)
   1.671 -				{
   1.672 -						XmlDocument doc = unitTable.OwnerDocument;
   1.673 -						XmlElement otherStatsRow = doc.CreateElement("tr");
   1.674 -						unitTable.AppendChild(otherStatsRow);
   1.675 -						XmlElement otherStatsCell = doc.CreateElement("td");
   1.676 -						otherStatsCell.SetAttribute("colspan", defaultStatLineCount.ToString());
   1.677 -						otherStatsRow.AppendChild(otherStatsCell);
   1.678 -			
   1.679 -						foreach (XmlElement tableElem in statParents.Values)
   1.680 -						{
   1.681 -								if (tableElem != unitTable)
   1.682 -								{
   1.683 -										otherStatsCell.AppendChild(tableElem);
   1.684 -								}
   1.685 -						}
   1.686 -				}
   1.687 -
   1.688 -				private Dictionary<string, XmlElement> CreateStatsParentElements(string[] statTypeIDs, XmlElement parentTable)
   1.689 -				{
   1.690 -						Dictionary<string, XmlElement> statParents = new Dictionary<string, XmlElement>();
   1.691 -						XmlDocument doc = parentTable.OwnerDocument;
   1.692 -						string defaultStatTypeID = GetFirstStatType(statTypeIDs);
   1.693 -						statParents[defaultStatTypeID] = parentTable;
   1.694 -			
   1.695 -						foreach (string statTypeID in statTypeIDs)
   1.696 -						{
   1.697 -								if (!statParents.ContainsKey(statTypeID))
   1.698 -								{
   1.699 -										XmlElement tableElement = doc.CreateElement("table");
   1.700 -										statParents[statTypeID] = tableElement;
   1.701 -								}
   1.702 -						}
   1.703 -			
   1.704 -						return statParents;
   1.705 -				}
   1.706 -
   1.707 -				private string GetDefaultStatCellText(Stat stat)
   1.708 -				{
   1.709 -						return Translation.GetTranslation("armyHtmlExportDefaultStatCellText", "{0}", stat.SlotValueString, stat.ParentSlotName);
   1.710 -				}
   1.711 -
   1.712 -				private string GetOtherStatCellText(Stat stat)
   1.713 -				{
   1.714 -						return Translation.GetTranslation("armyHtmlExportOtherStatCellText", "{1}: {0}", stat.SlotValueString, stat.ParentSlotName);
   1.715 -				}
   1.716 -		
   1.717 -				private static void AddStatCell(string statValue, XmlElement row)
   1.718 -				{
   1.719 -						XmlElement statCell = row.OwnerDocument.CreateElement("td");
   1.720 -						statCell.InnerText = statValue;
   1.721 -						row.AppendChild(statCell);
   1.722 -				}
   1.723 -		
   1.724 -				private string GetEquipmentAmountRatioTranslation(double amount, int number)
   1.725 -				{
   1.726 -						return Translation.GetTranslation("armyHtmlExportEquipAmountPercentage", "{0}% ({1})", amount, number);
   1.727 -				}
   1.728 -		
   1.729 -				private string GetEquipmentAmountNumberTranslation(int amount)
   1.730 -				{
   1.731 -						return Translation.GetTranslation("armyHtmlExportEquipAmountNumber", "{0}", amount);
   1.732 -				}
   1.733 -		
   1.734 -				private string GetEquipmentAmountAllTranslation(Unit unit)
   1.735 -				{
   1.736 -						return Translation.GetTranslation("armyHtmlExportEquipAmountAll", "all ({1})", 100, unit.Size);
   1.737 -				}
   1.738 +		private string GetEquipmentAmountAllTranslation(Unit unit)
   1.739 +		{
   1.740 +			return Translation.GetTranslation("armyHtmlExportEquipAmountAll", "all ({1})", 100, unit.Size);
   1.741  		}
   1.742 +	}
   1.743  }