using System;
using System.IO;
using ANX.Framework.NonXNA;
using ANX.Framework.NonXNA.PlatformSystem;

// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license

namespace ANX.Framework.Storage
{
	public sealed class StorageDevice
	{
		#region Private
		private INativeStorageDevice nativeImplementation;

		private static Func<PlayerIndex, int, int, StorageDevice> openDeviceDelegate = null;
		private Func<string, StorageContainer> openContainerDelegate = null;
		#endregion

		#region Public
#pragma warning disable 0067 //This event is never used
		public static event EventHandler<EventArgs> DeviceChanged;
#pragma warning restore 0067

		public long FreeSpace
		{
			get
			{
				return nativeImplementation.FreeSpace;
			}
		}

		public bool IsConnected
		{
			get
			{
				return nativeImplementation.IsConnected;
			}
		}

		public long TotalSpace
		{
			get
			{
				return nativeImplementation.TotalSpace;
			}
		}

		internal string StoragePath
		{
			get;
			private set;
		}

		internal PlayerIndex PlayerIndex
		{
			get;
			private set;
		}
		#endregion

		#region Constructor
		internal StorageDevice(PlayerIndex player, int sizeInBytes, int directoryCount)
		{
			nativeImplementation =
				AddInSystemFactory.DefaultPlatformCreator.CreateStorageDevice(
				this, player, sizeInBytes, directoryCount);
		}
		#endregion

		#region BeginOpenContainer
		public IAsyncResult BeginOpenContainer(string displayName,
			AsyncCallback callback, Object state)
		{
			if (openContainerDelegate != null)
				throw new InvalidOperationException(
					"There is currently a StorageContainer request pending. " +
					"Please let this request finish.");

			openContainerDelegate = OpenStorageContainer;
			return openContainerDelegate.BeginInvoke(displayName, callback, state);
		}
		#endregion

		#region BeginShowSelector
		public static IAsyncResult BeginShowSelector(AsyncCallback callback, Object state)
		{
			return BeginShowSelector(PlayerIndex.One, 0, 0, callback, state);
		}
		#endregion

		#region BeginShowSelector
		public static IAsyncResult BeginShowSelector(int sizeInBytes, int directoryCount,
			AsyncCallback callback, Object state)
		{
			return BeginShowSelector(PlayerIndex.One, sizeInBytes, directoryCount,
				callback, state);
		}
		#endregion

		#region BeginShowSelector
		public static IAsyncResult BeginShowSelector(PlayerIndex player,
			AsyncCallback callback, Object state)
		{
			return BeginShowSelector(player, 0, 0, callback, state);
		}
		#endregion

		#region BeginShowSelector
		public static IAsyncResult BeginShowSelector(PlayerIndex player,
			int sizeInBytes, int directoryCount, AsyncCallback callback, Object state)
		{
			if (openDeviceDelegate != null)
				throw new InvalidOperationException("There is currently a StorageDevice request pending. Please let this request finish.");

			openDeviceDelegate = OpenStorageDevice;
			return openDeviceDelegate.BeginInvoke(player, sizeInBytes, directoryCount,
				callback, state);
		}
		#endregion

		#region DeleteContainer
		public void DeleteContainer(string titleName)
		{
			if (String.IsNullOrEmpty(titleName))
				throw new ArgumentNullException("titleName");

			try
			{
				nativeImplementation.DeleteContainer(titleName);
			}
			catch (IOException e)
			{
				throw new InvalidOperationException("A IOException occured while deleting the container. See inner Exception.", e);
			}
		}
		#endregion

		#region EndOpenContainer
		public StorageContainer EndOpenContainer(IAsyncResult result)
		{
			if (openContainerDelegate == null)
				throw new InvalidOperationException("There is operation pending that could be ended.");

			StorageContainer container = openContainerDelegate.EndInvoke(result);
			openContainerDelegate = null;
			return container;
		}
		#endregion

		#region EndShowSelector
		public static StorageDevice EndShowSelector(IAsyncResult result)
		{
			if (openDeviceDelegate == null)
				throw new InvalidOperationException("There is operation pending that could be ended.");

			StorageDevice device = openDeviceDelegate.EndInvoke(result);
			openDeviceDelegate = null;
			return device;
		}
		#endregion

		#region OpenStorageDevice
		private static StorageDevice OpenStorageDevice(PlayerIndex player,
			int sizeInBytes, int directoryCount)
		{
			return new StorageDevice(player, sizeInBytes, directoryCount);
		}
		#endregion

		#region OpenStorageContainer
		private StorageContainer OpenStorageContainer(string displayName)
		{
			return new StorageContainer(this, PlayerIndex, displayName);
		}
		#endregion
	}
}