using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using SDL2;

namespace SharpQuake
{
	public class mainwindow : GameWindow
	{
		public static mainwindow Instance
		{
			get
			{
				return (mainwindow)mainwindow._Instance.Target;
			}
		}

		public static DisplayDevice DisplayDevice
		{
			get
			{
				return mainwindow._DisplayDevice;
			}
			set
			{
				mainwindow._DisplayDevice = value;
			}
		}

		public static bool IsFullscreen
		{
			get
			{
				return mainwindow.Instance.WindowState == WindowState.Fullscreen;
			}
		}

		private static string DumpFilePath
		{
			get
			{
				return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.txt");
			}
		}

		protected override void OnFocusedChanged(EventArgs e)
		{
			base.OnFocusedChanged(e);
			if (base.Focused)
			{
				snd.UnblockSound();
				return;
			}
			snd.BlockSound();
		}

		protected override void OnClosing(CancelEventArgs e)
		{
			base.OnClosing(e);
		}

		protected override void OnUpdateFrame(FrameEventArgs e)
		{
			try
			{
				if (this.WindowState == WindowState.Minimized || Scr.BlockDrawing)
				{
					Scr.SkipUpdate = true;
				}
				this._Swatch.Stop();
				double totalSeconds = this._Swatch.Elapsed.TotalSeconds;
				this._Swatch.Reset();
				this._Swatch.Start();
				host.Frame(totalSeconds);
			}
			catch (EndGameException)
			{
			}
		}

		private static mainwindow CreateInstance(Size size, GraphicsMode mode, bool fullScreen)
		{
			if (mainwindow._Instance != null)
			{
				throw new Exception("Game instance is already created!");
			}
			return new mainwindow(size, mode, fullScreen);
		}

		private static void DumpError(Exception ex)
		{
			try
			{
				using (StreamWriter streamWriter = new StreamWriter(new FileStream(mainwindow.DumpFilePath, FileMode.Append, FileAccess.Write, FileShare.Read)))
				{
					streamWriter.WriteLine();
					for (Exception ex2 = ex; ex2 != null; ex2 = ex2.InnerException)
					{
						streamWriter.WriteLine("[" + DateTime.Now.ToString() + "] Unhandled exception:");
						streamWriter.WriteLine(ex2.Message);
						streamWriter.WriteLine();
						streamWriter.WriteLine("Stack trace:");
						streamWriter.WriteLine(ex2.StackTrace);
						streamWriter.WriteLine();
					}
				}
			}
			catch (Exception)
			{
			}
		}

		private static void SafeShutdown()
		{
			try
			{
				host.Shutdown();
			}
			catch (Exception ex)
			{
				mainwindow.DumpError(ex);
				if (Debugger.IsAttached)
				{
					throw new Exception("Exception in SafeShutdown()!", ex);
				}
			}
		}

		private static void HandleException(Exception ex)
		{
			mainwindow.DumpError(ex);
			if (Debugger.IsAttached)
			{
				throw new Exception("Fatal error!", ex);
			}
			mainwindow.Instance.CursorVisible = true;
			SDL.SDL_ShowSimpleMessageBox(SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR, "Fatal error!", ex.Message, IntPtr.Zero);
			mainwindow.SafeShutdown();
		}

		[STAThread]
		private static int Main(string[] args)
		{
			Toolkit.Init(new ToolkitOptions
			{
				Backend = PlatformBackend.PreferNative,
				EnableHighResolution = true
			});
			try
			{
				mainwindow._DisplayDevice = DisplayDevice.Default;
				if (File.Exists(mainwindow.DumpFilePath))
				{
					File.Delete(mainwindow.DumpFilePath);
				}
				quakeparms_t quakeparms_t = new quakeparms_t();
				quakeparms_t.basedir = AppDomain.CurrentDomain.BaseDirectory;
				string[] array = new string[args.Length + 1];
				array[0] = string.Empty;
				args.CopyTo(array, 1);
				common.InitArgv(array);
				quakeparms_t.argv = new string[common.Argc];
				common.Args.CopyTo(quakeparms_t.argv, 0);
				if (common.HasParam("-dedicated"))
				{
					throw new QuakeException("Dedicated server mode not supported!");
				}
				Size size = new Size(1280, 720);
				GraphicsMode mode = new GraphicsMode();
				using (mainwindow mainwindow = mainwindow.CreateInstance(size, mode, false))
				{
					Con.DPrint("Host.Init\n", Array.Empty<object>());
					host.Init(quakeparms_t);
					mainwindow.Instance.CursorVisible = false;
					mainwindow.Run();
				}
				host.Shutdown();
			}
			catch (QuakeSystemError ex)
			{
				mainwindow.HandleException(ex);
			}
			catch (Exception ex2)
			{
				mainwindow.HandleException(ex2);
			}
			return 0;
		}

