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

namespace SharpQuake
{
	internal static class common
	{
		public static bool IsBigEndian
		{
			get
			{
				return !BitConverter.IsLittleEndian;
			}
		}

		public static string GameDir
		{
			get
			{
				return common._GameDir;
			}
		}

		public static GameKind GameKind
		{
			get
			{
				return common._GameKind;
			}
		}

		public static int Argc
		{
			get
			{
				return common._Argv.Length;
			}
		}

		public static string[] Args
		{
			get
			{
				return common._Argv;
			}
			set
			{
				common._Argv = new string[value.Length];
				value.CopyTo(common._Argv, 0);
				common._Args = string.Join(" ", value);
			}
		}

		public static string Token
		{
			get
			{
				return common._Token;
			}
		}

		public static bool IsRegistered
		{
			get
			{
				return common._Registered.Value != 0f;
			}
		}

		public static string Argv(int index)
		{
			return common._Argv[index];
		}

		public static int CheckParm(string parm)
		{
			for (int i = 1; i < common._Argv.Length; i++)
			{
				if (common._Argv[i].Equals(parm))
				{
					return i;
				}
			}
			return 0;
		}

		public static bool HasParam(string parm)
		{
			return common.CheckParm(parm) > 0;
		}

		public static void Init(string path, string[] argv)
		{
			common._Argv = argv;
			common._Registered = new cvar("registered", "0");
			common._CmdLine = new cvar("cmdline", "0", false, true);
			cmd.Add("path", new xcommand_t(common.Path_f));
			common.InitFileSystem();
			common.CheckRegistered();
		}

		public static void InitArgv(string[] argv)
		{
			common._Args = string.Join(" ", argv);
			common._Argv = new string[argv.Length];
			argv.CopyTo(common._Argv, 0);
			bool flag = false;
			string[] argv2 = common._Argv;
			for (int i = 0; i < argv2.Length; i++)
			{
				if (argv2[i] == "-safe")
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				string[] array = new string[common._Argv.Length + common.safeargvs.Length];
				common._Argv.CopyTo(array, 0);
				common.safeargvs.CopyTo(array, common._Argv.Length);
				common._Argv = array;
			}
			common._GameKind = GameKind.StandardQuake;
			if (common.HasParam("-rogue"))
			{
				common._GameKind = GameKind.Rogue;
			}
			if (common.HasParam("-hipnotic"))
			{
				common._GameKind = GameKind.Hipnotic;
			}
		}

		public static string Parse(string data)
		{
			common._Token = string.Empty;
			if (string.IsNullOrEmpty(data))
			{
				return null;
			}
			int i = 0;
			while (i < data.Length)
			{
				while (i < data.Length && data[i] <= ' ')
				{
					i++;
				}
				if (i >= data.Length)
				{
					return null;
				}
				if (data[i] != '/' || i + 1 >= data.Length || data[i + 1] != '/')
				{
					break;
				}
				while (i < data.Length && data[i] != '\n')
				{
					i++;
				}
			}
			if (i >= data.Length)
			{
				return null;
			}
			int num = i;
			if (data[i] == '"')
			{
				i++;
				num = i;
				while (i < data.Length && data[i] != '"')
				{
					i++;
				}
				if (i == data.Length)
				{
					common._Token = data.Substring(num, i - num);
					return null;
				}
				common._Token = data.Substring(num, i - num);
				if (i + 1 >= data.Length)
				{
					return null;
				}
				return data.Substring(i + 1);
			}
			else
			{
				char c = data[i];
				if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':')
				{
					common._Token = data.Substring(i, 1);
					if (i + 1 >= data.Length)
					{
						return null;
					}
					return data.Substring(i + 1);
				}
				else
				{
					while (i < data.Length)
					{
						c = data[i];
						if (c <= ' ' || c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':')
						{
							i--;
							break;
						}
						i++;
					}
					if (i == data.Length)
					{
						common._Token = data.Substring(num, i - num);
						return null;
					}
					common._Token = data.Substring(num, i - num + 1);
					if (i + 1 >= data.Length)
					{
						return null;
					}
					return data.Substring(i + 1);
				}
			}
		}

		public static byte[] LoadFile(string path)
		{
			DisposableWrapper<BinaryReader> disposableWrapper;
			int num = common.OpenFile(path, out disposableWrapper);
			if (disposableWrapper == null)
			{
				return null;
			}
			byte[] array = new byte[num];
			using (disposableWrapper)
			{
				Drawer.BeginDisc();
				int num2;
				for (int i = num; i > 0; i -= num2)
				{
					num2 = disposableWrapper.Object.Read(array, num - i, i);
					if (num2 == 0)
					{
						sys.Error("COM_LoadFile: reading failed!", Array.Empty<object>());
					}
				}
				Drawer.EndDisc();
			}
			return array;
		}

