using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf;
using StoicGoose.Common.Utilities;
using StoicGoose.Core.Machines;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using CartridgeMetadata = StoicGoose.Core.Cartridges.Metadata;

public class UStoicGoose : IEmuCore
{
    public static UStoicGoose instance;
    public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

    /* Constants */
    readonly static int maxScreenSizeFactor = 5;
    readonly static int maxRecentFiles = 15;
    readonly static int statusIconSize = 12;

    readonly static List<(string description, string extension, Func<string, System.IO.Stream> streamReadFunc)> supportedFileInformation = new()
        {
            ("WonderSwan ROMs", ".ws", GetStreamFromFile),
            ("WonderSwan Color ROMs", ".wsc", GetStreamFromFile),
            ("Zip Archives", ".zip", GetStreamFromFirstZippedFile)
        };

    /* Various handlers */
    DatabaseHandler databaseHandler = default;
    SGVideoPlayer graphicsHandler = default;
    SGSoundPlayer soundHandler = default;
    SGKeyboard inputHandler = default;
    SGLogger loggerHandler = default;
    public EmulatorHandler emulatorHandler = default;
    private RomPlatformType mPlatform = RomPlatformType.WonderSwan;

    /* Misc. windows */
    //SoundRecorderForm soundRecorderForm = default;
    //CheatsForm cheatsForm = default;

    /* Misc. runtime variables */
    Type machineType = default;
    bool isVerticalOrientation = false;
    string internalEepromPath = string.Empty;

    public string CurrRomName { get; private set; }

    #region 实现IEmuCore
    public override RomPlatformType Platform => mPlatform;

    public override uint Frame => (uint)emulatorHandler.AxiEmuRunFrame;

    public override Texture OutputPixel => graphicsHandler.rawBufferWarper;

    public override RawImage DrawCanvas => graphicsHandler.DrawCanvas;
    public override object GetState()
    {
        throw new NotImplementedException();
    }

    public override byte[] GetStateBytes()
    {
        throw new NotImplementedException();
    }

    public override void LoadState(object state)
    {
        throw new NotImplementedException();
    }

    public override void LoadStateFromBytes(byte[] data)
    {
        throw new NotImplementedException();
    }

    public override void Pause()
    {
        PauseEmulation();
    }

    public override void Resume()
    {
        UnpauseEmulation();
    }

    public override MsgBool StartGame(RomFile romFile)
    {
        mPlatform = romFile.Platform;

        Init();


        //保存当前正在进行的游戏存档
        if (emulatorHandler != null && !emulatorHandler.IsRunning)
        {
            SaveAllData();
        }

        if (LoadAndRunCartridge(romFile.LocalFilePath))
            return true;
        else
            return "Rom加载失败";
    }

    public override void Dispose()
    {
        //保存当前正在进行的游戏存档
        if (emulatorHandler != null && !emulatorHandler.IsRunning)
        {
            SaveAllData();
        }
        EmuClose();
    }

    public override void DoReset()
    {
        ResetEmulation();
    }

    public override IControllerSetuper GetControllerSetuper()
    {
        throw new NotImplementedException();
    }

    public override bool PushEmulatorFrame()
    {
        throw new NotImplementedException();
    }

    public override void AfterPushFrame()
    {
        throw new NotImplementedException();
    }

    public override void GetAudioParams(out int frequency, out int channels)
    {
        throw new NotImplementedException();
    }
    #endregion

    //Cheat[] cheats = default;

    #region Unity 生命周期

    void Awake()
    {
        //关闭垂直同步
        QualitySettings.vSyncCount = 0;
        //设为60帧
        Application.targetFrameRate = 60;

        instance = this;
        loggerHandler = new SGLogger();
        graphicsHandler = this.gameObject.GetComponent<SGVideoPlayer>();
        soundHandler = this.gameObject.GetComponent<SGSoundPlayer>();
        inputHandler = this.gameObject.GetComponent<SGKeyboard>();
        Log.Initialize(loggerHandler);
        Program.InitPath(Application.persistentDataPath);
        //Init();
        //LoadAndRunCartridge("G:/BaiduNetdiskDownload/Rockman & Forte - Mirai Kara no Chousen Sha (J) [M][!].ws");
    }
    private void Update()
    {
        if (!emulatorHandler.IsRunning)
            return;

        inputHandler.Update_InputData();

        emulatorHandler.Frame_Update();
    }
    void OnDestroy()
    {
        EmuClose();
    }
    #endregion
    private void Init()
    {
        Log.WriteEvent(LogSeverity.Information, this, "Initializing emulator and UI...");

        machineType = Program.Configuration.General.PreferOriginalWS ? typeof(WonderSwan) : typeof(WonderSwanColor);

        InitializeEmulatorHandler();
        VerifyConfiguration();
        InitializeOtherHandlers();
        //InitializeWindows();

        //SizeAndPositionWindow();
        SetWindowTitleAndStatus();
        Log.WriteEvent(LogSeverity.Information, this, "Initialization done!");
    }


