using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; namespace Mono.Documentation.Updater { public class TypeMap { /// This is the core lookup data structure ... main key is language, secondary key is typename "from" Dictionary> map; public List Items { get; private set; } public string GetTypeName(string lang, string typename) { if (map == null) InitializeMap(); if (!nonsinitialized && typename.IndexOf(".") == -1) InitializeNoNamespace(); Dictionary val; if (map.TryGetValue(lang, out val)) { TypeMapItem itemMap; if (val.TryGetValue(typename, out itemMap)) { return itemMap.To; } } return typename; } bool nonsinitialized = false; private void InitializeNoNamespace() { if (nonsinitialized) return; Func chopType = (orig) => { if (orig.Contains(".")) { var lastDot = orig.LastIndexOf("."); var choppedKey = orig.Substring(lastDot+1, orig.Length - lastDot -1); return choppedKey; } return orig; }; foreach (var langitem in map.Values) { var iitem = langitem.ToArray(); foreach (var item in iitem) { string choppedKey = chopType(item.Key); TypeMapItem choppedItem = new TypeMapItem { From = choppedKey, To = chopType(item.Value.To), Langs = item.Value.Langs }; langitem[choppedKey] = choppedItem; } } } private void InitializeMap() { map = new Dictionary>(); // init the map foreach (var item in Items) { // for each language that this item applies to, make a separate entry in the map for that language foreach (var itemLang in item.LangList) { Dictionary langList; if (!map.TryGetValue(itemLang, out langList)) { langList = new Dictionary(); map.Add(itemLang, langList); } // sanitize the inputs int genIndex = item.From.IndexOf("`"); if (genIndex > 0) item.From = item.From.Substring(0, genIndex); genIndex = item.To.IndexOf("`"); if (genIndex > 0) item.To = item.To.Substring(0, genIndex); // add to the list if it's not already there if (!langList.ContainsKey(item.From)) langList.Add(item.From, item); } } } public static TypeMap FromXml(string path) { var doc = XDocument.Load(path); return FromXDocument(doc); } public static TypeMap FromXDocument(XDocument doc) { TypeMap map = new TypeMap { Items = doc.Root.Elements() .Select(e => { switch (e.Name.LocalName) { case "TypeReplace": return ItemFromElement(e); case "InterfaceReplace": var item = ItemFromElement(e); item.Members = e.Element("Members"); return item; default: Console.WriteLine($"\tUnknown element: {e.Name.LocalName}"); break; } return new TypeMapItem(); }) .ToList() }; return map; } private static T ItemFromElement(XElement e) where T: TypeMapItem, new() { return new T { From = e.Attribute("From").Value, To = e.Attribute("To").Value, Langs = e.Attribute("Langs").Value }; } public TypeMapInterfaceItem HasInterfaceReplace(string lang, string facename) { Dictionary typemap; if (map.TryGetValue(lang, out typemap)) { TypeMapItem item; if (typemap.TryGetValue(facename, out item)) { var ifaceItem = item as TypeMapInterfaceItem; if (ifaceItem != null) return ifaceItem; } } return null; } } public class TypeMapItem { public string From { get; set; } public string To { get; set; } public string Langs { get; set; } public IEnumerable LangList { get { foreach (var l in Langs.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim())) yield return l; } } } public class TypeMapInterfaceItem : TypeMapItem { public XElement Members { get; set; } public XmlElement ToXmlElement(XElement el) { var doc = new XmlDocument(); doc.Load(el.CreateReader()); var xel = doc.DocumentElement; xel.ParentNode.RemoveChild(xel); return xel; } } }