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

namespace LitJson;

internal class Lexer
{
	private delegate bool StateHandler(FsmContext ctx);

	private static int[] fsm_return_table;

	private static StateHandler[] fsm_handler_table;

	private bool allow_comments;

	private bool allow_single_quoted_strings;

	private bool end_of_input;

	private FsmContext fsm_context;

	private int input_buffer;

	private int input_char;

	private TextReader reader;

	private int state;

	private StringBuilder string_buffer;

	private string string_value;

	private int token;

	private int unichar;

	public bool AllowComments
	{
		get
		{
			return allow_comments;
		}
		set
		{
			allow_comments = value;
		}
	}

	public bool AllowSingleQuotedStrings
	{
		get
		{
			return allow_single_quoted_strings;
		}
		set
		{
			allow_single_quoted_strings = value;
		}
	}

	public bool EndOfInput => end_of_input;

	public int Token => token;

	public string StringValue => string_value;

	static Lexer()
	{
		PopulateFsmTables();
	}

	public Lexer(TextReader reader)
	{
		allow_comments = true;
		allow_single_quoted_strings = true;
		input_buffer = 0;
		string_buffer = new StringBuilder(128);
		state = 1;
		end_of_input = false;
		this.reader = reader;
		fsm_context = new FsmContext();
		fsm_context.L = this;
	}

	private static int HexValue(int digit)
	{
		switch (digit)
		{
		case 65:
		case 97:
			return 10;
		case 66:
		case 98:
			return 11;
		case 67:
		case 99:
			return 12;
		case 68:
		case 100:
			return 13;
		case 69:
		case 101:
			return 14;
		case 70:
		case 102:
			return 15;
		default:
			return digit - 48;
		}
	}

	private static void PopulateFsmTables()
	{
		fsm_handler_table = new StateHandler[28]
		{
			State1, State2, State3, State4, State5, State6, State7, State8, State9, State10,
			State11, State12, State13, State14, State15, State16, State17, State18, State19, State20,
			State21, State22, State23, State24, State25, State26, State27, State28
		};
		fsm_return_table = new int[28]
		{
			65542, 0, 65537, 65537, 0, 65537, 0, 65537, 0, 0,
			65538, 0, 0, 0, 65539, 0, 0, 65540, 65541, 65542,
			0, 0, 65541, 65542, 0, 0, 0, 0
		};
	}

	private static char ProcessEscChar(int esc_char)
	{
		switch (esc_char)
		{
		case 34:
		case 39:
		case 47:
		case 92:
			return Convert.ToChar(esc_char);
		case 110:
			return '\n';
		case 116:
			return '\t';
		case 114:
			return '\r';
		case 98:
			return '\b';
		case 102:
			return '\f';
		default:
			return '?';
		}
	}

