#if false
using OpenTK.Graphics.OpenGL4;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.Common;
using OpenTK.Mathematics;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Xml.Serialization;
using SixLabors.ImageSharp;
using System.Reflection.Emit;
using System.Text.Json;
using OpenTK.Windowing.GraphicsLibraryFramework;

namespace Updater;

internal class Updater : NativeWindow
{
    readonly List<IRenderObject> RenderObjects = new();
    private readonly Queue<Action> queue = new();
    private RenderObject? TotalProgressBar, CurrentProgressBar;
    private RenderText? Current_Process, Total_Downloaded, Transfer_Speed;
    private readonly System.Timers.Timer Speed;
    private readonly BackgroundWorker Download = new();
    private const float Range = 1.8531212f;
    private readonly Argumets Argumets = new();
    private double Scale = 1, filscale = 1;
    private ulong before = 0, fil = 0, last = 0, current = 0;
    private float TotalPer = 0f, CurrentPer = 0f;
    private float[] to;
    private float[][] cur;
    private readonly ConfigFile cf;
    private int max = 0;
    private bool init = false;
    private List<double> speeds = new();
#if DEBUG
    private int iii = 0, iiii = 0;
    private List<int> speeds2 = new(), speeds3 = new();
#endif

    public Updater(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings, Argumets args) : base(nativeWindowSettings)
    {
        
        WindowState = WindowState.Normal;
        VSync = VSyncMode.Off;
        Download.DoWork += new DoWorkEventHandler(Download_DoWork);
        Download.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Download_RunWorkerCompleted);
        Download.WorkerReportsProgress = true;
        Argumets = args;
        Argumets.RemoteDirectory = Uri.EscapeDataString(args.RemoteDirectory);
        to = new float[12] {
            -0.926560581f, -0.133858263f, 0f, //top r
            -0.926560581f, -0.314960629f, 0f, //bot r
            -0.926560581f, -0.314960629f, 0f, //bot l
            -0.926560581f, -0.133858263f, 0f }; //top l
        cur = new float[][] { new float[12] { -0.9265606f, -0.5984252f, 0f, -0.9265606f, -0.779527545f, 0f, -0.9265606f, -0.779527545f, 0f, -0.9265606f, -0.5984252f, 0f } };
        Speed = new()
        {
            Interval = 200
        };
        Speed.Elapsed += Speed_Elapsed;
        cf = Config.GetConfig();
        if (!Argumets.LocalDirectory.EndsWith('/') && !Argumets.LocalDirectory.EndsWith('\\')) Argumets.LocalDirectory += Program.Slash;
        if (Argumets.Updater is not null && (!Argumets.Updater.EndsWith('/') && !Argumets.Updater.EndsWith('\\'))) Argumets.Updater += Program.Slash;
        GL.Viewport(0, 0, StartGUI.Width, StartGUI.Height);
        CenterWindow(0);
        uint small = (uint)Math.Round(0.078740157480315 * StartGUI.Height, 0);
        background = new Color4(cf.Colors.Background.R, cf.Colors.Background.G, cf.Colors.Background.B, cf.Colors.Background.A);
        RenderObjects.Add(new RenderObject(new float[] { -0.7919217f, 0.88188976f, 0f, 1f, 1f, -0.7919217f, 0.37007874f, 0f, 1f, 0f, -0.9510404f, 0.37007874f, 0f, 0f, 0f, -0.9510404f, 0.88188976f, 0f, 0f, 1f }, new uint[] { 0, 1, 3, 1, 2, 3 }, new Vector4(cf.Colors.Progress_bars.Backcolor.R, cf.Colors.Progress_bars.Backcolor.G, cf.Colors.Progress_bars.Backcolor.B, cf.Colors.Progress_bars.Backcolor.A), BufferUsageHint.StaticDraw, StartGUI.Logo));
        RenderObjects.Add(new RenderObject(new float[] {
            0.9363525f, -0.5748032f, 0.0f,
            0.9363525f, -0.8031496f, 0.0f,
            -0.9339045f, -0.8031496f, 0.0f,
            -0.9339045f, -0.5748032f, 0.0f,
            0.9363525f, -0.11304348f, 0.0f,
            0.9363525f, -0.341389941f, 0.0f,
            -0.9339045f, -0.341389941f, 0.0f,
            -0.9339045f, -0.11304348f, 0.0f }, new uint[] { 0, 1, 3, 1, 2, 3, 4, 5, 7, 5, 6, 7 }, new Vector4(cf.Colors.Progress_bars.Backcolor.R, cf.Colors.Progress_bars.Backcolor.G, cf.Colors.Progress_bars.Backcolor.B, cf.Colors.Progress_bars.Backcolor.A)));
        RenderObjects.Add(TotalProgressBar = new RenderObject(to, new uint[] { 0, 1, 3, 1, 2, 3 }, new Vector4(cf.Colors.Progress_bars.Fillcolor.R, cf.Colors.Progress_bars.Fillcolor.G, cf.Colors.Progress_bars.Fillcolor.B, cf.Colors.Progress_bars.Fillcolor.A)));
        RenderObjects.Add(CurrentProgressBar = new RenderObject(cur[0], new uint[] { 0, 1, 3, 1, 2, 3 }, new Vector4(cf.Colors.Progress_bars.Fillcolor.R, cf.Colors.Progress_bars.Fillcolor.G, cf.Colors.Progress_bars.Fillcolor.B, cf.Colors.Progress_bars.Fillcolor.A)));
        RenderObjects.Add(new RenderText("JacobTech", "OpenSans-Regular", (uint)Math.Round(0.1889763779527559 * StartGUI.Height, 0), -0.7648515f, 0.481781363f, 1.2f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
        RenderObjects.Add(Current_Process = new RenderText("Current Process: Waiting for threads to close", "joystix-monospace", small, -0.9381188f, -0.5217391f, 1.2f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
        small = (uint)Math.Round(0.0656167979002625 * StartGUI.Height, 0);
        RenderObjects.Add(Total_Downloaded = new RenderText("Download Amount", "OpenSans-Regular", small, -0.9381188f, 0.149797574f, 1.0f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
        small = (uint)Math.Round(0.078740157480315 * StartGUI.Height, 0);
        RenderObjects.Add(Transfer_Speed = new RenderText("Download Speed", "OpenSans-Regular", small, -0.9381188f, -0.05263158f, 1.2f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
        CursorState = CursorState.Normal;
        Speed.Start();
        queue.Enqueue(new Action(() => { Download.RunWorkerAsync(); }));
    }

    private void Speed_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
    {
        ulong BytesPertenthSec = ((ulong)Math.Round(current / Scale, 0)) - last;
        last = ((ulong)Math.Round(current / Scale, 0));
        speeds.Add(BytesPertenthSec * 5);
        if (speeds.Count > 25) speeds.RemoveAt(0);
#if DEBUG
        speeds2.Add(iii * 5);
        speeds3.Add(iiii * 5);
        iii = 0;
        iiii = 0;
        if (speeds2.Count > 25) speeds2.RemoveAt(0);
        if (speeds3.Count > 25) speeds3.RemoveAt(0);
#endif
        if (Transfer_Speed is not null && speeds.Average() != 0) Transfer_Speed.Text = Download_Speed_Neat(speeds.Average());
    }

    private void Download_DoWork(object? sender, DoWorkEventArgs e)
    {
        bool goodpre = true;
        while (goodpre)
        {
            while (!Program.IsProcessOpen(Argumets.Process))
            {
                goodpre = false;
                break;
            }
        }
        ChangeProcessText("Deleting old program files");
        
        void TryDeleteDir(string? dir)
        {
            if (string.IsNullOrEmpty(dir) || string.IsNullOrWhiteSpace(dir)) return;
            try
            {
                if (Directory.Exists(dir)) Directory.Delete(dir, true);
            }
            catch
            {
                DirectoryInfo dirInfo = new(dir);
                foreach (var file in dirInfo.GetFiles())
                {
                    try
                    {
                        file.Delete();
                    }
                    catch { }
                }
                foreach (var subdir in dirInfo.GetDirectories())
                {
                    TryDeleteDir(subdir.FullName);
                }
            }
        }
        TryDeleteDir(Argumets.LocalDirectory);
        Directory.CreateDirectory(Argumets.LocalDirectory);
        if (Argumets.Updater is not null) TryDeleteDir(Argumets.Updater);
        if (Argumets.Updater is not null) Directory.CreateDirectory(Argumets.Updater);

#pragma warning disable SYSLIB0014 // Type or member is obsolete
        using WebClient web = new();
#pragma warning restore SYSLIB0014 // Type or member is obsolete
        ChangeProcessText("Getting update info");
        string rem = web.DownloadString($"https://{Program.Domain}/Updater/Files?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriSeflContaind}{Argumets.UriPlatform}{Argumets.UriVersion}");
        ulong realmax;
        string uri;
        try
        {
            realmax = ulong.Parse(web.DownloadString($"https://{Program.Domain}/Updater/GetSize?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriSeflContaind}{Argumets.UriPlatform}{Argumets.UriVersion}"));
            if (realmax > int.MaxValue)
            {
                Scale = (double)int.MaxValue / (double)realmax;
                max = int.MaxValue;
            }
            else max = (int)realmax;
            web.DownloadProgressChanged += Web_DownloadProgressChanged;
            web.DownloadFileCompleted += Web_DownloadFileCompleted;
            queue.Enqueue(new Action(() => { if (Total_Downloaded is not null) Total_Downloaded.Text = TotalDownloadAmountNeat(realmax); }));
            Speed.Start();
            foreach (string file in rem.Split('\n'))
            {
                if (string.IsNullOrEmpty(file)) return;
                
                uri = $"https://{Program.Domain}/Updater/GetFileSize?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriVersion}{Argumets.UriSeflContaind}{Argumets.UriPlatform}&file={Uri.EscapeDataString(file)}";
                Uri u = new($"https://{Program.Domain}/Updater/GetFile?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriVersion}{Argumets.UriSeflContaind}{Argumets.UriPlatform}&file={Uri.EscapeDataString(file)}");
                string[] temp = file.Split('/');
                if (file.Contains('/'))
                {

                    string cur = "";
                    for (int i = 0; i < temp.Length - 1; i++)
                    {
                        cur += temp[i] + "/";
                        if (Argumets.Updater is null)
                        {
                            if (!Directory.Exists(Argumets.LocalDirectory + cur))
                                Directory.CreateDirectory(Argumets.LocalDirectory + cur);
                        }
                        else
                        {
                            if (!Directory.Exists(Argumets.Updater + cur))
                                Directory.CreateDirectory(Argumets.Updater + cur);
                        }
                    }
                }
                DownloadFile(web, uri, u, temp, file.Replace("/", Program.Slash)).Wait();
            }
        }
        catch (Exception ex)
        {
            StackTrace st = new(ex, true);
            StackFrame? frame = st.GetFrame(0);
            if (frame is null) return;
            int line = frame.GetFileLineNumber();
            string msg = $"Error in Updater.exe in function Download_DoWork on line '{line}' through error '{ex.Message}'\nERROR:\n'{ex}' FRAM:\n '{frame}'";
            _ = new HttpClient().PostAsync($"https://{Program.Domain}/Updater/Error/updater", new StringContent(msg));
            MessageBox.Show(ex.ToString());
        }
    }

    private Task DownloadFile(WebClient web, string uri, Uri u, string[] temp, string file)
    {
        while (!web.IsBusy)
        {
            fil = ulong.Parse(web.DownloadString(uri));
            int locfil;
            filscale = 1;
            if (fil > int.MaxValue)
            {
                locfil = int.MaxValue;
                filscale = (double)int.MaxValue / (double)fil;
            }
            else locfil = (int)fil;
            CurrentPer = Range / locfil;
            TotalPer = Range / max;
            ChangeProcessText($"Downloading {temp[^1]}");
            if (Argumets.Updater is null)
            {
                web.DownloadFileTaskAsync(u, Argumets.LocalDirectory + file).Wait();
            }
            else
            {
                web.DownloadFileTaskAsync(u, Argumets.Updater + file).Wait();
            }

            return Task.CompletedTask;
        }
        return Task.CompletedTask;
    }

    private void Download_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
    {
        try
        {
            if (Argumets.Updater is not null)
            {
                Process p = new();
                p.StartInfo.FileName = Path.Combine(Argumets.Updater, AppDomain.CurrentDomain.FriendlyName);
                if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD())
                {
                    Process m = Process.Start("/usr/bin/chmod", $"+x {Path.Combine(Argumets.Updater, AppDomain.CurrentDomain.FriendlyName)}");
                    m.WaitForExit();
                }

                p.StartInfo.WorkingDirectory = Argumets.Updater;
                p.StartInfo.CreateNoWindow = true;
                Program.rawargs[1] = AppDomain.CurrentDomain.BaseDirectory;
                p.StartInfo.Arguments = $"\"{string.Join("\" \"", Program.rawargs)}\"";
                p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            
                p.Start();
                Close();
            }
            else
            {
                if (Argumets.Loc is not null)
                {
                    FileInfo fi = new(Argumets.Loc);
                    if (!fi.Directory!.Exists) Directory.CreateDirectory(fi.Directory.FullName);
                    UpdaterSettings temp;
                    if (!File.Exists(Argumets.Loc))
                    {
                        File.WriteAllText(Argumets.Loc, JsonSerializer.Serialize(new UpdaterSettings(), UpdaterSettingsContext.Default.UpdaterSettings));
                        temp = new();
                    }

                    try
                    {
                        UpdaterSettings? ss = JsonSerializer.Deserialize(File.ReadAllText(Argumets.Loc), UpdaterSettingsContext.Default.UpdaterSettings);
                        if (ss is null)
                        {
                            ss = new();
                        }

                        temp = ss;
                    }
                    catch
                    {
                        temp = new();
                    }

                    temp.Updater = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName);
                    if (Argumets.Platform is not null) temp.Platform = Argumets.Platform!.ToLower();
                    temp.SelfContained = Argumets.SeflContaind;
                    temp.Branch = Argumets.Branch!.ToLower() switch
                    {
                        "dev" => Branch.Dev,
                        "beta" => Branch.Beta,
                        "master" or _ => Branch.Master
                    };
                    File.WriteAllText(Argumets.Loc, JsonSerializer.Serialize(temp, UpdaterSettingsContext.Default.UpdaterSettings));
                }
                if (string.IsNullOrEmpty(Argumets.DLL) || string.IsNullOrWhiteSpace(Argumets.DLL)) Close();
                Process p = new();
                p.StartInfo.FileName = Path.Combine(Argumets.LocalDirectory, Argumets.DLL);
                if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD())
                {
                    Process m = Process.Start("/usr/bin/chmod", $"+x \"{Path.Combine(Argumets.LocalDirectory, Argumets.DLL)}\"");
                    m.WaitForExit();
                }

                p.StartInfo.WorkingDirectory = Argumets.LocalDirectory;
                p.StartInfo.CreateNoWindow = true;
                foreach (string arg in Argumets.args!)
                {
                    p.StartInfo.ArgumentList.Add(arg);
                }

                p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

                p.Start();
                Close();
            }
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }
    }
    
    private void ChangeProcessText(string Process)
    {
        queue.Enqueue(new Action(() => { if (Current_Process is not null) Current_Process.Text = $"{Process}"; }));
    }

    private void Web_DownloadFileCompleted(object? sender, AsyncCompletedEventArgs e)
    {
        before += fil;
    }

    private void Web_DownloadProgressChanged(object? sender, DownloadProgressChangedEventArgs e)
    {
        try
        {
            ulong ctemp = (ulong)Math.Round((ulong)e.BytesReceived * filscale, 0);
            if (ctemp > int.MaxValue) ctemp = int.MaxValue;
            int ctol = (int)ctemp;
            ulong total = before + (ulong)e.BytesReceived;
            ulong temp = (ulong)Math.Round(total * Scale, 0);
            if (temp > int.MaxValue) temp = int.MaxValue;
            cur[0][6] = -0.9265606f + (ctol * CurrentPer);
            cur[0][9] = cur[0][6];
            current = temp;
            if ((-0.9265606f + (temp * TotalPer)) > Range / 2)
            {
                to[6] = Range / 2;
                to[9] = to[6];
            }
            else
            {
                to[6] = -0.9265606f + (temp * TotalPer);
                to[9] = to[6];
            }

            if (queue.Count <= 30) queue.Enqueue(new Action(() =>
            {
                if (CurrentProgressBar is not null) CurrentProgressBar.Points = cur[0];
                if (TotalProgressBar is not null) TotalProgressBar.Points = to;
                if (OperatingSystem.IsWindows()) WindowsOnly.SetProgress((int)temp, max);
                if (Total_Downloaded is not null) Total_Downloaded.Text = Downloaded_Amount_Neat(total, Total_Downloaded.Text);
            }));
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }
    }

    #region Neat
    private string Download_Speed_Neat(double Number)
    {
        ConfigFileSize cfs = cf.Format.Downloadspeed;
        string Size = SizeName(Number, cfs);
        int bytes = 1024;
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MebiByte) bytes = 1000;
        int Exponet;
        if (Number / bytes >= 1)
            if (Number / Math.Pow(bytes, 2) >= 1)
                if (Number / Math.Pow(bytes, 3) >= 1) Exponet = 3;
                else Exponet = 2;
            else Exponet = 1;
        else Exponet = 0;
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MegaBit) Number *= 8;
        Number = Math.Round(Number / Math.Pow(bytes, Exponet), 2, MidpointRounding.ToEven);
        if (!Number.ToString().Contains('.'))
        {
            return $"{Number}.00{Size}/s";
        }
        else
        {
            if (Number.ToString().Remove(0, Number.ToString().IndexOf('.')).Length == 1)
            {
                return $"{Number}0{Size}/s";
            }
            else
            {
                return $"{Number}{Size}/s";
            }
        }
    }