    private void EmuClose()
    {
        SaveAllData();
        emulatorHandler.Shutdown();

        Program.SaveConfiguration();
    }


    private void InitializeEmulatorHandler()
    {
        emulatorHandler = new EmulatorHandler(machineType);
        emulatorHandler.SetFpsLimiter(Program.Configuration.General.LimitFps);
    }

    private void VerifyConfiguration()
    {
        foreach (var button in emulatorHandler.Machine.GameControls.Replace(" ", "").Split(','))
        {
            if (!Program.Configuration.Input.GameControls.ContainsKey(button))
                Program.Configuration.Input.GameControls[button] = new();
        }

        foreach (var button in emulatorHandler.Machine.HardwareControls.Replace(" ", "").Split(','))
        {
            if (!Program.Configuration.Input.SystemControls.ContainsKey(button))
                Program.Configuration.Input.SystemControls[button] = new();
        }

        if (Program.Configuration.Video.ScreenSize < 2 || Program.Configuration.Video.ScreenSize > maxScreenSizeFactor)
            Program.Configuration.Video.ResetToDefault(nameof(Program.Configuration.Video.ScreenSize));

        //if (string.IsNullOrEmpty(Program.Configuration.Video.Shader) || (graphicsHandler != null && !graphicsHandler.AvailableShaders.Contains(Program.Configuration.Video.Shader)))
        //    Program.Configuration.Video.Shader = GraphicsHandler.DefaultShaderName;
    }

    private void InitializeOtherHandlers()
    {
        databaseHandler = new DatabaseHandler();

        //statusIconsLocation = machineType == typeof(WonderSwan) ? new(0, DisplayControllerCommon.ScreenHeight) : new(DisplayControllerCommon.ScreenWidth, 0);

        //TODO graphicsHandler基本参数,可能需要补上
        //graphicsHandler = new GraphicsHandler(machineType, new(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight), statusIconsLocation, statusIconSize, machineType != typeof(WonderSwan), Program.Configuration.Video.Shader)
        //{
        //    IsVerticalOrientation = isVerticalOrientation
        //};

        //TODO 声音基本参数,可能需要补上
        //soundHandler = new SoundHandler(44100, 2);
        //soundHandler.SetVolume(1.0f);
        //soundHandler.SetMute(Program.Configuration.Sound.Mute);
        //soundHandler.SetLowPassFilter(Program.Configuration.Sound.LowPassFilter);

        //TODO Input基本参数,可能需要补上
        //inputHandler = new InputHandler(renderControl);
        //inputHandler.SetKeyMapping(Program.Configuration.Input.GameControls, Program.Configuration.Input.SystemControls);
        //inputHandler.SetVerticalOrientation(isVerticalOrientation);
        //inputHandler.SetEnableRemapping(Program.Configuration.Input.AutoRemap);
        //inputHandler.SetVerticalRemapping(emulatorHandler.Machine.VerticalControlRemap
        //    .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
        //    .Select(x => x.Split('=', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        //    .ToDictionary(x => x[0], x => x[1]));


        emulatorHandler.Machine.DisplayController.SendFramebuffer = graphicsHandler.UpdateScreen;
        emulatorHandler.Machine.SoundController.SendSamples = (s) =>
        {
            soundHandler.EnqueueSamples(s);
            //soundRecorderForm.EnqueueSamples(s);
        };

        emulatorHandler.Machine.ReceiveInput += () =>
        {
            //var buttonsPressed = new List<string>();
            //var buttonsHeld = new List<string>();

            //inputHandler.PollInput(ref buttonsPressed, ref buttonsHeld);
            long buttonsHeld = 0;
            inputHandler.PollInput(ref buttonsHeld);
            return buttonsHeld;
            //if (buttonsPressed.Contains("Volume"))
            //    emulatorHandler.Machine.SoundController.ChangeMasterVolume();

            //return (buttonsPressed, buttonsHeld);
        };

        //renderControl.Resize += (s, e) => { if (s is Control control) graphicsHandler.Resize(control.ClientRectangle); };
        //renderControl.Paint += (s, e) =>
        //{
        //    graphicsHandler.SetClearColor(Color.Black);

        //    graphicsHandler.ClearFrame();

        //    if (emulatorHandler.Machine is MachineCommon machine)
        //    {
        //        var activeIcons = new List<string>() { "Power" };

        //        if (machine.BuiltInSelfTestOk) activeIcons.Add("Initialized");

        //        if (machine.DisplayController.IconSleep) activeIcons.Add("Sleep");
        //        if (machine.DisplayController.IconVertical) activeIcons.Add("Vertical");
        //        if (machine.DisplayController.IconHorizontal) activeIcons.Add("Horizontal");
        //        if (machine.DisplayController.IconAux1) activeIcons.Add("Aux1");
        //        if (machine.DisplayController.IconAux2) activeIcons.Add("Aux2");
        //        if (machine.DisplayController.IconAux3) activeIcons.Add("Aux3");

        //        if (machine.SoundController.HeadphonesConnected) activeIcons.Add("Headphones");
        //        if (machine.SoundController.MasterVolume == 0) activeIcons.Add("Volume0");
        //        if (machine.SoundController.MasterVolume == 1) activeIcons.Add("Volume1");
        //        if (machine.SoundController.MasterVolume == 2) activeIcons.Add("Volume2");
        //        if (machine.SoundController.MasterVolume == 3 && machine is WonderSwanColor) activeIcons.Add("Volume3");

        //        graphicsHandler.UpdateStatusIcons(activeIcons);
        //    }
        //    graphicsHandler.DrawFrame();
        //};

        internalEepromPath = System.IO.Path.Combine(Program.InternalDataPath, $"{machineType.Name}.eep");
    }

