using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Web.UI.WebControls;

namespace wijmoSample1.Models.FileExplorer
{
	public class FileExplorerAction
	{
		private const string AllFilesSearchPattern = "*.*";

		public ActionResult Process(ActionParam param)
		{
			try
			{
				switch (param.CommandName)
				{
					case FileCommand.Open:
					case FileCommand.GetItems:
						return ProcessGetItems(param);
					case FileCommand.CreateDirectory:
						return ProcessNewFolder(param);
					case FileCommand.Delete:
						return ProcessDelete(param);
					case FileCommand.Move:
						return ProcessMove(param);
					case FileCommand.Paste:
						return ProcessPaste(param);
					case FileCommand.Rename:
						return ProcessRename(param);
					case FileCommand.GetHostUri:
						return ProcessGetHostUri(param);
				}
			}
			catch (Exception ex)
			{
				return CreateErrorResponse(ex);
			}

			return CreateErrorResponse("Unknow commad name.");
		}

		private ActionResult ProcessRename(ActionParam param)
		{
			var sourcePath = param.SourcePaths[0];
			var localSourcePath = Helper.MapPath(sourcePath);
			var localNewPath = Helper.MapPath(param.Path);
			Directory.Move(localSourcePath, localNewPath);
			return CreateSuccessResponse();
		}

		private ActionResult ProcessPaste(ActionParam param)
		{
			var desLocalPath = Helper.MapPath(param.Path);
			var items = new List<ItemOperationResult>();
			foreach (var path in param.SourcePaths)
			{
				var item = new ItemOperationResult(path);
				try
				{
					Copy(Helper.MapPath(path), desLocalPath);
					item.Success = true;
				}
				catch (Exception ex)
				{
					item.Error = ex.Message;
				}

				items.Add(item);
			}

			var responseData = CreateSuccessResponse();
			responseData.ItemOperationResults = items.Cast<IItemOperationResult>().ToList();
			return responseData;
		}

		private ActionResult ProcessMove(ActionParam param)
		{
			var desLocalPath = Helper.MapPath(param.Path);
			var items = new List<ItemOperationResult>();
			foreach (var path in param.SourcePaths)
			{
				var item = new ItemOperationResult(path);

				try
				{
					var localPath = Helper.MapPath(path);
					var fileName = Path.GetFileName(localPath);
					Directory.Move(localPath, Path.Combine(desLocalPath, fileName));
					item.Success = true;
				}
				catch (Exception ex)
				{
					item.Error = ex.Message;
				}
				items.Add(item);
			}

			var responseData = CreateSuccessResponse();
			responseData.ItemOperationResults = items.Cast<IItemOperationResult>().ToList();
			return responseData;
		}

		private ActionResult ProcessDelete(ActionParam param)
		{
			var itemOperations = param.SourcePaths.Select(ProcessDeleteItem).ToList();
			var responseData = CreateSuccessResponse();
			responseData.ItemOperationResults = itemOperations.Cast<IItemOperationResult>().ToList();
			return responseData;
		}

		private ItemOperationResult ProcessDeleteItem(string path)
		{
			var itemOperation = new ItemOperationResult(path);

			try
			{
				var localPath = Helper.MapPath(path);
				if (Helper.IsDirectory(localPath))
				{
					Directory.Delete(localPath, true);
				}
				else
				{
					File.Delete(localPath);
				}
				itemOperation.Success = true;
			}
			catch (Exception ex)
			{
				itemOperation.Error = ex.Message;
			}

			return itemOperation;
		}

		private ActionResult ProcessNewFolder(ActionParam param)
		{
			var dirInfo = new DirectoryInfo(Helper.MapPath(param.Path));
			dirInfo.Create();
			return CreateSuccessResponse();
		}

		private static ActionResult CreateSuccessResponse()
		{
			return new ActionResult { Success = true };
		}

		private static ActionResult CreateErrorResponse(Exception ex)
		{
			return CreateErrorResponse(ex.Message);
		}