    private string Downloaded_Amount_Neat(double Number, string Old_Text)
    {
        int Exponet = 0;
        ConfigFileSize cfs = cf.Format.Downloadamount;
        int bytes = 1024;
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MebiByte) bytes = 1000;
        string Size = SizeName(Number, cfs);
        if (Size.ToLower().StartsWith('g')) Exponet = 3;
        else if (Size.ToLower().StartsWith('m')) Exponet = 2;
        else if (Size.ToLower().StartsWith('k')) Exponet = 1;
        Number = Math.Round(Number / Math.Pow(bytes, Exponet), 2, MidpointRounding.ToEven);
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MegaBit) Number *= 8;
        string text = Old_Text.Remove(0, Old_Text.IndexOf(' '));
        if (!Number.ToString().Contains('.'))
        {
            text = $"{Number}.00{Size}{text}";
        }
        else
        {
            text = Number.ToString().Remove(0, Number.ToString().IndexOf('.')).Length != 1 ? $"{Number}{Size}{text}" : $"{Number}0{Size}{text}";
        }
        return text;
    }

    private string TotalDownloadAmountNeat(double Number)
    {
        string Output;
        int Exponet;
        ConfigFileSize cfs = cf.Format.Downloadamount;
        int bytes = 1024;
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MebiByte) bytes = 1000;
        if (Number / bytes >= 1)
            if (Number / Math.Pow(bytes, 2) >= 1)
                if (Number / Math.Pow(bytes, 3) >= 1) Exponet = 3;
                else Exponet = 2;
            else Exponet = 1;
        else Exponet = 0;
        if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MegaBit) Number *= 8;
        Output = $"0{SizeName(Number, cfs)} / {Math.Round(Number / Math.Pow(bytes, Exponet), 2, MidpointRounding.ToEven)}{SizeName(Number, cfs)}           ";
        return Output;
    }

    private static string SizeName(double Number, ConfigFileSize format)
    {
        string Size;
        switch (format)
        {
            default:
            case ConfigFileSize.MegaByte:
                if (Number / 1000 >= 1)
                    if (Number / Math.Pow(1000, 2) >= 1)
                        if (Number / Math.Pow(1000, 3) >= 1) Size = "GB";
                        else Size = "MB";
                    else Size = "KB";
                else Size = "B";
                break;
            case ConfigFileSize.MebiByte:
                if (Number / 1024 >= 1)
                    if (Number / Math.Pow(1024, 2) >= 1)
                        if (Number / Math.Pow(1024, 3) >= 1) Size = "GiB";
                        else Size = "MiB";
                    else Size = "KiB";
                else Size = "B";
                break;
            case ConfigFileSize.MegaBit:
                Number *= 8;
                if (Number / 1000 >= 1)
                    if (Number / Math.Pow(1000, 2) >= 1)
                        if (Number / Math.Pow(1000, 3) >= 1) Size = "Gb";
                        else Size = "Mb";
                    else Size = "Kb";
                else Size = "b";
                break;
            case ConfigFileSize.MebiBit:
                Number *= 8;
                if (Number / 1024 >= 1)
                    if (Number / Math.Pow(1024, 2) >= 1)
                        if (Number / Math.Pow(1024, 3) >= 1) Size = "Gib";
                        else Size = "Mib";
                    else Size = "Kib";
                else Size = "b";
                break;
        }
        return Size;
    }
    #endregion

    private Color4 background = new(0.1568627450980392f, 0.1568627450980392f, 0.1568627450980392f, 0f);

    public static Tuple<int, int, int, int> FloatToRct(float[] nums)
    {
        int y = FloatToInt(nums[1], StartGUI.Height, true);
        int wr = FloatToInt(nums[0], StartGUI.Width);
        if (nums.Count() == 21)
        {
            int x = FloatToInt(nums[15], StartGUI.Width);
            int bl = FloatToInt(nums[11], StartGUI.Height, true);
            return new(x, y, wr - x, bl - y);
        }
        else
        {
            int x = FloatToInt(nums[9], StartGUI.Width);
            int bl = FloatToInt(nums[7], StartGUI.Height, true);
            return new(x, y, wr - x, bl - y);
        }
    }

    public static float[] RctToFloat(int x, int y, int Width, int Height, bool hastexture = false)
    {
        if (hastexture)
        {
            return new float[20] {
            IntToFloat(x + Width, StartGUI.Width), IntToFloat(y, StartGUI.Height, true), 0.0f, 1.0f, 1.0f,// top r
            IntToFloat(x + Width, StartGUI.Width), IntToFloat(y + Height, StartGUI.Height, true), 0.0f, 1.0f, 0.0f,//b r
            IntToFloat(x, StartGUI.Width), IntToFloat(y + Height, StartGUI.Height, true), 0.0f, 0.0f, 0.0f,//bot l
            IntToFloat(x, StartGUI.Width), IntToFloat(y, StartGUI.Height, true), 0.0f, 0.0f, 1.0f// top l
        };
        }
        else
        {
            return new float[12] {
            IntToFloat(x + Width, StartGUI.Width), IntToFloat(y, StartGUI.Height, true), 0.0f,// top r
            IntToFloat(x + Width, StartGUI.Width), IntToFloat(y + Height, StartGUI.Height, true), 0.0f, //b r
            IntToFloat(x, StartGUI.Width), IntToFloat(y + Height, StartGUI.Height, true), 0.0f, //bot l
            IntToFloat(x, StartGUI.Width), IntToFloat(y, StartGUI.Height, true), 0.0f,// top l
        };
        }
    }

    public static int FloatToInt(float p, int Size, bool Invert = false)
    {
        double half = Size * .5;
        if (p == 0) return (int)half;
        if (Invert)
        {
            if (p < 0) return (int)Math.Round((-p * half) + half, 0);
            else return (int)Math.Round(p * half, 0);
        }
        else
        {
            if (p > 0) return (int)Math.Round((p * half) + half, 0);
            else return (int)Math.Round(half - (-p * half), 0);
        }
    }

    public static float IntToFloat(int p, int Size, bool Invert = false)
    {
        double half = Size * .5;
        double Per = Math.Round((double)1 / half, 15);
        if (p == half) return 0.0f;
        if (Invert)
        {
            if (p > half) return float.Parse($"-{((double)(p - half) * Per)}");
            else return float.Parse($"{1 - (p * Per)}");
        }
        else
        {
            if (p > half) return float.Parse($"{((double)(p - half) * Per)}");
            else return float.Parse($"-{1 - (p * Per)}");
        }
    }

    public void CenterWindow(int mon)
    {
        Box2i clientArea = Monitors.GetMonitors()[mon].ClientArea;
        int num = (clientArea.Min.X + clientArea.Max.X - Size.X) / 2;
        int num2 = (clientArea.Min.Y + clientArea.Max.Y - Size.Y) / 2;
        if (num < clientArea.Min.X)
        {
            num = clientArea.Min.X;
        }

        if (num2 < clientArea.Min.Y)
        {
            num2 = clientArea.Min.Y;
        }

        ClientRectangle = new Box2i(num, num2, num + Size.X, num2 + Size.Y);
    }
    
    int exitcode = 0;

    public int StartRender()
    {
        Context.MakeCurrent();
        while (Exists && IsVisible && !IsExiting)
        {
            TickGUI();
        }

        return exitcode;
    }

    protected override void OnResize(ResizeEventArgs e)
    {
        base.OnResize(e);
        GL.Viewport(0, 0, e.Width, e.Height);
        UpdateBuffer();
    }

    public Task TickGUI()
    {
#if DEBUG
        double getspeed(int i, List<int> list)
        {
            try
            {
                if (list.Any()) return list.Average();
                else return i;
            }
            catch { return i; }
        }
        iii++;
#endif
        GLFW.PollEvents();
        if (!queue.Any()) return Task.CompletedTask;
        for (int i = 0; i < queue.Count; i++)
        {
            Action? a = queue.Dequeue();
            if (a is not null) a.Invoke();
        }
        UpdateBuffer();
        return Task.CompletedTask;
    }

    private static void delay(int Time_delay)
    {
        int i = 0;
        //  ameTir = new System.Timers.Timer();
        var _delayTimer = new System.Timers.Timer();
        _delayTimer.Interval = Time_delay;
        _delayTimer.AutoReset = false; //so that it only calls the method once
        _delayTimer.Elapsed += (s, args) => i = 1;
        _delayTimer.Start();
        while (i == 0) { };
    }

    private void UpdateBuffer()
    {
        #if DEBUG
        iiii++;
        #endif
        GL.ClearColor(background);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        for (int i = 0; i < RenderObjects.Count; i++) RenderObjects[i].Draw();
        Context.SwapBuffers();
    }
}
#endif