    //private void InitializeWindows()
    //{
    //    soundRecorderForm = new(soundHandler.SampleRate, soundHandler.NumChannels);
    //    cheatsForm = new()
    //    {
    //        Callback = (c) =>
    //        {
    //            if (emulatorHandler.IsRunning)
    //                cheats = (Cheat[])c.Clone();
    //        }
    //    };
    //}

    private void SizeAndPositionWindow()
    {
        graphicsHandler.SetSize(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight);
        //if (WindowState == For emulatorHandler.Machine.ScreenHeight;mWindowState.Maximized)
        //    WindowState = FormWindowState.Normal;

        //MinimumSize = SizeFromClientSize(CalculateRequiredClientSize(2));
        //Size = SizeFromClientSize(CalculateRequiredClientSize(Program.Configuration.Video.ScreenSize));
        //var screen = Screen.FromControl(this);
        //var workingArea = screen.WorkingArea;
        //Location = new Point()
        //{
        //    X = Math.Max(workingArea.X, workingArea.X + (workingArea.Width - Width) / 2),
        //    Y = Math.Max(workingArea.Y, workingArea.Y + (workingArea.Height - Height) / 2)
        //};
    }


    //TODO 设置屏幕宽高 看是否需要
    //private Size CalculateRequiredClientSize(int screenSize)
    //{
    //    if (emulatorHandler == null || graphicsHandler == null)
    //        return ClientSize;

    //    var statusIconsOnRight = statusIconsLocation.X > statusIconsLocation.Y;

    //    int screenWidth, screenHeight;

    //    if (!isVerticalOrientation)
    //    {
    //        screenWidth = emulatorHandler.Machine.ScreenWidth;
    //        screenHeight = emulatorHandler.Machine.ScreenHeight;
    //        if (statusIconsOnRight) screenWidth += statusIconSize;
    //        if (!statusIconsOnRight) screenHeight += statusIconSize;
    //    }
    //    else
    //    {
    //        screenWidth = emulatorHandler.Machine.ScreenHeight;
    //        screenHeight = emulatorHandler.Machine.ScreenWidth;
    //        if (!statusIconsOnRight) screenWidth += statusIconSize;
    //        if (statusIconsOnRight) screenHeight += statusIconSize;
    //    }

    //    return new(screenWidth * screenSize, (screenHeight * screenSize) + menuStrip.Height + statusStrip.Height);
    //}