		private static ActionResult CreateErrorResponse(string msg)
		{
			return new ActionResult
			{
				Success = false,
				Error = msg
			};
		}

		protected virtual string GetHostUri()
		{
			var request = HttpContext.Current.Request;
			var url = request.Url;
			return "http://" + url.Host + (url.Port == 80 ? string.Empty : ":" + url.Port) + request.ApplicationPath;
		}

		private ActionResult ProcessGetHostUri(ActionParam param)
		{
			var responseData = CreateSuccessResponse();
			responseData.HostUri = GetHostUri();

			return responseData;
		}

		private ActionResult ProcessGetItems(ActionParam param)
		{
			var localPath = Helper.MapPath(param.Path);
			var responseData = CreateSuccessResponse();
			var items = new List<FileExplorerItem>();

			var fileItems = new List<FileExplorerItem>();
			if (!param.OnlyFolder)
			{
				var searchPatterns = (param.SearchPatterns != null && param.SearchPatterns.Length > 0)
					? param.SearchPatterns
					: new[] { AllFilesSearchPattern };

				foreach (var searchPattern in searchPatterns)
				{
					foreach (var item in Directory.GetFiles(localPath, searchPattern, SearchOption.TopDirectoryOnly))
					{
						var fileItem = Helper.CreateFileExplorerItem(param.Path, item);
						if (CheckFilter(fileItem.Name, param))
						{
							fileItems.Add(fileItem);
						}
					}
				}

				if (param.SortExpression == SortField.Name)
				{
					fileItems.Sort(Helper.ComparisonWithName);
				}
				else
				{
					fileItems.Sort(((x, y) =>
					{
						if (x.Size == y.Size)
						{
							return 0;
						}

						if (!x.Size.HasValue)
						{
							return -1;
						}

						if (!y.Size.HasValue)
						{
							return 1;
						}

						return (int)(x.Size.Value - y.Size.Value);
					}));
				}

				if (param.SortDirection == SortDirection.Descending)
				{
					fileItems.Reverse();
				}
			}

			var folderItems = new List<FileExplorerItem>();
			foreach (var item in Directory.GetDirectories(localPath))
			{
				var foldItem = Helper.CreateFileExplorerItem(param.Path, item);
				if (CheckFilter(foldItem.Name, param))
				{
					folderItems.Add(foldItem);
				}
			}

			if (param.SortExpression == SortField.Name)
			{
				folderItems.Sort(Helper.ComparisonWithName);

				if (param.SortDirection == SortDirection.Descending)
				{
					folderItems.Reverse();
				}
			}

			if (param.SortDirection == SortDirection.Descending)
			{
				items.AddRange(fileItems);
				items.AddRange(folderItems);
			}
			else
			{
				items.AddRange(folderItems);
				items.AddRange(fileItems);
			}

			if (param.PageSize > 0)
			{
				responseData.PageCount = Math.Max(1, (int)Math.Ceiling((float)items.Count / param.PageSize));
				responseData.PageIndex = Math.Max(0, Math.Min(responseData.PageCount - 1, param.PageIndex));
				items = items.Skip(param.PageSize * responseData.PageIndex).Take(param.PageSize).ToList();
			}

			responseData.ItemOperationResults = items.Cast<IItemOperationResult>().ToList();
			return responseData;
		}

		private static bool CheckFilter(string name, ActionParam param)
		{
			return name.IndexOf(param.FilterExpression, StringComparison.OrdinalIgnoreCase) > -1;
		}

		private static void Copy(string sourcePath, string targetDir)
		{
			var fileName = Path.GetFileName(sourcePath);
			var newDirName = Path.Combine(targetDir, fileName);
			if (!Helper.IsDirectory(sourcePath))
			{
				File.Copy(sourcePath, newDirName);
				return;
			}

			Directory.CreateDirectory(newDirName);
			foreach (var item in Directory.GetFileSystemEntries(sourcePath))
			{
				Copy(item, newDirName);
			}
		}
	}
}