		public static pack_t LoadPackFile(string packfile)
		{
			FileStream fileStream = sys.FileOpenRead(packfile);
			if (fileStream == null)
			{
				return null;
			}
			dpackheader_t dpackheader_t = sys.ReadStructure<dpackheader_t>(fileStream);
			if (Encoding.ASCII.GetString(dpackheader_t.id) != "PACK")
			{
				sys.Error("{0} is not a packfile", new object[]
				{
					packfile
				});
			}
			dpackheader_t.dirofs = common.LittleLong(dpackheader_t.dirofs);
			dpackheader_t.dirlen = common.LittleLong(dpackheader_t.dirlen);
			int num = dpackheader_t.dirlen / Marshal.SizeOf(typeof(dpackfile_t));
			if (num > 2048)
			{
				sys.Error("{0} has {1} files", new object[]
				{
					packfile,
					num
				});
			}
			fileStream.Seek((long)dpackheader_t.dirofs, SeekOrigin.Begin);
			byte[] array = new byte[dpackheader_t.dirlen];
			if (fileStream.Read(array, 0, array.Length) != array.Length)
			{
				sys.Error("{0} buffering failed!", new object[]
				{
					packfile
				});
			}
			List<dpackfile_t> list = new List<dpackfile_t>(2048);
			GCHandle gchandle = GCHandle.Alloc(array, GCHandleType.Pinned);
			try
			{
				IntPtr ptr = gchandle.AddrOfPinnedObject();
				int i = 0;
				int num2 = Marshal.SizeOf(typeof(dpackfile_t));
				while (i < dpackheader_t.dirlen)
				{
					dpackfile_t item = (dpackfile_t)Marshal.PtrToStructure(ptr, typeof(dpackfile_t));
					list.Add(item);
					ptr = new IntPtr(ptr.ToInt64() + (long)num2);
					i += num2;
				}
				if (num != list.Count)
				{
					sys.Error("{0} directory reading failed!", new object[]
					{
						packfile
					});
				}
			}
			finally
			{
				gchandle.Free();
			}
			packfile_t[] array2 = new packfile_t[num];
			for (int j = 0; j < num; j++)
			{
				array2[j] = new packfile_t
				{
					name = common.GetString(list[j].name),
					filepos = common.LittleLong(list[j].filepos),
					filelen = common.LittleLong(list[j].filelen)
				};
			}
			pack_t result = new pack_t(packfile, new BinaryReader(fileStream, Encoding.ASCII), array2);
			Con.Print("Added packfile {0} ({1} files)\n", new object[]
			{
				packfile,
				num
			});
			return result;
		}

		public static int FOpenFile(string filename, out DisposableWrapper<BinaryReader> file)
		{
			return common.FindFile(filename, out file, true);
		}

