using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Decal.Interop.Filters;

namespace Decal.Adapter.Wrappers;

public class Vendor : GenericDisposableWrapper<Decal.Interop.Filters.Vendor>, IEnumerable<WorldObject>, IEnumerable
{
	public class VendorEnumerator : IEnumerator<WorldObject>, IDisposable, IEnumerator
	{
		private Vendor vendor;

		private WorldObject current;

		public WorldObject Current
		{
			get
			{
				if (current == null)
				{
					MoveNext();
				}
				return current;
			}
		}

		object IEnumerator.Current
		{
			get
			{
				if (current == null)
				{
					MoveNext();
				}
				return current;
			}
		}

		internal VendorEnumerator(Vendor vendor)
		{
			this.vendor = vendor;
		}

		~VendorEnumerator()
		{
			Dispose(userCalled: false);
		}

		public void Dispose()
		{
			Dispose(userCalled: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool userCalled)
		{
			if (vendor != null)
			{
				Reset();
				vendor = null;
			}
		}

		public bool MoveNext()
		{
			Decal.Interop.Filters.WorldObject ppObject = null;
			bool num = vendor.Wrapped.Next(ref ppObject);
			if (num && ppObject != null)
			{
				current = vendor.GetCachedObject(ppObject);
			}
			return num;
		}

		public void Reset()
		{
			vendor.Wrapped.Reset();
		}
	}

	private WorldFilter wf;

	private DisposableObjectDictionary<int, WorldObject> objectCache;

	private IEnumerator<WorldObject> oldstyleenumerator;

	/// <summary>
	/// The indentifier for this merchant
	/// </summary>
	public int MerchantId => base.Wrapped.MerchantID;

	/// <summary>
	/// The maximum value of an item this vendor will purchase
	/// </summary>
	public int MaxValue => base.Wrapped.BuyValue;

	/// <summary>
	/// The rate at which this vendor sells items
	/// </summary>
	public float SellRate => base.Wrapped.SellRate;

	/// <summary>
	/// The rate at which this vendor buys items
	/// </summary>
	public float BuyRate => base.Wrapped.BuyRate;

	/// <summary>
	/// The item categories that this vendor buys
	/// </summary>
	public int Categories => base.Wrapped.BuyCategories;

	/// <summary>
	/// Returns the number of items in the collection
	/// </summary>
	public int Count => base.Wrapped.Count;

	/// <summary>
	/// Returns the number of items represented by the collection, taking into account stacks of items.
	/// </summary>
	public int Quantity => base.Wrapped.Quantity;

	public WorldObject First
	{
		get
		{
			using IEnumerator<WorldObject> enumerator = GetEnumerator();
			return enumerator.Current;
		}
	}

	[Obsolete("Use enumerators")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public WorldObject Current
	{
		get
		{
			if (oldstyleenumerator == null)
			{
				oldstyleenumerator = GetEnumerator();
			}
			return oldstyleenumerator.Current;
		}
	}

	public WorldObject this[int id]
	{
		get
		{
			WorldObject value = null;
			if (!objectCache.TryGetValue(id, out value))
			{
				Decal.Interop.Filters.WorldObject byID = base.Wrapped.GetByID(id);
				if (byID != null)
				{
					value = new WorldObject(byID);
					objectCache.Add(value.Id, value);
				}
			}
			return value;
		}
	}

	public Vendor(WorldFilter wf, Decal.Interop.Filters.Vendor obj)
		: base(obj)
	{
		this.wf = wf;
		objectCache = new DisposableObjectDictionary<int, WorldObject>("Id");
	}

	protected override void Dispose(bool userCalled)
	{
		if (oldstyleenumerator != null)
		{
			oldstyleenumerator.Dispose();
			oldstyleenumerator = null;
		}
		objectCache.Clear();
		base.Dispose(userCalled);
	}

	internal WorldObject GetCachedObject(Decal.Interop.Filters.WorldObject iwo)
	{
		WorldObject value = null;
		if (!objectCache.TryGetValue(iwo.GUID, out value))
		{
			value = new WorldObject(iwo);
			objectCache.Add(value.Id, value);
		}
		return value;
	}

	/// <summary>
	/// Apply a filter to this collection to limit what it returns
	/// </summary>
	/// <param name="filter">filter object</param>
	public void SetFilter(WorldObjectCollectionFilter filter)
	{
		filter?.ApplyFilter(base.Wrapped);
	}

	[Obsolete("Use enumerators")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public bool MoveNext()
	{
		if (oldstyleenumerator == null)
		{
			oldstyleenumerator = GetEnumerator();
		}
		return oldstyleenumerator.MoveNext();
	}

	[Obsolete("Use enumerators")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void Reset()
	{
		if (oldstyleenumerator == null)
		{
			oldstyleenumerator = GetEnumerator();
		}
		oldstyleenumerator.Reset();
	}

	public IEnumerator<WorldObject> GetEnumerator()
	{
		return new VendorEnumerator(this);
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new VendorEnumerator(this);
	}
}
