using System;
using System.IO;
using System.Text;

namespace SharpQuake
{
	internal static class Con
	{
		public static bool IsInitialized
		{
			get
			{
				return Con._IsInitialized;
			}
		}

		public static bool ForcedUp
		{
			get
			{
				return Con._ForcedUp;
			}
			set
			{
				Con._ForcedUp = value;
			}
		}

		public static int NotifyLines
		{
			get
			{
				return Con._NotifyLines;
			}
			set
			{
				Con._NotifyLines = value;
			}
		}

		public static int TotalLines
		{
			get
			{
				return Con._TotalLines;
			}
		}

		public static void CheckResize()
		{
			int num = (Scr.vid.width >> 3) - 2;
			if (num == Con._LineWidth)
			{
				return;
			}
			if (num < 1)
			{
				num = 38;
				Con._LineWidth = num;
				Con._TotalLines = 16384 / Con._LineWidth;
				common.FillArray<char>(Con._Text, ' ');
			}
			else
			{
				int lineWidth = Con._LineWidth;
				Con._LineWidth = num;
				int totalLines = Con._TotalLines;
				Con._TotalLines = 16384 / Con._LineWidth;
				int num2 = totalLines;
				if (Con._TotalLines < num2)
				{
					num2 = Con._TotalLines;
				}
				int num3 = lineWidth;
				if (Con._LineWidth < num3)
				{
					num3 = Con._LineWidth;
				}
				char[] text = Con._Text;
				Con._Text = new char[16384];
				common.FillArray<char>(Con._Text, ' ');
				for (int i = 0; i < num2; i++)
				{
					for (int j = 0; j < num3; j++)
					{
						Con._Text[(Con._TotalLines - 1 - i) * Con._LineWidth + j] = text[(Con._Current - i + totalLines) % totalLines * lineWidth + j];
					}
				}
				Con.ClearNotify();
			}
			Con.BackScroll = 0;
			Con._Current = Con._TotalLines - 1;
		}

		public static void Init()
		{
			Con._DebugLog = (common.CheckParm("-condebug") > 0);
			if (Con._DebugLog)
			{
				string path = Path.Combine(common.GameDir, "qconsole.log");
				if (File.Exists(path))
				{
					File.Delete(path);
				}
				Con._Log = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
			}
			Con._LineWidth = -1;
			Con.CheckResize();
			Con.Print("Console initialized.\n");
			if (Con._NotifyTime == null)
			{
				Con._NotifyTime = new cvar("con_notifytime", "3");
			}
			cmd.Add("toggleconsole", new xcommand_t(Con.ToggleConsole_f));
			cmd.Add("messagemode", new xcommand_t(Con.MessageMode_f));
			cmd.Add("messagemode2", new xcommand_t(Con.MessageMode2_f));
			cmd.Add("clear", new xcommand_t(Con.Clear_f));
			Con._IsInitialized = true;
		}

		public static void Draw(int lines, bool drawinput)
		{
			if (lines <= 0)
			{
				return;
			}
			Drawer.DrawConsoleBackground(lines);
			Con._VisLines = lines;
			int num = lines - 16 >> 3;
			int num2 = lines - 16 - (num << 3);
			int i = Con._Current - num + 1;
			while (i <= Con._Current)
			{
				int num3 = i - Con.BackScroll;
				if (num3 < 0)
				{
					num3 = 0;
				}
				int num4 = num3 % Con._TotalLines * Con._LineWidth;
				for (int j = 0; j < Con._LineWidth; j++)
				{
					Drawer.DrawCharacter(j + 1 << 3, num2, (int)Con._Text[num4 + j]);
				}
				i++;
				num2 += 8;
			}
			if (drawinput)
			{
				Con.DrawInput();
			}
		}

		public static void Print(string fmt, params object[] args)
		{
			string text = (args.Length != 0) ? string.Format(fmt, args) : fmt;
			Console.WriteLine(text);
			if (Con._DebugLog)
			{
				Con.DebugLog(text);
			}
			if (!Con._IsInitialized)
			{
				return;
			}
			if (client.cls.state == cactive_t.ca_dedicated)
			{
				return;
			}
			Con.Print(text);
			if (client.cls.signon != 4 && !Scr.IsDisabledForLoading)
			{
				Scr.UpdateScreen();
			}
		}

		public static void Shutdown()
		{
			if (Con._Log != null)
			{
				Con._Log.Flush();
				Con._Log.Dispose();
				Con._Log = null;
			}
		}

		public static void DPrint(string fmt, params object[] args)
		{
			if (host.IsDeveloper)
			{
				Con.Print(fmt, args);
			}
		}

		public static void SafePrint(string fmt, params object[] args)
		{
			bool isDisabledForLoading = Scr.IsDisabledForLoading;
			Scr.IsDisabledForLoading = true;
			Con.Print(fmt, args);
			Scr.IsDisabledForLoading = isDisabledForLoading;
		}

