using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
namespace MadMilkman.Ini
{
///
/// Represents a base generic class for INI content item collections, and .
///
/// derived type.
///
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(DebugCollectionViewer<>))]
public abstract class IniItemCollection : IItemNameVerifier, IList where T : IniItem
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly bool caseSensitive;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly IniDuplication duplication;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly IList items;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly IniFile parentFile;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly IniItem owner;
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
protected IniFile ParentFile { get { return this.parentFile; } }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal IniItem Owner { get { return this.owner; } }
///
///
/// Gets the number of items in this collection.
///
public int Count { get { return this.items.Count; } }
internal IniItemCollection(IniFile parentFile, IniItem owner, IniDuplication duplication, bool caseSensitive)
{
this.caseSensitive = caseSensitive;
this.duplication = duplication;
this.parentFile = parentFile;
this.owner = owner;
this.items = new List();
}
///
/// Adds an item to the end of this collection.
///
/// Item to add to this collection.
///
public void Add(T item)
{
if (this.VerifyItem(item))
this.items.Add(item);
}
///
/// Removes all items from this collection.
///
public void Clear()
{
foreach (var item in this.items)
item.ParentCollectionCore = null;
this.items.Clear();
}
///
/// Determines whether an item is in this collection.
///
/// Item to locate in this collection.
/// if the specified item is in the collection.
public bool Contains(T item) { return this.items.Contains(item); }
///
/// Determines whether an item is in this collection.
///
/// Name of the item to locate in this collection.
/// if the item with specified name is in the collection.
public bool Contains(string name) { return this.GetItemIndexByName(name) != -1; }
///
/// Shallow copies the items of this collection to an array.
///
/// One-dimensional array that is the destination of the items copied from this collection.
/// Zero-based index in array at which copying begins.
public void CopyTo(T[] array, int arrayIndex) { this.items.CopyTo(array, arrayIndex); }
///
/// Searches for the specified item and returns the zero-based index of the first occurrence within this collection.
///
/// Item to locate in this collection.
/// Index of the first occurrence of specified item in the collection.
public int IndexOf(T item) { return this.items.IndexOf(item); }
///
/// Searches for the specified item and returns the zero-based index of the first occurrence within this collection.
///
/// Name of the item to locate in this collection.
/// Index of the first occurrence of the item with specified name in the collection.
public int IndexOf(string name) { return this.GetItemIndexByName(name); }
///
/// Inserts an item to this collection at the specified index.
///
/// Zero-based index at which item should be inserted.
/// Item to insert to this collection.
///
public void Insert(int index, T item)
{
if (this.VerifyItem(item))
this.items.Insert(index, item);
}
///
/// Removes the first occurrence of specific item from this collection.
///
/// Item to remove from this collection.
/// if the specified item is removed from the collection.
public bool Remove(T item)
{
if (!this.items.Remove(item))
return false;
item.ParentCollectionCore = null;
return true;
}
///
/// Removes the first occurrence of specific item from this collection.
///
/// Name of the item to remove from this collection.
/// if the item with specified name is removed from the collection.
public bool Remove(string name)
{
int index = this.GetItemIndexByName(name);
if (index == -1)
return false;
this.items.RemoveAt(index);
return true;
}
///
/// Removes an item at the specified index from this collection.
///
/// Zero-based index at which item should be inserted.
public void RemoveAt(int index)
{
this.items[index].ParentCollectionCore = null;
this.items.RemoveAt(index);
}
///
/// Gets or sets the item at the specified index.
///
/// Zero-based index of the item to get or set.
///
/// If item duplicates are ignored and value is a duplicate item, has an existing name in this collection, then this value is ignored.
///
public T this[int index]
{
get { return this.items[index]; }
set
{
if (this.VerifyItem(value))
{
this.items[index].ParentCollectionCore = null;
this.items[index] = value;
}
}
}
///
/// Gets the first item of the specified name.
///
/// Name of the item to get.
/// If item with the specified name doesn't exist a value is returned.
public T this[string name]
{
get
{
int index = this.GetItemIndexByName(name);
return (index != -1) ? this.items[index] : null;
}
}
///
/// Gets the first items of the specified names.
///
/// Names of the items to get.
/// If item with any specified name doesn't exist a value is returned in its place.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1043:UseIntegralOrStringArgumentForIndexers",
Justification = "I believe that this non-standard indexer can provide some useful data store access.")]
public IEnumerable this[params string[] names]
{
get
{
var returnedNames = new Dictionary();
int index;
for (int i = 0; i < names.Length; i++)
{
string name = names[i];
if (returnedNames.TryGetValue(name, out index))
{
if (index != -1)
{
index = GetItemIndexByName(name, index + 1);
returnedNames[name] = index;
}
}
else
{
index = GetItemIndexByName(name);
returnedNames.Add(name, index);
}
yield return (index != -1) ? this.items[index] : null;
}
}
}
///
/// Returns an enumerator that iterates through the collection.
///
/// object that can be used to iterate through the collection.
public IEnumerator GetEnumerator() { return this.items.GetEnumerator(); }
private int GetItemIndexByName(string name, int startIndex = 0)
{
var iniItems = (IEnumerable)this.items;
int index = 0;
foreach (var item in iniItems)
{
if (index >= startIndex &&
item.Name.Equals(name, (this.caseSensitive) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase))
return index;
else
index++;
}
return -1;
}
private bool VerifyItem(IniItem item)
{
if (item == null)
throw new ArgumentNullException("item");
if (item.ParentFile != this.parentFile)
throw new InvalidOperationException();
if (item.ParentCollectionCore != null)
throw new InvalidOperationException();
if (!this.VerifyItemName(item.Name))
return false;
item.ParentCollectionCore = this;
return true;
}
private bool VerifyItemName(string name) { return ((IItemNameVerifier)this).VerifyItemName(name); }
bool IItemNameVerifier.VerifyItemName(string name)
{
if (this.duplication != IniDuplication.Allowed && this.Contains(name))
{
if (this.duplication == IniDuplication.Disallowed)
throw new InvalidOperationException();
return false;
}
return true;
}
///
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
bool ICollection.IsReadOnly { get { return false; } }
}
}