using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Vanara.Collections;
using Vanara.Extensions;
using static Vanara.PInvoke.Shell32;

namespace Vanara.Windows.Shell
{
	/// <summary>The navigation log is a history of the locations visited by a shell view object.</summary>
	public class ShellNavigationHistory : IHistory<ShellItem>
	{
		private readonly History<PIDL> pidls = new History<PIDL>();

		internal ShellNavigationHistory()
		{
			pidls.CollectionChanged += (s, e) => CollectionChanged?.Invoke(this, e);
			pidls.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, e);
		}

		/// <summary>Occurs when an item is added, removed, changed, moved, or the entire list is refreshed.</summary>
		public event NotifyCollectionChangedEventHandler CollectionChanged;

		/// <summary>Occurs when a property value changes.</summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>Indicates the presence of items in the history that can be reached by calling <see cref="M:Vanara.Collections.IHistory`1.SeekBackward"/>.</summary>
		/// <value><see langword="true"/> if this instance can seek backward; otherwise, <see langword="false"/>.</value>
		public bool CanSeekBackward => pidls.CanSeekBackward;

		/// <summary>Indicates the presence of items in the history that can be reached by calling <see cref="M:Vanara.Collections.IHistory`1.SeekForward"/>.</summary>
		/// <value><see langword="true"/> if this instance can seek forward; otherwise, <see langword="false"/>.</value>
		public bool CanSeekForward => pidls.CanSeekForward;

		/// <summary>Gets the items in the history.</summary>
		/// <value>The number of items.</value>
		public int Count => pidls.Count;

		/// <summary>Gets the shell object in the Locations collection pointed to by CurrentLocationIndex.</summary>
		public ShellItem Current => new ShellItem(pidls.Current);

		/// <summary>
		/// Adds the specified item as the last history entry and sets the <see cref="P:Vanara.Collections.IHistory`1.Current"/> property to
		/// it's value.
		/// </summary>
		/// <param name="item">The item to add to the history.</param>
		public void Add(ShellItem item) => pidls.Add(item.PIDL, true);

		/// <summary>Clears the history of all items.</summary>
		public void Clear() => pidls.Clear();

		/// <summary>Returns an enumerator that iterates through the collection.</summary>
		/// <returns>A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.</returns>
		public IEnumerator<ShellItem> GetEnumerator() => pidls.Select(p => new ShellItem(p)).GetEnumerator();

		/// <summary>Gets a specified number of items starting at a location within the history.</summary>
		/// <param name="count">The maximum number of items to retrieve. The actual number of items returned may be less if not avaialable.</param>
		/// <param name="origin">The reference point within the history at which to start fetching items.</param>
		/// <returns>A read-only list of items.</returns>
		public IReadOnlyList<ShellItem> GetItems(int count, SeekOrigin origin) => (IReadOnlyList<ShellItem>)new List<ShellItem>(pidls.GetItems(count, origin).Select(ShIFromPIDL));

		/// <summary>
		/// Seeks through the history a given number of items starting at a known location within the history. This updates the <see
		/// cref="P:Vanara.Collections.IHistory`1.Current"/> property.
		/// </summary>
		/// <param name="count">The number of items to move. This value can be negative to search backwards or positive to search forwards.</param>
		/// <param name="origin">The reference point within the history at which to start seeking.</param>
		/// <returns>The value at the new current pointer position.</returns>
		public ShellItem Seek(int count, SeekOrigin origin) => ShIFromPIDL(pidls.Seek(count, origin));

		/// <summary>Seeks one position backwards.</summary>
		/// <returns>The value at the new current pointer position.</returns>
		public ShellItem SeekBackward() => ShIFromPIDL(pidls.SeekBackward());

		/// <summary>Seeks one position forwards.</summary>
		/// <returns>The value at the new current pointer position.</returns>
		public ShellItem SeekForward() => ShIFromPIDL(pidls.SeekForward());

		/// <summary>
		/// Adds the specified item as the last history entry and sets the <see cref="P:Vanara.Collections.IHistory`1.Current"/> property to
		/// it's value.
		/// </summary>
		/// <param name="item">The item to add to the history.</param>
		/// <param name="removeForwardItems">
		/// <see langword="true"/> indicates to remove all items forward of the current pointer; <see langword="false"/> leaves the history intact.
		/// </param>
		void IHistory<ShellItem>.Add(ShellItem item, bool removeForwardItems) => pidls.Add(item?.PIDL, removeForwardItems);

		IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

		internal void Add(PIDL pidl) => pidls.Add(pidl, true);

		private static ShellItem ShIFromPIDL(PIDL pidl) => pidl is null ? null : new ShellItem(pidl);
	}
}