		public static void DrawNotify()
		{
			int num = 0;
			for (int i = Con._Current - 4 + 1; i <= Con._Current; i++)
			{
				if (i >= 0)
				{
					double num2 = Con._Times[i % 4];
					if (num2 != 0.0)
					{
						num2 = host.RealTime - num2;
						if (num2 <= (double)Con._NotifyTime.Value)
						{
							int num3 = i % Con._TotalLines * Con._LineWidth;
							Scr.ClearNotify = 0;
							Scr.CopyTop = true;
							for (int j = 0; j < Con._LineWidth; j++)
							{
								Drawer.DrawCharacter(j + 1 << 3, num, (int)Con._Text[num3 + j]);
							}
							num += 8;
						}
					}
				}
			}
			if (Key.Destination == keydest_t.key_message)
			{
				Scr.ClearNotify = 0;
				Scr.CopyTop = true;
				int k = 0;
				Drawer.DrawString(8, num, "say:");
				string chatBuffer = Key.ChatBuffer;
				while (k < chatBuffer.Length)
				{
					Drawer.DrawCharacter(k + 5 << 3, num, (int)chatBuffer[k]);
					k++;
				}
				Drawer.DrawCharacter(k + 5 << 3, num, 10 + ((int)(host.RealTime * (double)Con._CursorSpeed) & 1));
				num += 8;
			}
			if (num > Con._NotifyLines)
			{
				Con._NotifyLines = num;
			}
		}

		public static void ClearNotify()
		{
			for (int i = 0; i < 4; i++)
			{
				Con._Times[i] = 0.0;
			}
		}

		public static void ToggleConsole_f()
		{
			if (Key.Destination == keydest_t.key_console)
			{
				if (client.cls.state == cactive_t.ca_connected)
				{
					Key.Destination = keydest_t.key_game;
					Key.Lines[Key.EditLine][1] = '\0';
					Key.LinePos = 1;
				}
				else
				{
					MenuBase.MainMenu.Show();
				}
			}
			else
			{
				Key.Destination = keydest_t.key_console;
			}
			Scr.EndLoadingPlaque();
			Array.Clear(Con._Times, 0, Con._Times.Length);
		}

		private static void DebugLog(string msg)
		{
			if (Con._Log != null)
			{
				byte[] bytes = Encoding.UTF8.GetBytes(msg);
				Con._Log.Write(bytes, 0, bytes.Length);
			}
		}

		private static void Print(string txt)
		{
			if (string.IsNullOrEmpty(txt))
			{
				return;
			}
			int i = 0;
			Con.BackScroll = 0;
			int num;
			if (txt.StartsWith('\u0001'.ToString()))
			{
				num = 128;
				snd.LocalSound("misc/talk.wav");
				i++;
			}
			else if (txt.StartsWith('\u0002'.ToString()))
			{
				num = 128;
				i++;
			}
			else
			{
				num = 0;
			}
			while (i < txt.Length)
			{
				char c = txt[i];
				int num2 = 0;
				while (num2 < Con._LineWidth && i + num2 < txt.Length && txt[i + num2] > ' ')
				{
					num2++;
				}
				if (num2 != Con._LineWidth && Con._X + num2 > Con._LineWidth)
				{
					Con._X = 0;
				}
				i++;
				if (Con._CR != 0)
				{
					Con._Current--;
					Con._CR = 0;
				}
				if (Con._X == 0)
				{
					Con.LineFeed();
					if (Con._Current >= 0)
					{
						Con._Times[Con._Current % 4] = host.RealTime;
					}
				}
				if (c != '\n')
				{
					if (c != '\r')
					{
						int num3 = Con._Current % Con._TotalLines;
						Con._Text[num3 * Con._LineWidth + Con._X] = (char)((int)c | num);
						Con._X++;
						if (Con._X >= Con._LineWidth)
						{
							Con._X = 0;
						}
					}
					else
					{
						Con._X = 0;
						Con._CR = 1;
					}
				}
				else
				{
					Con._X = 0;
				}
			}
		}

		private static void Clear_f()
		{
			common.FillArray<char>(Con._Text, ' ');
		}

		private static void MessageMode_f()
		{
			Key.Destination = keydest_t.key_message;
			Key.TeamMessage = false;
		}

		private static void MessageMode2_f()
		{
			Key.Destination = keydest_t.key_message;
			Key.TeamMessage = true;
		}

		private static void LineFeed()
		{
			Con._X = 0;
			Con._Current++;
			for (int i = 0; i < Con._LineWidth; i++)
			{
				Con._Text[Con._Current % Con._TotalLines * Con._LineWidth + i] = ' ';
			}
		}

		private static void DrawInput()
		{
			if (Key.Destination != keydest_t.key_console && !Con._ForcedUp)
			{
				return;
			}
			Key.Lines[Key.EditLine][Key.LinePos] = (char)(10 + ((int)(host.RealTime * (double)Con._CursorSpeed) & 1));
			for (int i = Key.LinePos + 1; i < Con._LineWidth; i++)
			{
				Key.Lines[Key.EditLine][i] = ' ';
			}
			int num = 0;
			if (Key.LinePos >= Con._LineWidth)
			{
				num = 1 + Key.LinePos - Con._LineWidth;
			}
			int visLines = Con._VisLines;
			for (int j = 0; j < Con._LineWidth; j++)
			{
				Drawer.DrawCharacter(j + 1 << 3, Con._VisLines - 16, (int)Key.Lines[Key.EditLine][num + j]);
			}
			Key.Lines[Key.EditLine][Key.LinePos] = '\0';
		}

		public static int BackScroll;

		private const string LOG_FILE_NAME = "qconsole.log";

		private const int CON_TEXTSIZE = 16384;

		private const int NUM_CON_TIMES = 4;

		private static char[] _Text = new char[16384];

		private static int _VisLines;

		private static int _TotalLines;

		private static int _Current;

		private static int _X;

		private static int _CR;

		private static double[] _Times = new double[4];

		private static int _LineWidth;

		private static bool _DebugLog;

		private static bool _IsInitialized;

		private static bool _ForcedUp;

		private static int _NotifyLines;

		private static cvar _NotifyTime;

		private static float _CursorSpeed = 4f;

		private static FileStream _Log;
	}
}
