using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using HeuristicLab.Common;
using HeuristicLab.Core;
namespace HeuristicLab.Data {
///
/// A dictionary having key-value pairs of the type .
///
/// The type of the keys, which must implement the interface .
/// The type of the values, which must imlement the interface .
public class ItemDictionary : ItemBase, IDictionary
where K : IItem
where V : IItem{
private Dictionary dict;
///
/// Gets the dictionary of key-value pairs.
///
public Dictionary Dictionary {
get { return dict; }
}
///
/// Initializes a new instance of .
///
/// Creates a new
/// having as type of keys and values
/// and a new as .
public ItemDictionary() {
dict = new Dictionary(new IItemKeyComparer());
}
#region ItemBase Members
///
/// Creates a new instance of .
///
/// The created instance as .
public override IView CreateView() {
return new ItemDictionaryView(this);
}
///
/// Clones the current instance and adds it to the dictionary .
///
/// Also the keys and values in the dictionary are cloned and saved to the dictionary ,
/// when they are not already contained (deep copy).
/// A dictionary of all already cloned objects.
/// The cloned instance as .
public override object Clone(IDictionary clonedObjects) {
ItemDictionary clone = new ItemDictionary();
clonedObjects.Add(Guid, clone);
foreach (KeyValuePair item in dict) {
clone.dict.Add((K) Auxiliary.Clone(item.Key, clonedObjects), (V) Auxiliary.Clone(item.Value, clonedObjects));
}
return clone;
}
///
/// Saves the current instance as in the specified .
///
/// Every key-value pair is saved as new child node with the tag name "KeyValuePair".
/// In the child node the key is saved as a new child node with the tag name "Key".
/// The value is also saved as new child node with the tag name "Val".
///
/// The (tag)name of the .
/// The where the data is saved.
/// A dictionary of all already persisted objects. (Needed to avoid cycles.)
/// The saved .
public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) {
XmlNode node = base.GetXmlNode(name, document, persistedObjects);
foreach (KeyValuePair item in dict) {
XmlNode keyNode = PersistenceManager.Persist("Key", item.Key, document, persistedObjects);
XmlNode valueNode = PersistenceManager.Persist("Val", item.Value, document, persistedObjects);
XmlNode pairNode = document.CreateNode(XmlNodeType.Element, "KeyValuePair", null);
pairNode.AppendChild(keyNode);
pairNode.AppendChild(valueNode);
node.AppendChild(pairNode);
}
return node;
}
///
/// Loads the persisted matrix from the specified .
///
/// All key-value pairs must be saved as child nodes of the node.
/// Every child node has to contain two child nodes itself, one for the key, having the tag name "Key",
/// and one for the value, having the tag name "Val" (see ).
/// The where the instance is saved.
/// The dictionary of all already restored objects. (Needed to avoid cycles.)
public override void Populate(XmlNode node, IDictionary restoredObjects) {
base.Populate(node, restoredObjects);
for (int i = 0; i < node.ChildNodes.Count; i++) {
K key = (K) PersistenceManager.Restore(node.ChildNodes[i].SelectSingleNode("Key"), restoredObjects);
V val = (V) PersistenceManager.Restore(node.ChildNodes[i].SelectSingleNode("Val"), restoredObjects);
dict[key] = val;
}
}
///
/// The string representation of the dictionary
///
/// The elements of the dictionary as string, each key-value pair in the format
/// Key:Value, separated by a semicolon.
/// If the dictionary contains no entries, "Empty Dictionary" is returned.
public override string ToString() {
if (dict.Count > 0) {
StringBuilder builder = new StringBuilder();
foreach (KeyValuePair item in dict) {
builder.Append(item.Key.ToString());
builder.Append(":");
builder.Append(item.Value.ToString());
builder.Append("; ");
}
return builder.ToString();
} else {
return "Empty Dictionary";
}
}
#endregion
#region IDictionary Members
/////
///// Adds a new key value pair to the dictionary.
/////
///
/// Calls .
///// The key to add.
///// The value to add.
public void Add(K key, V value) {
dict.Add(key, value);
OnItemAdded(key, value);
}
///
public bool ContainsKey(K key) {
return dict.ContainsKey(key);
}
///
public ICollection Keys {
get { return dict.Keys; }
}
///
/// Removes a key-value pair having the specified .
///
/// Calls .
/// The key of the key-value pair, which should be removed.
/// true if the key was found and successfully removed,
/// false if the key was not found.
public bool Remove(K key) {
V value = dict[key];
bool removed = dict.Remove(key);
OnItemRemoved(key, value);
return removed;
}
///
public bool TryGetValue(K key, out V value) {
return dict.TryGetValue(key, out value);
}
///
public ICollection Values {
get { return dict.Values; }
}
///
/// Gets or sets the value of a specified .
///
/// The key of the value which should be received or changed.
/// The value of the .
public V this[K key] {
get { return dict[key]; }
set { dict[key] = value; }
}
#endregion
#region ICollection> Members
///
/// Adds a key-value pair to the current instance.
///
/// Calls .
/// The key-value pair to add.
public void Add(KeyValuePair item) {
dict.Add(item.Key, item.Value);
OnItemAdded(item.Key, item.Value);
}
/////
///// Empties the dictionary.
/////
///
/// Calls .
public void Clear() {
dict.Clear();
OnCleared();
}
///
/// Checks whether the specified key-value pair exists in the current instance of the dictionary.
///
/// The key-value pair to check.
/// true if both, the key and the value exist in the dictionary,
/// false otherwise.
public bool Contains(KeyValuePair item) {
return (dict.ContainsKey(item.Key) && dict[item.Key].Equals(item.Value));
}
///
/// TODO
///
///
///
public void CopyTo(KeyValuePair[] array, int arrayIndex) {
throw new NotImplementedException();
}
///
public int Count {
get { return dict.Count; }
}
///
/// Checks whether the dictionary is read-only.
///
/// Always returns false.
public bool IsReadOnly {
get { return false; }
}
///
/// Removes the specified key-value pair.
///
/// Calls when the removal was successful.
/// The key-value pair to remove.
/// true if the removal was successful, false otherwise.
public bool Remove(KeyValuePair item) {
bool removed = dict.Remove(item.Key);
if (removed) {
OnItemRemoved(item.Key, item.Value);
}
return removed;
}
#endregion
#region IEnumerable> Members
///
public IEnumerator> GetEnumerator() {
return dict.GetEnumerator();
}
#endregion
#region IEnumerable Members
///
IEnumerator IEnumerable.GetEnumerator() {
return dict.GetEnumerator();
}
#endregion
#region Event Handler
///
/// Occurs when a new item is added to the dictionary.
///
public event EventHandler> ItemAdded;
///
/// Fires a new ItemAdded event.
///
/// Calls .
/// The key that was added.
/// The value that was added.
protected virtual void OnItemAdded(K key, V value) {
if (ItemAdded != null)
ItemAdded(this, new EventArgs(key, value));
OnChanged();
}
///
/// Occurs when an item is removed from the dictionary.
///
public event EventHandler> ItemRemoved;
///
/// Fires a new ItemRemoved event.
///
/// Calls .
/// The key that was removed.
/// The value that was removed
protected virtual void OnItemRemoved(K key, V value) {
if (ItemRemoved != null)
ItemRemoved(this, new EventArgs(key, value));
OnChanged();
}
///
/// Occurs when the dictionary is emptied.
///
public event EventHandler Cleared;
///
/// Fires a new Cleared event.
///
/// Calls .
protected virtual void OnCleared() {
if (Cleared != null)
Cleared(this, new EventArgs());
OnChanged();
}
#endregion
#region IEqualityComparer
///
/// Compares two keys with each other.
///
/// The type of the keys.
internal sealed class IItemKeyComparer : IEqualityComparer
where T : IItem {
///
/// Checks whether two keys are equal to each other.
///
/// Key number one.
/// Key number two.
/// true if the two keys are the same, false otherwise.
public bool Equals(T x, T y) {
if (x is IComparable) {
return (((IComparable) x).CompareTo(y) == 0);
}
if (y is IComparable) {
return (((IComparable) y).CompareTo(x) == 0);
}
return x.Equals(y);
}
///
/// Serves as a hash function for a particular type.
///
/// The object where the hash code is searched for.
/// A hash code for the given .
public int GetHashCode(T obj) {
if (obj is IObjectData) {
return ((IObjectData) obj).Data.GetHashCode();
}
return obj.Guid.GetHashCode();
}
}
#endregion
}
}