using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Windows.Forms;

namespace Sentience
{
    /// <summary>
    /// The Platform Utils static class provides some basic file operation features.
    /// </summary>
    public static class Utils
    {
        /// <summary>
        /// Browse for a folder.
        /// </summary>
        /// <param name="path">The startup path.</param>
        /// <param name="description">The description to use.</param>
        /// <returns>The selected path.</returns>
        public static String BrowseFolder(String path, String description)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.SelectedPath = path;
            folderDialog.Description = description;

            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                return folderDialog.SelectedPath + "\\";
            }
            else
            {
                return path;
            }
        }

        /// <summary>
        /// Browse for a folder.
        /// </summary>
        /// <param name="path">The startup path.</param>
        /// <returns>The selected path.</returns>
        public static String BrowseFolder(String path)
        {
            return BrowseFolder(path, "");
        }

        /// <summary>
        /// Shows the open file dialog.
        /// </summary>
        /// <param name="owner">The parent form.</param>
        /// <param name="filter">The file filter to apply.</param>
        /// <returns>The path of the selected file.</returns>
        public static String OpenFile(IWin32Window owner, String filter)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Filter = filter;

            if (openDialog.ShowDialog(owner) == DialogResult.OK)
            {
                return openDialog.FileName;
            }
            else
            {
                return null;
            }
        }

        public static float Distance(PointF start, PointF target)
        {
            return (float)Math.Sqrt((start.X - target.X) * (start.X - target.X) + (start.Y - target.Y) * (start.Y - target.Y));
        }

        /// <summary>
        /// Shows the save file dialog.
        /// </summary>
        /// <param name="filter">The file filter to apply.</param>
        /// <returns>The path of the selected file.</returns>
        public static String SaveFile(String filter)
        {
            return SaveFile(null, filter);
        }

        /// <summary>
        /// Shows the save file dialog.
        /// </summary>
        /// <param name="owner">The parent form.</param>
        /// <param name="filter">The file filter to apply.</param>
        /// <returns>The path of the selected file.</returns>
        public static String SaveFile(IWin32Window owner, String filter)
        {
            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.Filter = filter;

            if (saveDialog.ShowDialog(owner) == DialogResult.OK)
            {
                return saveDialog.FileName;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Shows the open file dialog.
        /// </summary>
        /// <param name="filter">The file filter to apply.</param>
        /// <returns>The path of the selected file.</returns>
        public static String OpenFile(String filter)
        {
            return OpenFile(null, filter);
        }

        /// <summary>
        /// Gets the absolute path from a provided path.
        /// </summary>
        /// <param name="path">The specified path.</param>
        /// <returns>The specified path as an absolute path.</returns>
        public static String GetAbsolutePath(String path)
        {
            String absolutePath = Path.GetFullPath(path);

            if (absolutePath[absolutePath.Length - 1] != Path.DirectorySeparatorChar)
            {
                absolutePath += Path.DirectorySeparatorChar;
            }

            return absolutePath;
        }

        /// <summary>
        /// Gets the relative path from a provided path.
        /// </summary>
        /// <param name="absoluteFilePath">The specified path.</param>
        /// <param name="startPath">The path the specified path should be relative to.</param>
        /// <returns>The specified path as an relative path.</returns>
        public static String GetRelativePath(String absoluteFilePath, String startPath)
        {
            String[] firstPathParts = startPath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
            String[] secondPathParts = absoluteFilePath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);

            int sameCounter = 0;
            for (int i = 0; i < Math.Min(firstPathParts.Length, secondPathParts.Length); i++)
            {
                if (!firstPathParts[i].ToLower().Equals(secondPathParts[i].ToLower()))
                {
                    break;
                }
                sameCounter++;
            }

            if (sameCounter == 0)
            {
                return absoluteFilePath;
            }

            String newPath = String.Empty;
            for (int i = sameCounter; i < firstPathParts.Length; i++)
            {
                if (i > sameCounter)
                {
                    newPath += Path.DirectorySeparatorChar;
                }
                newPath += "..";
            }
            if (newPath.Length == 0)
            {
                newPath = ".";
            }
            for (int i = sameCounter; i < secondPathParts.Length; i++)
            {
                newPath += Path.DirectorySeparatorChar;
                newPath += secondPathParts[i];
            }

            if (newPath[newPath.Length - 1] != Path.DirectorySeparatorChar)
            {
                newPath += Path.DirectorySeparatorChar;
            }

            return newPath;
        }

        /// <summary>
        /// Checks if a specified file is locked by the operating system.
        /// </summary>
        /// <param name="fileName">The file to check.</param>
        /// <returns>True if the file is locked, false if not.</returns>
        public static bool IsFileLocked(String fileName)
        {
            bool isLocked = false;
            FileStream fs;
            try
            {
                fs = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
                fs.Close();
            }
            catch (IOException)
            {
                isLocked = true;
            }
            return isLocked;
        }

        /// <summary>
        /// Deletes all the files in a specified folder. It should go without saying that
        /// this method should be USED WITH CAUTION.
        /// </summary>
        /// <param name="path">The path to the folder.</param>
        public static void CleanupDir(String path)
        {
            if (Directory.Exists(path))
            {
                String[] dirFiles = Directory.GetFiles(path);

                for (int i = 0; i < dirFiles.Length; i++)
                {
                    while (IsFileLocked(dirFiles[i])) { }
                    File.Delete(dirFiles[i]);
                }
            }
        }

        /// <summary>
        /// Formats a supplied integer to two digits, e.g. 3 = 03.
        /// </summary>
        /// <param name="i">The integer to format.</param>
        /// <returns>The integer as a two digit string</returns>
        public static String FullDigit(int i)
        {
            String time = i.ToString();

            if (i < 10)
            {
                time = "0" + i;
            }
            return time;
        }

        /// <summary>
        /// Creates a timestamp.
        /// </summary>
        /// <param name="s">The object to place after the timestamp.</param>
        /// <returns>The supplied object as a string with a prefixed timestamp.</returns>
        public static String GetTimeStamp(Object s)
        {
            return String.Format("[{0}:{1}:{2}] {3}", FullDigit(DateTime.Now.Hour), FullDigit(DateTime.Now.Minute), FullDigit(DateTime.Now.Second), s.ToString());
        }

        /// <summary>
        /// Suffixes an 's' to the end of a string if
        /// </summary>
        /// <param name="t">The object's name.</param>
        /// <param name="i">How many objects there are.</param>
        /// <returns>The properly formatted string.</returns>
        public static String FullLabel(String t, int i)
        {
            if (i == 1)
            {
                return i + " " + t;
            }
            else
            {
                return i + " " + t + "s";
            }
        }

        /// <summary>
        /// Creates a timespan from a ulong epoch.
        /// </summary>
        /// <param name="seconds">The second count.</param>
        /// <returns>The timespan created from the ulong.</returns>
        public static TimeSpan GetTimeStampFromULong(ulong seconds)
        {
            int hours = (int)(seconds / 3600);
            int minutes = (int)(seconds / 60) - (hours * 60);
            int secs = (int)(seconds % 60);

            return new TimeSpan(hours, minutes, secs);
        }

        /// <summary>
        /// Shows the color picker dialog.
        /// </summary>
        /// <param name="owner">The parent form.</param>
        /// <returns>The selected color.</returns>
        public static Color GetColor(IWin32Window owner)
        {
            ColorDialog colorDialog = new ColorDialog();

            if (colorDialog.ShowDialog(owner) == DialogResult.OK)
            {
                return colorDialog.Color;
            }
            else
            {
                return Color.Empty;
            }
        }

        /// <summary>
        /// Shows the color picker dialog.
        /// </summary>
        /// <returns>The selected color.</returns>
        public static Color GetColor()
        {
            return GetColor(null);
        }

        /// <summary>
        /// Creates a nice time string from a supplied timespan.
        /// </summary>
        /// <param name="time">The timespan to use.</param>
        /// <returns>The created time string.</returns>
        public static String GetTimeStringShort(DateTime time)
        {
            return GetTimeStringShort(new TimeSpan(time.Ticks));
        }

        /// <summary>
        /// Creates a nice time string from a supplied timespan.
        /// </summary>
        /// <param name="time">The timespan to use.</param>
        /// <returns>The created time string.</returns>
        public static String GetTimeStringShort(TimeSpan time)
        {
            String tHours;
            String tMins;
            String tSecs;

            if (time.Hours.ToString().Length <= 1)
            {
                tHours = "0" + time.Hours;
            }
            else
            {
                tHours = time.Hours + "";
            }
            if (time.Minutes.ToString().Length <= 1)
            {
                tMins = "0" + time.Minutes.ToString();
            }
            else
            {
                tMins = time.Minutes.ToString();
            }
            if (time.Seconds.ToString().Length <= 1)
            {
                tSecs = "0" + time.Seconds.ToString();
            }
            else
            {
                tSecs = time.Seconds.ToString();
            }

            return tHours + ":" + tMins + ":" + tSecs;
        }

        

    }
}
