#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using YamlDotNet.RepresentationModel;
using HEAL.Attic;
namespace HeuristicLab.BioBoost.Data {
[StorableType("ADCB9CD6-ECBD-4202-B945-0602E538D771")]
[Item("DataItem", "Generic Item for holding various pieces of information")]
public abstract class DataItem : ParameterizedNamedItem {
#region Construction & Cloning
[StorableConstructor]
protected DataItem(StorableConstructorFlag _) : base(_) { }
protected DataItem(DataItem orig, Cloner cloner) : base(orig, cloner) {}
protected DataItem() {}
#endregion
public static IEnumerable ParseFile(string filename) {
using (var reader = File.OpenText(filename)) {
return ParseStream(reader);
}
}
public abstract bool IsEquivalentTo(DataItem other);
public static IEnumerable ParseStream(TextReader reader) {
var yaml = new YamlStream();
yaml.Load(reader);
if (yaml.Documents.Count == 0) return Enumerable.Empty();
var root = yaml.Documents[0].RootNode as YamlMappingNode;
if (root == null) return Enumerable.Empty();
return ParseItems(root);
}
private static IEnumerable ParseItems(YamlMappingNode root) {
foreach (var child in root.Children) {
var type = child.Key as YamlScalarNode;
var value = child.Value as YamlSequenceNode;
if (type == null || value == null) {
// ignore or error?
} else {
switch (((string) type).ToLowerInvariant()) {
case "products":
foreach (var item in ParseSequence(value))
yield return item;
break;
case "logistics":
foreach (var item in ParseSequence(value))
yield return item;
break;
case "conversions":
foreach (var item in ParseSequence(value))
yield return item;
break;
case "cost-factors":
foreach (var item in ParseSequence(value))
yield return item;
break;
}
}
}
}
public static IEnumerable ParseSequence(YamlSequenceNode seq) where T : DataItem, new() {
foreach (var node in seq.Children) {
var mappingNode = node as YamlMappingNode;
if (mappingNode == null) continue;
var item = new T();
item.Parse(mappingNode);
yield return item;
}
}
protected virtual void Parse(YamlMappingNode node) {
foreach (var child in node) {
var parameterNode = child.Key as YamlScalarNode;
if (parameterNode == null) continue;
var parameterName = ConvertNameYAML2NET(parameterNode.ToString());
IParameter param;
if (Parameters.TryGetValue(parameterName, out param) && param is IValueParameter) {
SetParameter(param, child.Value);
}
}
// TODO: check that all parameters have been filled
}
private static void SetParameter(IParameter param, YamlNode node) {
if (node is YamlScalarNode) {
SetScalarParameter((IValueParameter) param, (YamlScalarNode) node);
} else if (node is YamlMappingNode) {
SetMappingParameter((IValueParameter) param, (YamlMappingNode) node);
} else {
// TODO: parse error/warning?
}
}
private static void SetScalarParameter(IValueParameter param, YamlScalarNode node) {
if (param.DataType == typeof(StringValue)) {
param.Value = new StringValue(node.ToString());
} else if (param.DataType == typeof(DoubleValue)) {
param.Value = new DoubleValue(Double.Parse(node.ToString(), CultureInfo.InvariantCulture));
} else {
// TODO: parse error/warning?
}
}
private static void SetMappingParameter(IValueParameter param, YamlMappingNode node) {
if (typeof (DataItem).IsAssignableFrom(param.DataType)) {
var constructorInfo = param.DataType.GetConstructor(Type.EmptyTypes);
if (constructorInfo != null) {
var item = (DataItem) constructorInfo.Invoke(new object[0]);
item.Parse(node);
param.Value = item;
return;
}
} else if (param.DataType.IsAssignableFrom(typeof(ValueParameterCollection))) {
var dict = new ValueParameterCollection();
foreach (var child in node.Children) {
var key = child.Key as YamlScalarNode;
if (key != null) {
var p = new ValueParameter(key.ToString());
SetParameter(p, child.Value);
dict.Add(p);
} else {
// TODO: parse error/warning?
}
}
param.Value = dict;
}
// TODO: parse error? warning?
}
public static IItem CreateItem(YamlNode node) {
var n = node as YamlScalarNode;
if (n == null) return null;
double d;
string s = n.ToString();
if (Double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out d)) {
return new DoubleValue(d);
} else {
return new StringValue(s);
}
}
#region Auxiliary Methods
public static string ConvertNameYAML2NET(string s) {
var sb = new StringBuilder();
foreach (var word in s.Split('-')) {
sb.Append(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(word.ToLower()));
}
return sb.ToString();
}
public static string ConvertNameNET2YAML(string s) {
return Regex.Replace(s, "([A-Z])", "-$1", RegexOptions.Compiled).Trim().ToLower();
}
#endregion
}
}