using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Foo.Platform
{
    /// <summary>
    /// Oogy Environment Class for getting OS, Application, and Theme Settings
    /// </summary>
    public class Env
    {         
        private static int m_dwMajorVersion = 0;
        private static int m_dwMinorVersion = 0;        
        private static Themes m_Theme = Themes.Classic;
        private static AssemblyRunTimePath m_RunTimePath = null;

        /// <summary>
        /// Public Properties
        /// </summary>
        public static int MajorVersion {get{return m_dwMajorVersion;}}
        public static int MinorVersion {get{return m_dwMinorVersion;}}        
        public static Themes Theme {get{return m_Theme;}}

        /// <summary>
        /// This is our versioning system, does not correspond to Windows 
        /// </summary>
        public enum OSVersions : int 
        {  
            OS_WINDOWS_VISTA  = 1,
            OS_WINDOWS_2000	  = 2, /*incl. Server OSes*/
            OS_WINDOWS_2003   = 3, /*incl. Server OSes and Windows XP*/  
            OS_WINDOWS_SE7EN  = 7, /*for future use ?*/
            OS_NOT_SUPPORTED  = 99
        }

        /// <summary>
        /// This are our Theme Configurations for ButtonHook/GUI components.        
        /// </summary>
        public enum Themes : int 
        {
            Classic = 0,
            XPtheme = 1,
            AeroTheme = 2,
            VistaNoAero = 3
        } 

        /// <summary>
        /// Static Constructor, immediatly sets our environment variables
        /// </summary>
        static Env()
        {
            ObtainEnvInformation();
            m_RunTimePath = new AssemblyRunTimePath();
        }

        /// <summary>
        /// Call this function first - before querying for themes, etc
        /// </summary>
        private static void ObtainEnvInformation()
        {
            GetSystemInformation(out m_dwMajorVersion, out m_dwMinorVersion);
            CheckWindowsXPTheme();
            CheckWindowsVistaTheme();
        }

        /// <summary>
        /// Use to get the Oogy Application path. Creates folder if none exists
        /// </summary>
        /// <returns>Path to Ooganizer Application Folder</returns>
        public static string GetAppdirectory()
        {
            string appDataFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
            string oogyAppData = appDataFolder + @"\Ooganizer";

            if (!Directory.Exists(oogyAppData))
            {
                // create oogy app data folder
                Directory.CreateDirectory(oogyAppData);
            }

            return oogyAppData;
        }

        /// <summary>
        /// Use to get the Oogy artifact snapshot image path. Creates folder if none exists
        /// </summary>
        /// <returns>Path to Ooganizer artifact snapshot data folder</returns>
        public static string GetSnapshotDirectory()
        {
            string path = Platform.Env.GetAppdirectory() + @"\Snapshots";

            if (!Directory.Exists(path))
            {
                // create snapshot data folder
                Directory.CreateDirectory(path);
            }

            return path;
        }

        /// <summary>
        /// Use to get the Oogy log path. Creates folder if none exists
        /// </summary>
        /// <returns>Path to Ooganizer log folder</returns>
        public static string GetLogDirectory()
        {
            string path = Platform.Env.GetAppdirectory() + @"\Logs";

            if (!Directory.Exists(path))
            {
                // create snapshot data folder
                Directory.CreateDirectory(path);
            }

            return path;
        }

        /// <summary>
        /// Use this to query the current running assembly path
        /// </summary>
        /// <returns>Path of assembly location</returns>
        public static string GetRunTimePath()
        {
            return m_RunTimePath.strPath;
        }

        /// <summary>
        /// Quickly Check if the current OS Environment is supported by Oogy
        /// </summary>
        /// <returns>true if it is supported, false otherwise</returns>
        public static bool IsWindowsOSSupported()
        {
            OSVersions version = OSVersionCheck();

            if ((version == OSVersions.OS_WINDOWS_2003) ||
               (version == OSVersions.OS_WINDOWS_VISTA) ||
               (version == OSVersions.OS_WINDOWS_SE7EN))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Retrieves Windows OS specific information
        /// </summary>
        /// <param name="dwMajorVersion">dwMajorVersion[out]</param>
        /// <param name="dwMinorVersion">dwMinorVersion[out]</param>
        /// <param name="is32bitNT">is32bitNT[out] = supports 32-bit Windows NT</param>
        /// <returns>true, if succesfully retrieved, false otherwise</returns>
        private static void GetSystemInformation(out int dwMajorVersion, out int dwMinorVersion)
        {
            dwMajorVersion = System.Environment.OSVersion.Version.Major;
            dwMinorVersion = System.Environment.OSVersion.Version.Minor;            
        }

        /// <summary>
        /// Use this function to obtain the current OS version information
        /// </summary>
        /// <returns>Returns the Current OSVersion Enum of this Environment</returns>
        private static OSVersions OSVersionCheck()
        {
	        switch(m_dwMajorVersion) // we ignore minor version for now
	        {
	            case 4:		// Windows 2000?
                    return (OSVersions.OS_WINDOWS_2000);		            
	            case 5:		// Windows XP && Windows 2003
                    return (OSVersions.OS_WINDOWS_2003);
	            case 6:
		            return (OSVersions.OS_WINDOWS_VISTA);		            
	            case 7:
		            return (OSVersions.OS_WINDOWS_SE7EN);		            
	            default:
		            return (OSVersions.OS_NOT_SUPPORTED);
	        }
        }        

        /// <summary>
        /// Vista Specific Theme Checking is done here
        /// </summary>
        /// <returns></returns>
        private static void CheckWindowsVistaTheme()
        {            
	        if(OSVersionCheck() == OSVersions.OS_WINDOWS_VISTA)
	        {                
                bool bIsAero = false;
                if(Win32.Win32Functions.DwmIsCompositionEnabled(ref bIsAero) < 0)
                    return; //Call Failed

                if (bIsAero)
                    m_Theme = Themes.AeroTheme;
                else
                    m_Theme = Themes.VistaNoAero;             
	        }	        
        }

        /// <summary>
        /// XP Specific Theme Checking is done here
        /// </summary>
        /// <returns></returns>
        private static void CheckWindowsXPTheme()
        {
            if (OSVersionCheck() == OSVersions.OS_WINDOWS_2003)
            {
                if (Win32.Win32Functions.IsAppThemed())                
                    m_Theme = Themes.XPtheme;
                else                
                    m_Theme = Themes.Classic;                
           }
        }
    }

    /// <summary>
    /// Since we only can query the Assembly path by instantiation,
    /// we have a class that handles it
    /// </summary>
    internal class AssemblyRunTimePath
    {            
        public string strPath;
        public AssemblyRunTimePath(){strPath = Path.GetDirectoryName(GetType().Assembly.Location);}
    }

    /// <summary>
    /// EnvironmentCCW is a wrapper around Env - specifically made to be non-static
    /// as to be able to be called from COM (ButtonHook/C++ code can now use Environment as well
    /// </summary>
    [Guid("85E2E5F6-877F-4edd-B7D1-D52C431F0AFC")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class EnvironmentCCW
    {        
        public bool IsWindowsOSSupported()
        {
            return Env.IsWindowsOSSupported();
        }
        public int GetCurWindowsTheme()
        {
            return (int)Env.Theme;
        }
    }

}
