#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 } }