	private static bool State1(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13))
			{
				continue;
			}
			if (ctx.L.input_char >= 49 && ctx.L.input_char <= 57)
			{
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 3;
				return true;
			}
			switch (ctx.L.input_char)
			{
			case 34:
				ctx.NextState = 19;
				ctx.Return = true;
				return true;
			case 44:
			case 58:
			case 91:
			case 93:
			case 123:
			case 125:
				ctx.NextState = 1;
				ctx.Return = true;
				return true;
			case 45:
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 2;
				return true;
			case 48:
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 4;
				return true;
			case 102:
				ctx.NextState = 12;
				return true;
			case 110:
				ctx.NextState = 16;
				return true;
			case 116:
				ctx.NextState = 9;
				return true;
			case 39:
				if (!ctx.L.allow_single_quoted_strings)
				{
					return false;
				}
				ctx.L.input_char = 34;
				ctx.NextState = 23;
				ctx.Return = true;
				return true;
			case 47:
				if (!ctx.L.allow_comments)
				{
					return false;
				}
				ctx.NextState = 25;
				return true;
			default:
				return false;
			}
		}
		return true;
	}

	private static bool State2(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char >= 49 && ctx.L.input_char <= 57)
		{
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 3;
			return true;
		}
		if (ctx.L.input_char == 48)
		{
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 4;
			return true;
		}
		return false;
	}

	private static bool State3(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57)
			{
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				continue;
			}
			if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13))
			{
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			}
			switch (ctx.L.input_char)
			{
			case 44:
			case 93:
			case 125:
				ctx.L.UngetChar();
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			case 46:
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 5;
				return true;
			case 69:
			case 101:
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 7;
				return true;
			default:
				return false;
			}
		}
		return true;
	}

	private static bool State4(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13))
		{
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		switch (ctx.L.input_char)
		{
		case 44:
		case 93:
		case 125:
			ctx.L.UngetChar();
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		case 46:
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 5;
			return true;
		case 69:
		case 101:
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 7;
			return true;
		default:
			return false;
		}
	}

	private static bool State5(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57)
		{
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 6;
			return true;
		}
		return false;
	}

	private static bool State6(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57)
			{
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				continue;
			}
			if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13))
			{
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			}
			switch (ctx.L.input_char)
			{
			case 44:
			case 93:
			case 125:
				ctx.L.UngetChar();
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			case 69:
			case 101:
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				ctx.NextState = 7;
				return true;
			default:
				return false;
			}
		}
		return true;
	}

	private static bool State7(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57)
		{
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 8;
			return true;
		}
		int num = ctx.L.input_char;
		if (num == 43 || num == 45)
		{
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
			ctx.NextState = 8;
			return true;
		}
		return false;
	}

	private static bool State8(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57)
			{
				ctx.L.string_buffer.Append((char)ctx.L.input_char);
				continue;
			}
			if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13))
			{
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			}
			int num = ctx.L.input_char;
			if (num == 44 || num == 93 || num == 125)
			{
				ctx.L.UngetChar();
				ctx.Return = true;
				ctx.NextState = 1;
				return true;
			}
			return false;
		}
		return true;
	}

	private static bool State9(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 114)
		{
			ctx.NextState = 10;
			return true;
		}
		return false;
	}

	private static bool State10(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 117)
		{
			ctx.NextState = 11;
			return true;
		}
		return false;
	}

	private static bool State11(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 101)
		{
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		return false;
	}

	private static bool State12(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 97)
		{
			ctx.NextState = 13;
			return true;
		}
		return false;
	}

	private static bool State13(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 108)
		{
			ctx.NextState = 14;
			return true;
		}
		return false;
	}

	private static bool State14(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 115)
		{
			ctx.NextState = 15;
			return true;
		}
		return false;
	}

	private static bool State15(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 101)
		{
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		return false;
	}

	private static bool State16(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 117)
		{
			ctx.NextState = 17;
			return true;
		}
		return false;
	}

	private static bool State17(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 108)
		{
			ctx.NextState = 18;
			return true;
		}
		return false;
	}

	private static bool State18(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 108)
		{
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		return false;
	}

	private static bool State19(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			switch (ctx.L.input_char)
			{
			case 34:
				ctx.L.UngetChar();
				ctx.Return = true;
				ctx.NextState = 20;
				return true;
			case 92:
				ctx.StateStack = 19;
				ctx.NextState = 21;
				return true;
			}
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
		}
		return true;
	}

	private static bool State20(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 34)
		{
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		return false;
	}

	private static bool State21(FsmContext ctx)
	{
		ctx.L.GetChar();
		switch (ctx.L.input_char)
		{
		case 117:
			ctx.NextState = 22;
			return true;
		case 34:
		case 39:
		case 47:
		case 92:
		case 98:
		case 102:
		case 110:
		case 114:
		case 116:
			ctx.L.string_buffer.Append(ProcessEscChar(ctx.L.input_char));
			ctx.NextState = ctx.StateStack;
			return true;
		default:
			return false;
		}
	}

	private static bool State22(FsmContext ctx)
	{
		int num = 0;
		int num2 = 4096;
		ctx.L.unichar = 0;
		while (ctx.L.GetChar())
		{
			if ((ctx.L.input_char >= 48 && ctx.L.input_char <= 57) || (ctx.L.input_char >= 65 && ctx.L.input_char <= 70) || (ctx.L.input_char >= 97 && ctx.L.input_char <= 102))
			{
				ctx.L.unichar += HexValue(ctx.L.input_char) * num2;
				num++;
				num2 /= 16;
				if (num == 4)
				{
					ctx.L.string_buffer.Append(Convert.ToChar(ctx.L.unichar));
					ctx.NextState = ctx.StateStack;
					return true;
				}
				continue;
			}
			return false;
		}
		return true;
	}

	private static bool State23(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			switch (ctx.L.input_char)
			{
			case 39:
				ctx.L.UngetChar();
				ctx.Return = true;
				ctx.NextState = 24;
				return true;
			case 92:
				ctx.StateStack = 23;
				ctx.NextState = 21;
				return true;
			}
			ctx.L.string_buffer.Append((char)ctx.L.input_char);
		}
		return true;
	}

	private static bool State24(FsmContext ctx)
	{
		ctx.L.GetChar();
		if (ctx.L.input_char == 39)
		{
			ctx.L.input_char = 34;
			ctx.Return = true;
			ctx.NextState = 1;
			return true;
		}
		return false;
	}

	private static bool State25(FsmContext ctx)
	{
		ctx.L.GetChar();
		switch (ctx.L.input_char)
		{
		case 42:
			ctx.NextState = 27;
			return true;
		case 47:
			ctx.NextState = 26;
			return true;
		default:
			return false;
		}
	}

	private static bool State26(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char == 10)
			{
				ctx.NextState = 1;
				return true;
			}
		}
		return true;
	}

	private static bool State27(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char == 42)
			{
				ctx.NextState = 28;
				return true;
			}
		}
		return true;
	}

	private static bool State28(FsmContext ctx)
	{
		while (ctx.L.GetChar())
		{
			if (ctx.L.input_char != 42)
			{
				if (ctx.L.input_char == 47)
				{
					ctx.NextState = 1;
					return true;
				}
				ctx.NextState = 27;
				return true;
			}
		}
		return true;
	}

	private bool GetChar()
	{
		if ((input_char = NextChar()) != -1)
		{
			return true;
		}
		end_of_input = true;
		return false;
	}

	private int NextChar()
	{
		if (input_buffer != 0)
		{
			int result = input_buffer;
			input_buffer = 0;
			return result;
		}
		return reader.Read();
	}

	public bool NextToken()
	{
		fsm_context.Return = false;
		while (true)
		{
			if (!fsm_handler_table[state - 1](fsm_context))
			{
				throw new JsonException(input_char);
			}
			if (end_of_input)
			{
				return false;
			}
			if (fsm_context.Return)
			{
				break;
			}
			state = fsm_context.NextState;
		}
		string_value = string_buffer.ToString();
		string_buffer.Remove(0, string_buffer.Length);
		token = fsm_return_table[state - 1];
		if (token == 65542)
		{
			token = input_char;
		}
		state = fsm_context.NextState;
		return true;
	}

	private void UngetChar()
	{
		input_buffer = input_char;
	}
}