    private void SetWindowTitleAndStatus()
    {
        //TODO 修改为状态字符串,显示在某个地方

        //var titleStringBuilder = new StringBuilder();

        //titleStringBuilder.Append($"{Application.ProductName} {Program.GetVersionString(false)}");

        //if (emulatorHandler.Machine.Cartridge.IsLoaded)
        //{
        //    titleStringBuilder.Append($" - [{Path.GetFileName(Program.Configuration.General.RecentFiles.First())}]");

        //    var statusStringBuilder = new StringBuilder();
        //    statusStringBuilder.Append($"Emulating {emulatorHandler.Machine.Manufacturer} {emulatorHandler.Machine.Model}, ");
        //    statusStringBuilder.Append($"playing {databaseHandler.GetGameTitle(emulatorHandler.Machine.Cartridge.Crc32, emulatorHandler.Machine.Cartridge.SizeInBytes)} ({emulatorHandler.Machine.Cartridge.Metadata.GameIdString})");

        //    tsslStatus.Text = statusStringBuilder.ToString();
        //    tsslEmulationStatus.Text = emulatorHandler.IsRunning ? (emulatorHandler.IsPaused ? "Paused" : "Running") : "Stopped";
        //}
        //else
        //{
        //    tsslStatus.Text = "Ready";
        //    tsslEmulationStatus.Text = "Stopped";
        //}

        //Text = titleStringBuilder.ToString();
    }

    private void LoadBootstrap(string filename)
    {
        if (GlobalVariables.EnableSkipBootstrapIfFound) return;

        if (!emulatorHandler.IsRunning)
        {
            if (AxiIO.File.Exists(filename))
            {
                //using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                //var data = new byte[stream.Length];
                //stream.Read(data, 0, data.Length);

                var data = AxiIO.File.ReadAllBytes(filename);

                emulatorHandler.Machine.LoadBootstrap(data);
            }
            emulatorHandler.Machine.UseBootstrap = Program.Configuration.General.UseBootstrap;
        }
    }

    private void LoadInternalEeprom()
    {
        if (!emulatorHandler.IsRunning && AxiIO.File.Exists(internalEepromPath))
        {
            //using var stream = new FileStream(internalEepromPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            //var data = new byte[stream.Length];
            //stream.Read(data, 0, data.Length);

            var data = AxiIO.File.ReadAllBytes(internalEepromPath);

            emulatorHandler.Machine.LoadInternalEeprom(data);
        }
    }

    private static System.IO.Stream GetStreamFromFile(string filename)
    {
        //return new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        byte[] data = AxiIO.File.ReadAllBytes(filename);
        return new System.IO.MemoryStream(data);
    }

    private static System.IO.Stream GetStreamFromFirstZippedFile(string filename)
    {
        //return new ZipArchive(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)).Entries.FirstOrDefault()?.Open();

        byte[] data = AxiIO.File.ReadAllBytes(filename);
        return new ZipArchive(new System.IO.MemoryStream(data)).Entries.FirstOrDefault()?.Open();
    }

    private bool LoadAndRunCartridge(string filename)
    {
        try
        {
            if (emulatorHandler.IsRunning)
            {
                SaveAllData();
                emulatorHandler.Shutdown();
            }

            using var inputStream = supportedFileInformation.FirstOrDefault(x => x.extension == System.IO.Path.GetExtension(filename)).streamReadFunc(filename) ?? GetStreamFromFile(filename);
            using var stream = new System.IO.MemoryStream();
            inputStream.CopyTo(stream);
            stream.Position = 0;

            var data = new byte[stream.Length];
            stream.Read(data, 0, data.Length);
            emulatorHandler.Machine.LoadRom(data);

            graphicsHandler.IsVerticalOrientation = isVerticalOrientation = emulatorHandler.Machine.Cartridge.Metadata.Orientation == CartridgeMetadata.Orientations.Vertical;
            inputHandler.SetVerticalOrientation(isVerticalOrientation);

            CurrRomName = System.IO.Path.GetFileName(filename);

            LoadRam();

            LoadBootstrap(emulatorHandler.Machine is WonderSwan ? Program.Configuration.General.BootstrapFile : Program.Configuration.General.BootstrapFileWSC);
            LoadInternalEeprom();

            //初始化音频
            soundHandler.Initialize();

            emulatorHandler.Startup();

            SizeAndPositionWindow();
            SetWindowTitleAndStatus();

            Program.SaveConfiguration();
            return true;
        }
        catch (Exception ex) when (!AppEnvironment.DebugMode)
        {
            App.log.Error("ex=>"+ex.ToString());
            return false;
        }
    }

