namespace Umbraco.Cms.Core.Composing; /// /// Implements an ordered collection builder. /// /// The type of the builder. /// The type of the collection. /// The type of the items. public abstract class OrderedCollectionBuilderBase : CollectionBuilderBase where TBuilder : OrderedCollectionBuilderBase where TCollection : class, IBuilderCollection { protected abstract TBuilder This { get; } /// /// Clears all types in the collection. /// /// The builder. public TBuilder Clear() { Configure(types => types.Clear()); return This; } /// /// Appends a type to the collection. /// /// The type to append. /// The builder. public TBuilder Append() where T : TItem { Configure(types => { Type type = typeof(T); if (types.Contains(type)) { types.Remove(type); } types.Add(type); }); return This; } /// /// Appends a type to the collection. /// /// The type to append. /// The builder. public TBuilder Append(Type type) { Configure(types => { EnsureType(type, "register"); if (types.Contains(type)) { types.Remove(type); } types.Add(type); }); return This; } /// /// Appends types to the collections. /// /// The types to append. /// The builder. public TBuilder Append(IEnumerable types) { Configure(list => { foreach (Type type in types) { // would be detected by CollectionBuilderBase when registering, anyways, but let's fail fast EnsureType(type, "register"); if (list.Contains(type)) { list.Remove(type); } list.Add(type); } }); return This; } /// /// Inserts a type into the collection. /// /// The type to insert. /// The optional index. /// The builder. /// Throws if the index is out of range. public TBuilder Insert(int index = 0) where T : TItem { Configure(types => { Type type = typeof(T); if (types.Contains(type)) { types.Remove(type); } types.Insert(index, type); }); return This; } /// /// Inserts a type into the collection. /// /// The type to insert. /// The builder. /// Throws if the index is out of range. public TBuilder Insert(Type type) => Insert(0, type); /// /// Inserts a type into the collection. /// /// The index. /// The type to insert. /// The builder. /// Throws if the index is out of range. public TBuilder Insert(int index, Type type) { Configure(types => { EnsureType(type, "register"); if (types.Contains(type)) { types.Remove(type); } types.Insert(index, type); }); return This; } /// /// Inserts a type before another type. /// /// The other type. /// The type to insert. /// The builder. /// Throws if both types are identical, or if the other type does not already belong to the collection. public TBuilder InsertBefore() where TBefore : TItem where T : TItem { Configure(types => { Type typeBefore = typeof(TBefore); Type type = typeof(T); if (typeBefore == type) { throw new InvalidOperationException(); } var index = types.IndexOf(typeBefore); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeBefore); // in case removing type changed index types.Insert(index, type); }); return This; } /// /// Inserts a type before another type. /// /// The other type. /// The type to insert. /// The builder. /// Throws if both types are identical, or if the other type does not already belong to the collection. public TBuilder InsertBefore(Type typeBefore, Type type) { Configure(types => { EnsureType(typeBefore, "find"); EnsureType(type, "register"); if (typeBefore == type) { throw new InvalidOperationException(); } var index = types.IndexOf(typeBefore); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeBefore); // in case removing type changed index types.Insert(index, type); }); return This; } /// /// Inserts a type after another type. /// /// The other type. /// The type to append. /// The builder. /// Throws if both types are identical, or if the other type does not already belong to the collection. public TBuilder InsertAfter() where TAfter : TItem where T : TItem { Configure(types => { Type typeAfter = typeof(TAfter); Type type = typeof(T); if (typeAfter == type) { throw new InvalidOperationException(); } var index = types.IndexOf(typeAfter); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeAfter); // in case removing type changed index index += 1; // insert here if (index == types.Count) { types.Add(type); } else { types.Insert(index, type); } }); return This; } /// /// Inserts a type after another type. /// /// The other type. /// The type to insert. /// The builder. /// Throws if both types are identical, or if the other type does not already belong to the collection. public TBuilder InsertAfter(Type typeAfter, Type type) { Configure(types => { EnsureType(typeAfter, "find"); EnsureType(type, "register"); if (typeAfter == type) { throw new InvalidOperationException(); } var index = types.IndexOf(typeAfter); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeAfter); // in case removing type changed index index += 1; // insert here if (index == types.Count) { types.Add(type); } else { types.Insert(index, type); } }); return This; } /// /// Removes a type from the collection. /// /// The type to remove. /// The builder. public TBuilder Remove() where T : TItem { Configure(types => { Type type = typeof(T); if (types.Contains(type)) { types.Remove(type); } }); return This; } /// /// Removes a type from the collection. /// /// The type to remove. /// The builder. public TBuilder Remove(Type type) { Configure(types => { EnsureType(type, "remove"); if (types.Contains(type)) { types.Remove(type); } }); return This; } /// /// Replaces a type in the collection. /// /// The type to replace. /// The type to insert. /// The builder. /// Throws if the type to replace does not already belong to the collection. public TBuilder Replace() where TReplaced : TItem where T : TItem { Configure(types => { Type typeReplaced = typeof(TReplaced); Type type = typeof(T); if (typeReplaced == type) { return; } var index = types.IndexOf(typeReplaced); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeReplaced); // in case removing type changed index types.Insert(index, type); types.Remove(typeReplaced); }); return This; } /// /// Replaces a type in the collection. /// /// The type to replace. /// The type to insert. /// The builder. /// Throws if the type to replace does not already belong to the collection. public TBuilder Replace(Type typeReplaced, Type type) { Configure(types => { EnsureType(typeReplaced, "find"); EnsureType(type, "register"); if (typeReplaced == type) { return; } var index = types.IndexOf(typeReplaced); if (index < 0) { throw new InvalidOperationException(); } if (types.Contains(type)) { types.Remove(type); } index = types.IndexOf(typeReplaced); // in case removing type changed index types.Insert(index, type); types.Remove(typeReplaced); }); return This; } }