using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Android.Content;
using Android.OS;
using Java.IO;
using KeePassLib.Serialization;
using KeePassLib.Utility;

namespace keepass2android.Io
{
	public static class IoUtil
	{

		public static bool TryTakePersistablePermissions(ContentResolver contentResolver, Android.Net.Uri uri)
		{
			if ((int)Build.VERSION.SdkInt >= 19)
			{
				//try to take persistable permissions
				try
				{
					Kp2aLog.Log("TakePersistableUriPermission");
					var takeFlags = (ActivityFlags.GrantReadUriPermission
							| ActivityFlags.GrantWriteUriPermission);
					contentResolver.TakePersistableUriPermission(uri, takeFlags);
					return true;
				}
				catch (Exception e)
				{
					Kp2aLog.Log(e.ToString());
				}

			}
			return false;
		}
		public static bool DeleteDir(Java.IO.File dir, bool contentsOnly=false)
		{
			if (dir != null && dir.IsDirectory)
			{
				String[] children = dir.List();
				for (int i = 0; i < children.Length; i++)
				{
					bool success = DeleteDir(new Java.IO.File(dir, children[i]));
					if (!success)
					{
						return false;
					}
				}
			}
			
			if (contentsOnly)
				return true;

			// The directory is now empty so delete it
			return dir.Delete();
		}


		public static IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
		{
			var iocParent = ioc.CloneDeep();
			if (iocParent.Path.EndsWith("/"))
				iocParent.Path = iocParent.Path.Substring(0, iocParent.Path.Length - 1);

			int slashPos = iocParent.Path.LastIndexOf("/", StringComparison.Ordinal);
			if (slashPos == -1)
				iocParent.Path = "";
			else
			{
				iocParent.Path = iocParent.Path.Substring(0, slashPos);
			}
			return iocParent;
		}

		public static bool IsInInternalDirectory(string path, Context context)
		{
			try
			{
				Java.IO.File filesDir = context.FilesDir.CanonicalFile;
                Java.IO.File noBackupDir = GetInternalDirectory(context).CanonicalFile;
                Java.IO.File ourFile = new Java.IO.File(path).CanonicalFile;
                //http://www.java2s.com/Tutorial/Java/0180__File/Checkswhetherthechilddirectoryisasubdirectoryofthebasedirectory.htm

                Java.IO.File parentFile = ourFile;
				while (parentFile != null)
				{
					if ((filesDir.Equals(parentFile) || noBackupDir.Equals(parentFile)))
					{
						return true;
					}
					parentFile = parentFile.ParentFile;
				}
				return false;
			}
			catch (Exception e)
			{
				Kp2aLog.LogUnexpectedError(e);
				return false;
			}
			
		}

		public static void Copy(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc, IKp2aApp app)
		{
			IFileStorage sourceStorage = app.GetFileStorage(sourceIoc, false); //don't cache source. file won't be used ever again
			IFileStorage targetStorage = app.GetFileStorage(targetIoc);

			using (
				var writeTransaction = targetStorage.OpenWriteTransaction(targetIoc,
																		  app.GetBooleanPreference(
																			  PreferenceKey.UseFileTransactions)))
			{
				using (var writeStream = writeTransaction.OpenFile())
				{
					sourceStorage.OpenFileForRead(sourceIoc).CopyTo(writeStream);
				}
				writeTransaction.CommitWrite();
			}
		}

		public static Java.IO.File GetInternalDirectory(Context ctx)
		{
			if ((int)Android.OS.Build.VERSION.SdkInt >= 21)
				return ctx.NoBackupFilesDir;
			else
				return ctx.FilesDir;
		}

        //creates a local ioc where the sourceIoc can be stored to
	    public static IOConnectionInfo GetInternalIoc(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app)
	    {
	        Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(ctx);
	        var filestorage = app.GetFileStorage(sourceIoc);

	        string targetPath = filestorage.GetFilenameWithoutPathAndExt(sourceIoc);
	        targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
	        if (targetPath == "")
	            targetPath = "internal";
	        if (new Java.IO.File(internalDirectory, targetPath).Exists())
	        {
	            int c = 1;
	            var ext = UrlUtil.GetExtension(targetPath);
	            var filenameWithoutExt = UrlUtil.StripExtension(targetPath);
	            do
	            {
	                c++;
	                targetPath = filenameWithoutExt + c;
	                if (!String.IsNullOrEmpty(ext))
	                    targetPath += "." + ext;
	            } while (new Java.IO.File(internalDirectory, targetPath).Exists());
	        }
	        return IOConnectionInfo.FromPath(new Java.IO.File(internalDirectory, targetPath).CanonicalPath);
        }

	    public static IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app)
	    {
	        var targetIoc = GetInternalIoc(sourceIoc, ctx, app);


            IoUtil.Copy(targetIoc, sourceIoc, app);
	        return targetIoc;
	    }

	    public static string GetIocPrefKey(IOConnectionInfo ioc, string suffix)
	    {
	        var iocAsHexString = IocAsHexString(ioc);

	        return "kp2a_ioc_key_" + iocAsHexString + suffix;
	    }


	    public static string IocAsHexString(IOConnectionInfo ioc)
	    {
	        SHA256Managed sha256 = new SHA256Managed();
	        string iocAsHexString =
	            MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
	        return iocAsHexString;
	    }
    }
}