    private void LoadRam()
    {
        //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav");
        var path = System.IO.Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav");
        //if (!File.Exists(path)) return;
        if (!AxiIO.File.Exists(path)) return;

        //using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        //var data = new byte[stream.Length];
        //stream.Read(data, 0, data.Length);

        var data = AxiIO.File.ReadAllBytes(path);
        if (data.Length != 0)
            emulatorHandler.Machine.LoadSaveData(data);
    }

    private void SaveAllData()
    {
        SaveInternalEeprom();
        SaveRam();
    }

    private void SaveInternalEeprom()
    {
        var data = emulatorHandler.Machine.GetInternalEeprom();
        if (data.Length == 0) return;

        //using var stream = new FileStream(internalEepromPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
        //stream.Write(data, 0, data.Length);

        AxiIO.File.WriteAllBytes(internalEepromPath, data);
    }

    private void SaveRam()
    {
        var data = emulatorHandler.Machine.GetSaveData();
        if (data.Length == 0) return;

        //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav");
        var path = System.IO.Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav");

        //using var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
        //stream.Write(data, 0, data.Length);

        AxiIO.File.WriteAllBytes(path, data);
    }


    private void PauseEmulation()
    {
        if (!emulatorHandler.IsRunning) return;

        emulatorHandler.Pause();
        soundHandler.Pause();

        SetWindowTitleAndStatus();
    }

    private void UnpauseEmulation()
    {
        if (!emulatorHandler.IsRunning) return;

        emulatorHandler.Unpause();
        soundHandler.Unpause();

        SetWindowTitleAndStatus();
    }

    private void ResetEmulation()
    {
        SaveAllData();
        emulatorHandler.Reset();

        Program.SaveConfiguration();
    }

}

static class Program
{
    static string jsonConfigFileName;//= "Config.json";
    static string logFileName;//= "Log.txt";
    static string internalDataDirectoryName;//= "Internal";
    static string saveDataDirectoryName;//= "Saves";
    static string cheatDataDirectoryName;//= "Cheats";
    static string debuggingDataDirectoryName;//= "Debugging";
    static string assetsDirectoryName;//= "Assets";
    static string shaderDirectoryName;//= "Shaders";
    static string noIntroDatDirectoryName;//= "No-Intro";
    static string mutexName;//= $"Unity_{GetVersionDetails()}";
    static string programDataDirectory;//= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Application.ProductName);
    static string programConfigPath;//= Path.Combine(programDataDirectory, jsonConfigFileName);

    public static Configuration Configuration;// { get; private set; } = LoadConfiguration(programConfigPath);

    public static string DataPath;//{ get; } = string.Empty;
    public static string InternalDataPath;//{ get; } = string.Empty;
    public static string SaveDataPath;//{ get; } = string.Empty;
    public static string CheatsDataPath;//{ get; } = string.Empty;
    public static string DebuggingDataPath;//{ get; } = string.Empty;

    static string programApplicationDirectory;// = AppDomain.CurrentDomain.BaseDirectory;
    static string programAssetsDirectory;// = Path.Combine(programApplicationDirectory, assetsDirectoryName);

    //public static string ShaderPath { get; } = string.Empty;
    public static string NoIntroDatPath;// { get; } = string.Empty;

    //static MainForm mainForm = default;

