using System;
using System.IO;
namespace Wayne.Lib.IO
{
    /// <summary>
    /// Support class managing file paths of the Wayne system.
    /// </summary>
    public class PathsImplementation : IPaths
    {
        #region DLL Import

        [System.Runtime.InteropServices.DllImport("coredll.dll", EntryPoint = "GetModuleFileName", SetLastError = true)]
        private static extern int GetModuleFileNameWinCE(IntPtr hModule, byte[] lpFilename, int nSize);

        [System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "GetModuleFileNameW", SetLastError = true)]
        private static extern int GetModuleFileNameWin32(IntPtr hModule, byte[] lpFilename, int nSize);

        #endregion

        #region Construction
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="fullWindows"></param>
        public PathsImplementation(bool fullWindows)
        {
           
            //bool fullWindows = FileSupport.DirectoryExists(@"C:\");
            if (fullWindows)
                Root = @"C:\Wayne";
            else
                Root = @"\Storage card";
            Config = Combine("Config");
            Log = Combine("Log");
            Transactions = Combine("Transactions");
            Data = Combine("Data");


            const int MAX_PATH = 260;
            byte[] buffer = new byte[MAX_PATH * 2];
            int chars;

            if (fullWindows)
                chars = GetModuleFileNameWin32(IntPtr.Zero, buffer, MAX_PATH);
            else
                chars = GetModuleFileNameWinCE(IntPtr.Zero, buffer, MAX_PATH);

            if (chars > 0)
            {
                ExecutablePath = System.Text.Encoding.Unicode.GetString(buffer, 0, chars * 2);
                ExecutableDirectory = Path.GetDirectoryName(ExecutablePath);
            }
            else
            {
                ExecutablePath = string.Empty;
                ExecutableDirectory = string.Empty;
            }
        }

        #endregion


        #region Properties

        /// <summary>
        /// The root path used by Wayne applications.
        /// </summary>
        public string Root { get; private set; }

        /// <summary>
        /// The base path to all config files.
        /// </summary>
        public string Config { get; private set; }

        /// <summary>
        /// The base path to all transaction files.
        /// </summary>
        public string Transactions { get; private set; }

        /// <summary>
        /// The base path to all log files.
        /// </summary>
        public string Log { get; private set; }

        /// <summary>
        /// The complete path (including the file name) to the executable.
        /// </summary>
        public string ExecutablePath { get; private set; }

        /// <summary>
        /// The directory path to the executable.
        /// </summary>
        public string ExecutableDirectory { get; private set; }

        /// <summary>
        /// The base path to data files.
        /// </summary>
        public string Data { get; private set; }

        #endregion

        #region Methods

        /// <summary>
        /// Combines the Root path and the given subPath.
        /// </summary>
        /// <param name="subPath">The sub path (under the main path).</param>
        /// <returns></returns>
        public string Combine(string subPath)
        {
            return Path.Combine(Root, subPath);
        }

        /// <summary>
        /// Combines the Root path and the given subPath and file name.
        /// </summary>
        /// <param name="subPath">The sub path (under the main path).</param>
        /// <param name="subPath2">An additional sub path (or the name of a file).</param>
        /// <returns></returns>
        public string Combine(string subPath, string subPath2)
        {
            return Path.Combine(Path.Combine(Root, subPath), subPath2);
        }

        /// <summary>
        /// Returns the config path to the given config name.
        /// </summary>
        /// <param name="configName">The name of the config.</param>
        /// <returns></returns>
        public string GetConfigPath(string configName)
        {
            return Path.Combine(Config, configName);
        }

        /// <summary>
        /// Returns the config path to the given config name.
        /// </summary>
        /// <param name="configName">The name of the config.</param>
        /// <param name="fileName">The name of a config file.</param>
        /// <returns></returns>
        public string GetConfigPath(string configName, string fileName)
        {
            return Path.Combine(Path.Combine(Config, configName), fileName);
        }

        /// <summary>
        /// Returns the transaction file path to the given terminal type.
        /// </summary>
        /// <param name="terminalType">The name of the terminal type.</param>
        /// <returns></returns>
        public string GetTransactionsPath(string terminalType)
        {
            return Path.Combine(Transactions, terminalType);
        }

        /// <summary>
        /// Returns the transaction file path to the given terminal type.
        /// </summary>
        /// <param name="terminalType">The name of the terminal type.</param>
        /// <param name="subState">The name of the sub state.</param>
        /// <returns></returns>
        public string GetTransactionsPath(string terminalType, string subState)
        {
            return Path.Combine(Path.Combine(Transactions, terminalType), subState);
        }

        /// <summary>
        /// Replaces the extension of a file (e.g. from C:\MyFile.aaa to C:\MyFile.bbb)
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="newExtension"></param>
        /// <returns></returns>
        public string ReplaceExtension(string fileName, string newExtension)
        {
            string dir = Path.GetDirectoryName(fileName);
            string name = Path.GetFileNameWithoutExtension(fileName);
            return Path.Combine(dir, string.Concat(name, newExtension.StartsWith(".") ? string.Empty : ".", newExtension));
        }

        #endregion

        #region Parse

        /// <summary>
        /// Parses the path to replace any %...% variables with the current actual path.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public string Parse(string path)
        {
            if (path != null)
            {
                Replace(ref path, "%Root%", Root);
                Replace(ref path, "%Config%", Config);
                Replace(ref path, "%Transactions%", Transactions);
                Replace(ref path, "%Log%", Log);
                Replace(ref path, "%ExeDir%", ExecutableDirectory);
                Replace(ref path, "%Data%", Data);
            }
            return path;
        }

        private static void Replace(ref string path, string variableName, string actualText)
        {
            int index = path.IndexOf(variableName, StringComparison.InvariantCultureIgnoreCase);
            if (index > -1)
                path = path.Remove(index, variableName.Length).Insert(index, actualText);
        }

        /// <summary>
        /// Checks if file exists
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        [Obsolete("Use the DirectoryExists() in FileSupport instead!")]
        public bool FileExists(string fileName)
        {
            return FileSupport.FileExists(Parse(fileName));
        }

        /// <summary>
        /// Checks if directory exists
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        [Obsolete("Use the DirectoryExists() in FileSupport instead!")]
        public bool DirectoryExists(string path)
        {
            return FileSupport.EnsureDirectoryExists(path);
        }

        /// <summary>
        /// Ensures the directory exists by trying to create it if it does not exist already.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        [Obsolete("Use the DirectoryExists() in FileSupport instead!")]
        public bool EnsureDirectoryExists(string path)
        {
            return FileSupport.EnsureDirectoryExists(path);
        }

        #endregion
    }
}