using System; using System.Collections; using System.Collections.Generic; using System.Linq; using ClassicAssist.Shared; namespace ClassicAssist.UO.Objects { public sealed class ItemCollection : EntityCollection, IEnumerable { public delegate void dContainerContentsChanged( bool added, IEnumerable items ); private const int DefaultCapacity = 125; public readonly int Serial; public ItemCollection( int serial ) : base( DefaultCapacity ) { Serial = serial; } public IEnumerator GetEnumerator() { return EntityList.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public bool FindItem( int id, out Item item ) { item = SelectEntity( i => i.ID == id ); if ( item != null ) { return true; } item = null; return false; } public override bool Add( Item entity ) { bool added = base.Add( entity ); if ( added ) { OnCollectionChanged( true, true, new[] { entity } ); } return added; } public override bool Add( Item[] entities ) { bool added = base.Add( entities ); if ( added ) { OnCollectionChanged( true, true, entities ); } return added; } public bool FindItems( int id, out Item[] items ) { items = SelectEntities( i => i.ID == id ); if ( items != null ) { return true; } items = null; return false; } /// /// Flatten items + subitems into a single array. /// /// Item array to flatten. /// Array of flattened items. public static Item[] GetAllItems( Item[] items ) { List output = new List(); for ( int i = 0; i < items.Length; i++ ) { output.Add( items[i] ); if ( items[i].IsContainer ) { output.AddRange( GetAllItems( items[i].Container.GetItems() ) ); } } return output.ToArray(); } /// /// Get item with specified serial. /// /// Serial of item to retrieve. /// Item (out). /// Null if no match is found. public bool GetItem( int serial, out Item item ) { try { Item match = EntityList.Values.FirstOrDefault( i => i.Serial == serial ); if ( match != null ) { item = match; return true; } IEnumerable containers = EntityList.Values.Where( i => i.IsContainer ); foreach ( Item container in containers ) { if ( !container.Container.GetItem( serial, out Item containerMatch ) ) { continue; } item = containerMatch; return true; } } catch ( Exception ) { // ignored } item = null; return false; } public Item GetItem( int serial ) { GetItem( serial, out Item item ); return item; } /// /// Get all items contained within this container. /// public Item[] GetItems() { Item[] itemArray = new Item[EntityList.Values.Count]; EntityList.Values.CopyTo( itemArray, 0 ); return itemArray; } public int GetItemCount() { return EntityList.Count; } public int GetTotalItemCount() { int count = 0; foreach ( Item item in EntityList.Values ) { count++; if ( item.IsContainer ) { count += item.Container.GetTotalItemCount(); } } return count; } public static implicit operator int( ItemCollection i ) { return i.Serial; } public override bool Remove( Item entity ) { bool changed; if ( entity.Container == null ) { changed = base.Remove( entity ); } else { Remove( entity.Container.GetItems() ); changed = base.Remove( entity ); } if ( changed ) { OnCollectionChanged( true, false, new[] { entity } ); } return changed; } public override bool Remove( Item[] entities ) { bool changed = false; if ( entities == null ) { return false; } foreach ( Item entity in entities ) { if ( entity == null ) { continue; } if ( entity.Container != null ) { Remove( entity.Container.GetItems() ); } if ( base.Remove( entity ) ) { changed = true; } } if ( changed ) { OnCollectionChanged( true, false, entities ); } return changed; } public override bool Remove( int serial ) { bool changed = false; Item item = GetItem( serial ); if ( EntityList.ContainsKey( serial ) ) { changed = base.Remove( serial ); } else { IEnumerable containers = EntityList.Values.Where( i => i.IsContainer ); foreach ( Item container in containers ) { if ( container.Container?.GetItem( serial ) == null ) { continue; } container.Container.Remove( serial ); } } if ( changed && item != null ) { OnCollectionChanged( true, false, new[] { item } ); } return changed; } internal void RemoveByOwner( int serial ) { Item[] items = SelectEntities( i => i.Owner == serial ); if ( items == null ) { return; } Remove( items ); } public override Item[] SelectEntities( Func func ) { List itemList = new List(); IEnumerable ents = EntityList.Select( m => m.Value ).Where( m => func( m ) || m.IsContainer ); foreach ( Item i in ents ) { if ( func( i ) && !itemList.Contains( i ) ) { itemList.Add( i ); } if ( !i.IsContainer ) { continue; } Item[] result = i.Container.SelectEntities( func ); if ( result != null ) { itemList.AddRange( result ); } } return itemList.Count > 0 ? itemList.ToArray() : null; } public override Item SelectEntity( Func func ) { Item item = base.SelectEntity( func ); if ( item != null ) { return item; } IEnumerable containers = EntityList.Select( i => i.Value ).Where( i => i.Container != null ); foreach ( Item container in containers ) { item = container.Container.SelectEntity( func ); if ( item != null ) { return item; } } return null; } public void OnCollectionChanged( bool rippleDown, bool added, Item[] items ) { OnCollectionChanged( added, items ); // Ripple down if ( !rippleDown ) { return; } if ( Serial == 0 || !Engine.Items.GetItem( Serial, out Item item ) || item.Owner == 0 ) { return; } if ( Engine.Items.GetItem( item.Owner, out Item parent ) ) { parent.Container?.OnCollectionChanged( false, added, items ); } } public override string ToString() { return $"ItemCollection: Items: {EntityList.Count}, Total Items: {GetTotalItemCount()}"; } } }