    public static void InitPath(string CustonDataDir)
    {
        try
        {
            jsonConfigFileName = "Config.json";
            logFileName = "Log.txt";
            internalDataDirectoryName = "Internal";
            saveDataDirectoryName = "Saves";
            cheatDataDirectoryName = "Cheats";
            debuggingDataDirectoryName = "Debugging";
            assetsDirectoryName = "Assets";
            shaderDirectoryName = "Shaders";
            noIntroDatDirectoryName = "No-Intro";
            mutexName = $"Unity_{GetVersionDetails()}";
            programDataDirectory = System.IO.Path.Combine(CustonDataDir, "AxibugEmu");
            programConfigPath = System.IO.Path.Combine(programDataDirectory, jsonConfigFileName);
            Configuration = LoadConfiguration(programConfigPath);
            Log.WriteLine(System.IO.Path.Combine(programDataDirectory, logFileName));
            programApplicationDirectory = AppDomain.CurrentDomain.BaseDirectory;
            programAssetsDirectory = System.IO.Path.Combine(programApplicationDirectory, assetsDirectoryName);
            AxiIO.Directory.CreateDirectory(DataPath = programDataDirectory);
            AxiIO.Directory.CreateDirectory(InternalDataPath = System.IO.Path.Combine(programDataDirectory, internalDataDirectoryName));
            AxiIO.Directory.CreateDirectory(SaveDataPath = System.IO.Path.Combine(programDataDirectory, saveDataDirectoryName));
            AxiIO.Directory.CreateDirectory(CheatsDataPath = System.IO.Path.Combine(programDataDirectory, cheatDataDirectoryName));
            AxiIO.Directory.CreateDirectory(DebuggingDataPath = System.IO.Path.Combine(programDataDirectory, debuggingDataDirectoryName));

            //if (!Directory.Exists(ShaderPath = Path.Combine(programAssetsDirectory, shaderDirectoryName)))
            //    throw new DirectoryNotFoundException("Shader directory missing");

            if (!AxiIO.Directory.Exists(NoIntroDatPath = System.IO.Path.Combine(programAssetsDirectory, noIntroDatDirectoryName)))
                throw new Exception("No-Intro .dat directory missing");
        }
        catch (Exception e)
        {
        }
    }

    //[STAThread]
    //static void Main()
    //{
    //    using var mutex = new Mutex(true, mutexName, out bool newInstance);
    //    if (!newInstance)
    //    {
    //        MessageBox.Show($"Another instance of {Application.ProductName} is already running.\n\nThis instance will now shut down.",
    //            $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    //        Environment.Exit(-1);
    //    }

    //    Application.SetHighDpiMode(HighDpiMode.SystemAware);
    //    Application.EnableVisualStyles();
    //    Application.SetCompatibleTextRenderingDefault(false);

    //    if (!Debugger.IsAttached)
    //    {
    //        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
    //        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
    //        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    //    }

    //    Application.Run(mainForm = new MainForm());
    //}

    //static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    //{
    //    if (e.Exception is GLFWException glEx)
    //    {
    //        var renderControl = mainForm.Controls["renderControl"] as OpenGL.RenderControl;
    //        MessageBox.Show($"{glEx.Message.EnsureEndsWithPeriod()}\n\n{Application.ProductName} requires GPU and drivers supporting OpenGL {renderControl.APIVersion.Major}.{renderControl.APIVersion.Minor}.", $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    //    }
    //    else
    //    {
    //        MessageBox.Show(e.Exception.Message.EnsureEndsWithPeriod(), $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    //    }

    //    Environment.Exit(-1);
    //}

    //static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    //{
    //    MessageBox.Show((e.ExceptionObject as Exception).Message, $"{Application.ProductName} Startup Error");
    //    Environment.Exit(-1);
    //}

    private static Configuration LoadConfiguration(string filename)
    {
        AxiIO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename));

        Configuration configuration;
        //if (!File.Exists(filename) || (configuration = filename.DeserializeFromFile<Configuration>()) == null)
        //{
        //    configuration = new Configuration();
        //    configuration.SerializeToFile(filename);
        //}

        configuration = new Configuration();

        return configuration;
    }

    public static void ReplaceConfiguration(Configuration newConfig)
    {
        ConfigurationBase.CopyConfiguration(newConfig, Configuration);
        SaveConfiguration();
    }

    public static void SaveConfiguration()
    {
        //Configuration?.SerializeToFile(programConfigPath);
    }

    private static string GetVersionDetails()
    {
        //return $"{ThisAssembly.Git.Branch}-{ThisAssembly.Git.Commit}{(ThisAssembly.Git.IsDirty ? "-dirty" : string.Empty)}{(GlobalVariables.IsDebugBuild ? "+debug" : string.Empty)}";
        return $"{(GlobalVariables.IsDebugBuild ? "+debug" : string.Empty)}";
    }

    //public static string GetVersionString(bool detailed)
    //{
    //    var version = new Version(Application.ProductVersion);
    //    var stringBuilder = new StringBuilder();
    //    stringBuilder.Append($"v{version.Major:D3}{(version.Minor != 0 ? $".{version.Minor}" : string.Empty)}");
    //    if (detailed) stringBuilder.Append($" ({GetVersionDetails()})");
    //    return stringBuilder.ToString();
    //}
}