		private void Mouse_WheelChanged(object sender, MouseWheelEventArgs e)
		{
			if (e.Delta > 0)
			{
				Key.Event(239, true);
				Key.Event(239, false);
				return;
			}
			Key.Event(240, true);
			Key.Event(240, false);
		}

		private void Mouse_ButtonEvent(object sender, MouseButtonEventArgs e)
		{
			this._MouseBtnState = 0;
			if (e.Button == MouseButton.Left && e.IsPressed)
			{
				this._MouseBtnState |= 1;
			}
			if (e.Button == MouseButton.Right && e.IsPressed)
			{
				this._MouseBtnState |= 2;
			}
			if (e.Button == MouseButton.Middle && e.IsPressed)
			{
				this._MouseBtnState |= 4;
			}
			input.MouseEvent(this._MouseBtnState);
		}

		private void Mouse_Move(object sender, MouseMoveEventArgs e)
		{
			input.MouseEvent(this._MouseBtnState);
		}

		private int MapKey(Key srcKey)
		{
			int num = (int)(srcKey & (Key)255);
			if (num >= mainwindow._KeyTable.Length)
			{
				return 0;
			}
			if (mainwindow._KeyTable[num] == 0)
			{
				Con.DPrint("key 0x{0:X} has no translation\n", new object[]
				{
					num
				});
			}
			return (int)mainwindow._KeyTable[num];
		}

		private void Keyboard_KeyUp(object sender, KeyboardKeyEventArgs e)
		{
			Key.Event(this.MapKey(e.Key), false);
		}

		private void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e)
		{
			Key.Event(this.MapKey(e.Key), true);
		}

		private mainwindow(Size size, GraphicsMode mode, bool fullScreen) : base(size.Width, size.Height, mode, "SharpQuake", fullScreen ? GameWindowFlags.Fullscreen : GameWindowFlags.Default)
		{
			mainwindow._Instance = new WeakReference(this);
			this._Swatch = new Stopwatch();
			base.VSync = VSyncMode.On;
			base.Icon = Icon.ExtractAssociatedIcon(AppDomain.CurrentDomain.FriendlyName);
			base.KeyDown += this.Keyboard_KeyDown;
			base.KeyUp += this.Keyboard_KeyUp;
			base.MouseMove += this.Mouse_Move;
			base.MouseDown += this.Mouse_ButtonEvent;
			base.MouseUp += this.Mouse_ButtonEvent;
			base.MouseWheel += this.Mouse_WheelChanged;
		}

		public bool ConfirmExit = true;

		private static byte[] _KeyTable = new byte[]
		{
			0,
			134,
			134,
			133,
			133,
			132,
			132,
			0,
			0,
			0,
			135,
			136,
			137,
			138,
			139,
			140,
			141,
			142,
			143,
			144,
			145,
			146,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			128,
			129,
			130,
			131,
			13,
			27,
			32,
			9,
			127,
			147,
			148,
			150,
			149,
			151,
			152,
			0,
			0,
			0,
			byte.MaxValue,
			0,
			0,
			0,
			147,
			152,
			129,
			149,
			130,
			0,
			131,
			151,
			128,
			150,
			47,
			42,
			45,
			43,
			46,
			13,
			97,
			98,
			99,
			100,
			101,
			102,
			103,
			104,
			105,
			106,
			107,
			108,
			109,
			110,
			111,
			112,
			113,
			114,
			115,
			116,
			117,
			118,
			119,
			120,
			121,
			122,
			48,
			49,
			50,
			51,
			52,
			53,
			54,
			55,
			56,
			57,
			96,
			45,
			43,
			91,
			93,
			59,
			39,
			44,
			46,
			47,
			92
		};

		private static WeakReference _Instance;

		private static DisplayDevice _DisplayDevice;

		private int _MouseBtnState;

		private Stopwatch _Swatch;
	}
}
