using System;
using System.IO;
using System.Text.RegularExpressions;

namespace MicronSync
{
    /// <summary>
    /// Provides common IO functionality via Windows Forms.
    /// </summary>
    public class CommonIO : IDisposable
    {
        public enum FileType { sz, ini }

        #region Filesystem

        public string SaveFile(string originalPath, FileType f)
        {
            var file = new System.Windows.Forms.SaveFileDialog();

            switch (f)
            {
                case FileType.sz:
                    file.Filter = "7-Zip File|*.7z";
                    file.DefaultExt = ".7z";
                    break;
                case FileType.ini:
                    file.Filter = "Config Files (*.mini;*.ini)|*.mini;*.ini";
                    file.DefaultExt = "*.mini";
                    break;
                default:
                    break;
            }

            file.AddExtension = true;
            System.Windows.Forms.DialogResult result = file.ShowDialog();

            // Only change the value if a valid path is entered.
            string newPath;
            if (file.FileName != "") { newPath = file.FileName.ToString(); }
            else { newPath = originalPath; }

            return newPath;
        }

        public string OpenFile(string originalPath, FileType f)
        {
            var file = new System.Windows.Forms.OpenFileDialog();

            switch (f)
            {
                case FileType.sz:
                    file.Filter = "7-Zip File|*.7z";
                    file.DefaultExt = ".7z";
                    break;
                case FileType.ini:
                    file.Filter = "Config Files (*.mini;*.ini)|*.mini;*.ini";
                    break;
                default:
                    break;
            }

            file.AddExtension = true;
            System.Windows.Forms.DialogResult result = file.ShowDialog();

            // Only change the value if a valid path is entered.
            string newPath;
            if (file.FileName != "") { newPath = file.FileName.ToString(); }
            else { newPath = originalPath; }

            return newPath;
        }

        /// <summary>
        /// Browse to existing folder on the system.
        /// </summary>
        /// <param name="originalPath"></param>
        /// <returns></returns>
        public string BrowseFolder(string originalPath)
        {
            // The result of the Windows Forms dialog is passed as a
            // string to the method caller.
            var folder = new System.Windows.Forms.FolderBrowserDialog();
            System.Windows.Forms.DialogResult result = folder.ShowDialog();

            // Only change the value if a valid path is entered.
            string newPath;
            if (folder.SelectedPath != "") { newPath = folder.SelectedPath.ToString(); }
            else { newPath = originalPath; }

            return newPath;
        }

        public double CalculateFileSizeMB (string file)
        {
            FileInfo fi = new FileInfo(file);
            return ConvertBytesToMB(fi.Length);
        }

        #endregion

        #region String manipulation

        public string CalculateDirectoryModifyDate (string dir)
        {
            string result = null;
            if (Directory.Exists(dir))
                result = string.Format("{0} - {1}",
                    Directory.GetLastWriteTime(dir).ToShortDateString(),
                    Directory.GetLastWriteTime(dir).ToLongTimeString());
            else
                result = "N/A";

            return result;
        }

        public string CalculateFileModifyDate(string file)
        {
            string result = null;
            if (File.Exists(file))
                result = string.Format("{0} - {1}",
                    File.GetLastWriteTime(file).ToShortDateString(),
                    File.GetLastWriteTime(file).ToLongTimeString());
            else
                result = "N/A";

            return result;
        }

        public string GetRootPath(string input)
        {
            string result = null;
            Match unc = Regex.Match(input, @"(\\\\(\w+)\\)");
            Match drive = Regex.Match(input, @"(\w:\\)");

            string varPath = ConvertPathToVariable(input);
            if (!string.IsNullOrEmpty(varPath))
                result = varPath;
            else
            {
                if (input.StartsWith(@"\\"))
                    result = unc.Value;
                else
                    result = drive.Value;
            }

            return result;
        }

        public string ConvertPathToVariable(string fullPath)
        {
            string result = null;

            if (!string.IsNullOrEmpty(fullPath))
                foreach (var item in UserConfig.SysVars)
                    if (fullPath.StartsWith(item.Value))
                    {
                        result = item.Key;
                        break;
                    }

            return result;
        }

        public string ConvertVariableToPath(string variable)
        {
            string result = variable;

            if (!string.IsNullOrEmpty(variable))
                foreach (var item in UserConfig.SysVars)
                    if (variable.StartsWith(item.Key))
                    {
                        result = item.Value;
                        break;
                    }

            return result;
        }

        #endregion.

        #region Filesystem Modification

        public enum endResult
        {
            ClearEntireDirectory_Error,
            CopyEntireDirectory_Error,
            Default,
            RenameEntireDirectory_Error,
            WriteToDirectory_Error,
        }

        public endResult ClearEntireDirectory(string dir)
        {
            endResult _endResult = endResult.Default;

            try
            {
                string[] files = Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories);
                string[] dirs = Directory.GetDirectories(dir, "*", SearchOption.AllDirectories);

                foreach (var file in files)
                {
                    File.SetAttributes(file, FileAttributes.Normal);
                    File.Delete(file);
                }

                foreach (var directory in dirs)
                {
                    if (Directory.Exists(directory))
                        Directory.Delete(directory, true);
                }
            }
            catch (Exception)
            {
                _endResult = endResult.ClearEntireDirectory_Error;
            }

            return _endResult;
        }

        public endResult RenameEntireDirectory(string dir, string newName)
        {
            endResult _endResult = endResult.Default;

            try
            {
                Directory.Move(dir, Path.Combine(
                    Path.GetDirectoryName(dir), newName));
            }
            catch (Exception)
            {
                _endResult = endResult.RenameEntireDirectory_Error;
            }

            return _endResult;
        }

        public endResult CopyEntireDirectory(string src, string dst)
        {
            endResult _endResult = endResult.Default;

            try
            {
                // Generate list of all directories in source and create backup directory.
                DirectoryInfo dir = new DirectoryInfo(src);
                DirectoryInfo[] dirs = dir.GetDirectories();
                if (!Directory.Exists(dst))
                    Directory.CreateDirectory(dst);
                else
                {
                    Directory.Delete(dst, true);
                    Directory.CreateDirectory(dst);
                }

                // Copy all files to destination.
                FileInfo[] files = dir.GetFiles();
                foreach (FileInfo file in files)
                    File.Copy(Path.Combine(src, file.Name),
                        Path.Combine(dst, file.Name));

                // Repeat for subdirectories.
                foreach (DirectoryInfo subDir in dirs)
                    CopyEntireDirectory(subDir.FullName,
                        Path.Combine(dst, subDir.Name));
            }
            catch (Exception)
            {
                _endResult = endResult.CopyEntireDirectory_Error;
            }
            
            return _endResult;
        }

        public endResult WriteToDirectory(string file)
        {
            endResult _endResult = endResult.Default;

            try
            {
                using (StreamWriter w = new StreamWriter(file))
                {
                    w.WriteLine("Write access is functional");
                    w.Close();
                }
                if (File.Exists(file))
                    File.Delete(file);
            }
            catch (UnauthorizedAccessException)
            {
                _endResult = endResult.WriteToDirectory_Error;
            }

            return _endResult;
        }

        #endregion

        #region Conversion

        public double ConvertBytesToMB(double bytes)
        {
            return Math.Round(bytes / 1024f / 1024f, 2);
        }

        #endregion

        public void Dispose() { GC.Collect(); }
    }
}