		public static int atoi(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return 0;
			}
			int num = 1;
			int num2 = 0;
			int num3 = 0;
			if (s.StartsWith("-"))
			{
				num = -1;
				num3++;
			}
			int num4 = -1;
			if (s.Length > 2)
			{
				num4 = s.IndexOf("0x", num3, 2);
				if (num4 == -1)
				{
					num4 = s.IndexOf("0X", num3, 2);
				}
			}
			if (num4 == num3)
			{
				int.TryParse(s.Substring(num3 + 2), NumberStyles.HexNumber, null, out num2);
			}
			else
			{
				num4 = s.IndexOf('\'', num3, 1);
				if (num4 != -1)
				{
					num2 = (int)((byte)s[num4 + 1]);
				}
				else
				{
					int.TryParse(s.Substring(num3), out num2);
				}
			}
			return num * num2;
		}

		public static float atof(string s)
		{
			float result;
			float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out result);
			return result;
		}

		public static bool SameText(string a, string b)
		{
			return string.Compare(a, b, true) == 0;
		}

		public static bool SameText(string a, string b, int count)
		{
			return string.Compare(a, 0, b, 0, count, true) == 0;
		}

		public static short BigShort(short l)
		{
			return common._Converter.BigShort(l);
		}

		public static short LittleShort(short l)
		{
			return common._Converter.LittleShort(l);
		}

		public static int BigLong(int l)
		{
			return common._Converter.BigLong(l);
		}

		public static int LittleLong(int l)
		{
			return common._Converter.LittleLong(l);
		}

		public static float BigFloat(float l)
		{
			return common._Converter.BigFloat(l);
		}

		public static float LittleFloat(float l)
		{
			return common._Converter.LittleFloat(l);
		}

		public static Vector3 LittleVector(Vector3 src)
		{
			return new Vector3(common._Converter.LittleFloat(src.X), common._Converter.LittleFloat(src.Y), common._Converter.LittleFloat(src.Z));
		}

		public static Vector3 LittleVector3(float[] src)
		{
			return new Vector3(common._Converter.LittleFloat(src[0]), common._Converter.LittleFloat(src[1]), common._Converter.LittleFloat(src[2]));
		}

		public static Vector4 LittleVector4(float[] src, int offset)
		{
			return new Vector4(common._Converter.LittleFloat(src[offset]), common._Converter.LittleFloat(src[offset + 1]), common._Converter.LittleFloat(src[offset + 2]), common._Converter.LittleFloat(src[offset + 3]));
		}

		public static void FillArray<T>(T[] dest, T value)
		{
			int num = Marshal.SizeOf(typeof(T));
			int num2 = Math.Min(dest.Length, 4096 / num);
			for (int i = 0; i < num2; i++)
			{
				dest[i] = value;
			}
			int num3 = num2 * num;
			int num4 = num3;
			int num5 = Buffer.ByteLength(dest);
			for (;;)
			{
				int num6 = num5 - num4;
				if (num6 < num3)
				{
					num3 = num6;
				}
				if (num3 <= 0)
				{
					break;
				}
				Buffer.BlockCopy(dest, 0, dest, num4, num3);
				num4 += num3;
			}
		}

		public static void ZeroArray<T>(T[] dest, int startIndex, int length)
		{
			int num = Marshal.SizeOf(typeof(T));
			int num2 = startIndex * num;
			int num3 = dest.Length * num - num2;
			for (;;)
			{
				int num4 = num3 - num2;
				if (num4 > common.ZeroBytes.Length)
				{
					num4 = common.ZeroBytes.Length;
				}
				if (num4 <= 0)
				{
					break;
				}
				Buffer.BlockCopy(common.ZeroBytes, 0, dest, num2, num4);
				num2 += num4;
			}
		}

		public static string Copy(string src, int maxLength)
		{
			if (src == null)
			{
				return null;
			}
			if (src.Length <= maxLength)
			{
				return src;
			}
			return src.Substring(1, maxLength);
		}

		public static void Copy(float[] src, out Vector3 dest)
		{
			dest.X = src[0];
			dest.Y = src[1];
			dest.Z = src[2];
		}

		public static void Copy(ref Vector3 src, float[] dest)
		{
			dest[0] = src.X;
			dest[1] = src.Y;
			dest[2] = src.Z;
		}

		public static string GetString(byte[] src)
		{
			int num = 0;
			while (num < src.Length && src[num] != 0)
			{
				num++;
			}
			if (num <= 0)
			{
				return string.Empty;
			}
			return Encoding.ASCII.GetString(src, 0, num);
		}

		public static Vector3 ToVector(ref v3f v)
		{
			return new Vector3(v.x, v.y, v.z);
		}

		public static void WriteInt(byte[] dest, int offset, int value)
		{
			Union4b empty = Union4b.Empty;
			empty.i0 = value;
			dest[offset] = empty.b0;
			dest[offset + 1] = empty.b1;
			dest[offset + 2] = empty.b2;
			dest[offset + 3] = empty.b3;
		}

		private static void CopyFile(string netpath, string cachepath)
		{
			using (Stream stream = sys.FileOpenRead(netpath))
			{
				using (Stream stream2 = sys.FileOpenWrite(cachepath, false))
				{
					if (stream == null)
					{
						sys.Error("CopyFile: cannot open file {0}\n", new object[]
						{
							netpath
						});
					}
					long num = stream.Length;
					string directoryName = Path.GetDirectoryName(cachepath);
					if (!Directory.Exists(directoryName))
					{
						Directory.CreateDirectory(directoryName);
					}
					byte[] array = new byte[4096];
					while (num > 0L)
					{
						int num2 = array.Length;
						if (num < (long)num2)
						{
							num2 = (int)num;
						}
						stream.Read(array, 0, num2);
						stream2.Write(array, 0, num2);
						num -= (long)num2;
					}
				}
			}
		}

		private static int FindFile(string filename, out DisposableWrapper<BinaryReader> file, bool duplicateStream)
		{
			file = null;
			string text = string.Empty;
			foreach (searchpath_t searchpath_t in common._SearchPaths)
			{
				if (searchpath_t.pack != null)
				{
					pack_t pack = searchpath_t.pack;
					foreach (packfile_t packfile_t in pack.files)
					{
						if (packfile_t.name.Equals(filename))
						{
							Con.DPrint("PackFile: {0} : {1}\n", new object[]
							{
								searchpath_t.pack.filename,
								filename
							});
							if (duplicateStream)
							{
								FileStream input = new FileStream(((FileStream)pack.stream.BaseStream).Name, FileMode.Open, FileAccess.Read, FileShare.Read);
								file = new DisposableWrapper<BinaryReader>(new BinaryReader(input, Encoding.ASCII), true);
							}
							else
							{
								file = new DisposableWrapper<BinaryReader>(pack.stream, false);
							}
							file.Object.BaseStream.Seek((long)packfile_t.filepos, SeekOrigin.Begin);
							return packfile_t.filelen;
						}
					}
				}
				else if (common._StaticRegistered || filename.IndexOfAny(common._Slashes) == -1)
				{
					string text2 = searchpath_t.filename + "/" + filename;
					DateTime fileTime = sys.GetFileTime(text2);
					if (!(fileTime == DateTime.MinValue))
					{
						if (!string.IsNullOrEmpty(common._CacheDir))
						{
							if (sys.IsWindows)
							{
								if (text2.Length < 2 || text2[1] != ':')
								{
									text = common._CacheDir + text2;
								}
								else
								{
									text = common._CacheDir + text2.Substring(2);
								}
							}
							else
							{
								text = common._CacheDir + text2;
							}
							if (sys.GetFileTime(text) < fileTime)
							{
								common.CopyFile(text2, text);
							}
							text2 = text;
						}
						Con.DPrint("FindFile: {0}\n", new object[]
						{
							text2
						});
						FileStream fileStream = sys.FileOpenRead(text2);
						if (fileStream == null)
						{
							file = null;
							return -1;
						}
						file = new DisposableWrapper<BinaryReader>(new BinaryReader(fileStream, Encoding.ASCII), true);
						return (int)fileStream.Length;
					}
				}
			}
			Con.DPrint("FindFile: can't find {0}\n", new object[]
			{
				filename
			});
			return -1;
		}

		private static int OpenFile(string filename, out DisposableWrapper<BinaryReader> file)
		{
			return common.FindFile(filename, out file, false);
		}

		private static void Path_f()
		{
			Con.Print("Current search path:\n", Array.Empty<object>());
			foreach (searchpath_t searchpath_t in common._SearchPaths)
			{
				if (searchpath_t.pack != null)
				{
					Con.Print("{0} ({1} files)\n", new object[]
					{
						searchpath_t.pack.filename,
						searchpath_t.pack.files.Length
					});
				}
				else
				{
					Con.Print("{0}\n", new object[]
					{
						searchpath_t.filename
					});
				}
			}
		}

		private static void CheckRegistered()
		{
			common._StaticRegistered = false;
			byte[] array = common.LoadFile("gfx/pop.lmp");
			if (array == null || array.Length < 256)
			{
				Con.Print("Playing shareware version.\n", Array.Empty<object>());
				if (common._IsModified)
				{
					sys.Error("You must have the registered version to use modified games", Array.Empty<object>());
				}
				return;
			}
			ushort[] array2 = new ushort[array.Length / 2];
			Buffer.BlockCopy(array, 0, array2, 0, array.Length);
			for (int i = 0; i < 128; i++)
			{
				if (common._Pop[i] != (ushort)common._Converter.BigShort((short)array2[i]))
				{
					sys.Error("Corrupted data file.", Array.Empty<object>());
				}
			}
			cvar.Set("cmdline", common._Args);
			cvar.Set("registered", "1");
			common._StaticRegistered = true;
			Con.Print("Playing registered version.\n", Array.Empty<object>());
		}

		private static void InitFileSystem()
		{
			string text = string.Empty;
			int num = common.CheckParm("-basedir");
			if (num > 0 && num < common._Argv.Length - 1)
			{
				text = common._Argv[num + 1];
			}
			else
			{
				text = host.Params.basedir;
				qparam.globalbasedir = text;
			}
			if (!string.IsNullOrEmpty(text))
			{
				text.TrimEnd(new char[]
				{
					'\\',
					'/'
				});
			}
			num = common.CheckParm("-cachedir");
			if (num > 0 && num < common._Argv.Length - 1)
			{
				if (common._Argv[num + 1][0] == '-')
				{
					common._CacheDir = string.Empty;
				}
				else
				{
					common._CacheDir = common._Argv[num + 1];
				}
			}
			else if (!string.IsNullOrEmpty(host.Params.cachedir))
			{
				common._CacheDir = host.Params.cachedir;
			}
			else
			{
				common._CacheDir = string.Empty;
			}
			common.AddGameDirectory(text + "/Id1");
			qparam.globalgameid = "Id1";
			if (common.HasParam("-rogue"))
			{
				common.AddGameDirectory(text + "/rogue");
				qparam.globalgameid = "rogue";
			}
			if (common.HasParam("-hipnotic"))
			{
				common.AddGameDirectory(text + "/hipnotic");
				qparam.globalgameid = "hipnotic";
			}
			num = common.CheckParm("-game");
			if (num > 0 && num < common._Argv.Length - 1)
			{
				common._IsModified = true;
				common.AddGameDirectory(text + "/" + common._Argv[num + 1]);
			}
			num = common.CheckParm("-path");
			if (num > 0)
			{
				common._IsModified = true;
				common._SearchPaths.Clear();
				while (++num < common._Argv.Length && !string.IsNullOrEmpty(common._Argv[num]) && common._Argv[num][0] != '+' && common._Argv[num][0] != '-')
				{
					common._SearchPaths.Insert(0, new searchpath_t(common._Argv[num]));
				}
			}
		}

		private static void AddGameDirectory(string dir)
		{
			common._GameDir = dir;
			common._SearchPaths.Insert(0, new searchpath_t(dir));
			int num = 0;
			for (;;)
			{
				pack_t pack_t = common.LoadPackFile(string.Format("{0}/PAK{1}.PAK", dir, num));
				if (pack_t == null)
				{
					break;
				}
				common._SearchPaths.Insert(0, new searchpath_t(pack_t));
				num++;
			}
		}

		static common()
		{
			if (BitConverter.IsLittleEndian)
			{
				common._Converter = new LittleEndianConverter();
			}
			else
			{
				common._Converter = new BigEndianConverter();
			}
			common._SearchPaths = new List<searchpath_t>();
		}

		public const int MAX_FILES_IN_PACK = 2048;

		public const int PAK0_COUNT = 339;

		public const int PAK0_CRC = 32981;

		public static Vector3 ZeroVector = Vector3.Zero;

		public static v3f ZeroVector3f = default(v3f);

		private static readonly byte[] ZeroBytes = new byte[4096];

		private static ushort[] _Pop = new ushort[]
		{
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			26112,
			0,
			0,
			0,
			26112,
			0,
			0,
			102,
			0,
			0,
			0,
			0,
			103,
			0,
			0,
			26213,
			0,
			0,
			0,
			0,
			101,
			26112,
			99,
			25953,
			0,
			0,
			0,
			0,
			97,
			25955,
			100,
			25953,
			0,
			0,
			0,
			0,
			97,
			25956,
			100,
			25956,
			0,
			25705,
			26985,
			25600,
			100,
			25956,
			99,
			25960,
			25088,
			100,
			26724,
			0,
			25192,
			25955,
			0,
			25959,
			26979,
			100,
			26468,
			99,
			26983,
			25856,
			0,
			25190,
			26473,
			27240,
			26472,
			27241,
			26470,
			25088,
			0,
			98,
			25958,
			26214,
			26214,
			26214,
			25954,
			0,
			0,
			0,
			98,
			25444,
			26212,
			25442,
			0,
			0,
			0,
			0,
			0,
			98,
			26210,
			0,
			0,
			0,
			0,
			0,
			0,
			97,
			26209,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			25856,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			25600,
			0,
			0,
			0
		};

		private static string[] safeargvs = new string[]
		{
			"-stdvid",
			"-nolan",
			"-nosound",
			"-nocdaudio",
			"-nojoy",
			"-nomouse",
			"-dibonly"
		};

		private static IByteOrderConverter _Converter;

		private static cvar _Registered;

		private static cvar _CmdLine;

		private static string _CacheDir;

		private static string _GameDir;

		private static List<searchpath_t> _SearchPaths;

		private static string[] _Argv;

		private static string _Args;

		private static GameKind _GameKind;

		private static bool _IsModified;

		private static bool _StaticRegistered;

		private static char[] _Slashes = new char[]
		{
			'/',
			'\\'
		};

		private static string _Token;
	}
}
