using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data.MoveVectorData.Interfaces; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; namespace HeuristicLab.Data.MoveVectorData { [Item("MoveVector", "Represents a vector of moves.")] [StorableClass] public class MoveVector : Item, IEnumerable, IStringConvertibleArray { private const int maximumToStringLength = 100; public static new Image StaticItemImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.Class; } } [Storable] protected IMove[] array; #region Parameters [Storable] protected List elementNames; public virtual IEnumerable ElementNames { get { return this.elementNames; } set { if (ReadOnly) throw new NotSupportedException("ElementNames cannot be set. ValueTypeArray is read-only."); if (value == null || !value.Any()) elementNames = new List(); else if (value.Count() > Length) throw new ArgumentException("The number of element names must not exceed the array length."); else elementNames = new List(value); OnElementNamesChanged(); } } public virtual int Length { get { return array.Length; } protected set { if (ReadOnly) throw new NotSupportedException("Length cannot be set. StringArray is read-only."); if (value != Length) { Array.Resize(ref array, value); while (elementNames.Count > value) elementNames.RemoveAt(elementNames.Count - 1); OnElementNamesChanged(); OnReset(); } } } [Storable] protected bool readOnly; public virtual bool ReadOnly { get { return readOnly; } } private IList moveTypes; public IList MoveTypes { get { if (moveTypes == null) throw new NullReferenceException("MoveTypes must not be null"); return moveTypes; } set { moveTypes = value; } } #endregion #region Cloning [StorableConstructor] protected MoveVector(bool deserializing) : base(deserializing) { } protected MoveVector(MoveVector original, Cloner cloner) : base(original, cloner) { this.array = (IMove[])original.array.Clone(); this.readOnly = original.readOnly; this.elementNames = new List(original.elementNames); this.moveTypes = new List(original.moveTypes); } public override IDeepCloneable Clone(Cloner cloner) { return new MoveVector(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (elementNames == null) { elementNames = new List(); } } public virtual MoveVector AsReadOnly() { MoveVector readOnlyStringArray = (MoveVector)this.Clone(); readOnlyStringArray.readOnly = true; return readOnlyStringArray; } #endregion public MoveVector(IList moveTypes) : this(0, moveTypes) { } public MoveVector(int length, IList moveTypes) { if (moveTypes == null) throw new NullReferenceException("MoveTypes must not be null"); array = new IMove[length]; readOnly = false; elementNames = new List(); MoveTypes = moveTypes; } public MoveVector(int length, IRandom random, IList moveTypes, int min, int max) : this(length, moveTypes) { Randomize(random, min, max); } public MoveVector(IMove[] elements, IList moveTypes) : this(elements.Length, moveTypes) { for (int i = 0; i < array.Length; i++) array[i] = elements[i]; } public override string ToString() { if (array.Length == 0) return "[]"; StringBuilder sb = new StringBuilder(); sb.Append("["); sb.Append(array[0]); for (int i = 1; i < array.Length; i++) { sb.Append(";").Append(array[i]); if (sb.Length > maximumToStringLength) { sb.Append("..."); break; } } sb.Append("]"); return sb.ToString(); } public virtual IEnumerator GetEnumerator() { return array.Cast().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } protected virtual bool Validate(string value, out string errorMessage) { if (value == null) //TODO { errorMessage = "Invalid Value (string must not be null)"; return false; } else { errorMessage = string.Empty; return true; } } public virtual IMove this[int index] { get { return array[index]; } set { if (ReadOnly) throw new NotSupportedException("Item cannot be set. StringArray is read-only."); if (value != array[index]) { if (value != null) { array[index] = value; OnItemChanged(index); } } } } protected virtual string GetValue(int index) { return this[index].ToString(); } protected virtual bool SetValue(string value, int index) { if (value != null) { this[index] = null; //TODO return true; } else { return false; } } public virtual void Randomize(IRandom random, int startIndex, int length, int min, int max, int step = 1) { if (length > 0) { for (int i = startIndex; i < startIndex + length; i++) { Type type = MoveTypes[random.Next(0, MoveTypes.Count)]; IMove move = (IMove)Activator.CreateInstance(type); move.Randomize(random, min, max, step); array[i] = move; } OnReset(); } } public virtual void Randomize(IRandom random, int startIndex, int length, IntMatrix bounds) { if (length > 0) { int min = bounds[0, 0], max = bounds[0, 1], step = 1; if (bounds.Columns > 2) step = bounds[0, 2]; Randomize(random, startIndex, length, min, max, step); } } public void Randomize(IRandom random, int min, int max, int step = 1) { Randomize(random, 0, Length, min, max, step); } public void Randomize(IRandom random, IntMatrix bounds) { Randomize(random, 0, Length, bounds); } #region Events public event EventHandler ElementNamesChanged; protected virtual void OnElementNamesChanged() { EventHandler handler = ElementNamesChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler> ItemChanged; protected virtual void OnItemChanged(int index) { if (ItemChanged != null) ItemChanged(this, new EventArgs(index)); if (index < maximumToStringLength) OnToStringChanged(); } public event EventHandler Reset; public event EventHandler ResizableChanged; protected virtual void OnReset() { if (Reset != null) Reset(this, EventArgs.Empty); OnToStringChanged(); } #endregion #region IStringConvertibleArray Members int IValueTypeArray.Length { get { return Length; } set { Length = value; } } public bool Resizable { get { return false; } set { } } bool IStringConvertibleArray.Validate(string value, out string errorMessage) { return Validate(value, out errorMessage); } string IStringConvertibleArray.GetValue(int index) { return GetValue(index); } bool IStringConvertibleArray.SetValue(string value, int index) { return SetValue(value, index); } IValueTypeArray IValueTypeArray.AsReadOnly() { throw new NotImplementedException(); } #endregion } }