GroupComposite Load(XElement xml, GroupComposite comp)
{
foreach (XNode node in xml.Nodes())
{
if (node.NodeType == XmlNodeType.Comment)
{
comp.AddChild(new Comment(((XComment)node).Value));
}
else if (node.NodeType == XmlNodeType.Element)
{
var element = (XElement)node;
Type type = Type.GetType("HighVoltz.Composites." + element.Name);
if (type == null)
{
IEnumerable<Type> pbTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where (typeof(IPBComposite)).IsAssignableFrom(t) && !t.IsAbstract
select t;
type = pbTypes.FirstOrDefault(t => t.GetCustomAttributes(typeof(XmlRootAttribute), true).Any(a => ((XmlRootAttribute)a).ElementName == element.Name));
if (type == null)
throw new InvalidOperationException(string.Format("Unable to bind XML Element: {0} to a Type", element.Name));
}
var pbComp = (IPBComposite)Activator.CreateInstance(type);
pbComp.OnProfileLoad(element);
var pbXmlAttrs = from pi in type.GetProperties()
from attr in (PbXmlAttributeAttribute[])pi.GetCustomAttributes(typeof(PbXmlAttributeAttribute), true)
where attr != null
let name = attr.AttributeName ?? pi.Name
select new { name, pi };
Dictionary<string, PropertyInfo> piDict = pbXmlAttrs.ToDictionary(kv => kv.name, kv => kv.pi);
Dictionary<string, string> attributes = element.Attributes().ToDictionary(k => k.Name.ToString(), v => v.Value);
// use legacy X,Y,Z location for backwards compatability
if (attributes.ContainsKey("X"))
{
string location = string.Format("{0},{1},{2}", attributes["X"], attributes["Y"], attributes["Z"]);
piDict["Location"].SetValue(pbComp, location, null);
attributes.Remove("X");
attributes.Remove("Y");
attributes.Remove("Z");
}
foreach (KeyValuePair<string, string> attr in attributes)
{
if (piDict.ContainsKey(attr.Key))
{
PropertyInfo pi = piDict[attr.Key];
// check if there is a type converter attached
var typeConverterAttr = (TypeConverterAttribute)pi.GetCustomAttributes(typeof(TypeConverterAttribute), true).FirstOrDefault();
if (typeConverterAttr != null)
{
try
{
var typeConverter = (TypeConverter)Activator.CreateInstance(Type.GetType(typeConverterAttr.ConverterTypeName));
if (typeConverter.CanConvertFrom(typeof(string)))
{
pi.SetValue(pbComp, typeConverter.ConvertFrom(null, System.Globalization.CultureInfo.CurrentCulture, attr.Value), null);
}
else
Professionbuddy.Err("The TypeConvert {0} can not convert from string.", typeConverterAttr.ConverterTypeName);
}
catch (Exception ex)
{
Professionbuddy.Err("Type conversion for {0} has failed.\n{1}", type.Name + attr.Key, ex);
}
}
else
{
pi.SetValue(pbComp,
pi.PropertyType.IsEnum
? Enum.Parse(pi.PropertyType, attr.Value)
: Convert.ChangeType(attr.Value, pi.PropertyType), null);
}
}
else
Professionbuddy.Log("{0}->{1} appears to be unused", type,attr.Key);
}
if (pbComp is GroupComposite)
Load(element, pbComp as GroupComposite);
comp.AddChild((Composite)pbComp);
}
}
return comp;
}