using System;
using System.Text;

namespace QCRPG.Framework;

public class BitBuilder
{
	private StringBuilder sb = new StringBuilder();

	public void AddBitsAsString(string bitString)
	{
		char[] array = bitString.ToCharArray();
		foreach (char c in array)
		{
			if (c != '0' && c != '1')
			{
				throw new Exception("Invalid character in bitString");
			}
		}
		sb.Append(bitString);
	}

	public void AddBitsAsByte(byte b)
	{
		AddBitsAsByte(b, 8);
	}

	public void AddBitsAsByte(byte b, int numberOfBits)
	{
		if (numberOfBits != 0)
		{
			string text = Convert.ToString(b, 2).PadLeft(numberOfBits, '0');
			if (text.Length > numberOfBits)
			{
				throw new Exception("Value exceeds number of bits");
			}
			sb.Append(text);
		}
	}

	public void AddBitsAsUint(uint u)
	{
		AddBitsAsUint(u, 32);
	}

	public void AddBitsAsUlong(ulong u)
	{
		AddBitsAsUlong(u, 64);
	}

	public void AddBitsAsUintLittleEndian(uint u)
	{
		AddBitsAsUintLittleEndian(u, 32);
	}

	public void AddBitsAsUlongLittleEndian(ulong u)
	{
		AddBitsAsUlongLittleEndian(u, 64);
	}

	public void AddBitsAsUint(uint u, int numberOfBits)
	{
		if (numberOfBits != 0)
		{
			string text = Convert.ToString(u, 2).PadLeft(numberOfBits, '0');
			if (text.Length > numberOfBits)
			{
				throw new Exception("Value exceeds number of bits");
			}
			sb.Append(text);
		}
	}

	public void AddBitsAsUlong(ulong u, int numberOfBits)
	{
		if (numberOfBits != 0)
		{
			string text = Convert.ToString((long)u, 2).PadLeft(numberOfBits, '0');
			if (text.Length > numberOfBits)
			{
				throw new Exception("Value exceeds number of bits");
			}
			sb.Append(text);
		}
	}

	public void AddBitsAsUintLittleEndian(uint u, int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return;
		}
		if (numberOfBits % 8 != 0)
		{
			throw new Exception("Byte aligned number of bits not specified");
		}
		uint num = 0u;
		switch (numberOfBits)
		{
		case 8:
			if (u > 255)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num = u;
			break;
		case 16:
			if (u > 65535)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 8;
			num |= (u & 0xFF00) >> 8;
			break;
		case 24:
			if (u > 16777215)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 16;
			num |= u & 0xFF00u;
			num |= (u & 0xFF0000) >> 16;
			break;
		case 32:
			num |= (u & 0xFF) << 24;
			num |= (u & 0xFF00) << 8;
			num |= (u & 0xFF0000) >> 8;
			num |= (u & 0xFF000000u) >> 24;
			break;
		default:
			throw new Exception("Unsupported number of bits: " + numberOfBits);
		}
		string text = Convert.ToString(num, 2).PadLeft(numberOfBits, '0');
		if (text.Length > numberOfBits)
		{
			throw new Exception("Value exceeds number of bits");
		}
		sb.Append(text);
	}

	public void AddBitsAsUlongLittleEndian(ulong u, int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return;
		}
		if (numberOfBits % 8 != 0)
		{
			throw new Exception("Byte aligned number of bits not specified");
		}
		ulong num = 0uL;
		switch (numberOfBits)
		{
		case 8:
			if (u > 255)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num = u;
			break;
		case 16:
			if (u > 65535)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 8;
			num |= (u & 0xFF00) >> 8;
			break;
		case 24:
			if (u > 16777215)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 16;
			num |= u & 0xFF00;
			num |= (u & 0xFF0000) >> 16;
			break;
		case 32:
			if (u > uint.MaxValue)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 24;
			num |= (u & 0xFF00) << 8;
			num |= (u & 0xFF0000) >> 8;
			num |= (u & 0xFF000000u) >> 24;
			break;
		case 40:
			if (u > 1099511627775L)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 32;
			num |= (u & 0xFF00) << 16;
			num |= u & 0xFF0000;
			num |= (u & 0xFF000000u) >> 16;
			num |= (u & 0xFF00000000L) >> 32;
			break;
		case 48:
			if (u > 281474976710655L)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 40;
			num |= (u & 0xFF00) << 24;
			num |= (u & 0xFF0000) << 8;
			num |= (u & 0xFF000000u) >> 8;
			num |= (u & 0xFF00000000L) >> 24;
			num |= (u & 0xFF0000000000L) >> 40;
			break;
		case 56:
			if (u > 72057594037927935L)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 48;
			num |= (u & 0xFF00) << 32;
			num |= (u & 0xFF0000) << 16;
			num |= u & 0xFF000000u;
			num |= (u & 0xFF00000000L) >> 16;
			num |= (u & 0xFF0000000000L) >> 32;
			num |= (u & 0xFF000000000000L) >> 48;
			break;
		case 64:
			num |= (u & 0xFF) << 56;
			num |= (u & 0xFF00) << 40;
			num |= (u & 0xFF0000) << 24;
			num |= (u & 0xFF000000u) << 8;
			num |= (u & 0xFF00000000L) >> 8;
			num |= (u & 0xFF0000000000L) >> 24;
			num |= (u & 0xFF000000000000L) >> 40;
			num |= (u & 0xFF00000000000000uL) >> 56;
			break;
		default:
			throw new Exception("Unsupported number of bits: " + numberOfBits);
		}
		string text = Convert.ToString((long)num, 2).PadLeft(numberOfBits, '0');
		if (text.Length > numberOfBits)
		{
			throw new Exception("Value exceeds number of bits");
		}
		sb.Append(text);
	}

	public string RemoveBitsAsString(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return "";
		}
		string result = sb.ToString().Substring(0, numberOfBits);
		sb = sb.Remove(0, numberOfBits);
		return result;
	}

	public byte RemoveBitsAsByte(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return 0;
		}
		if (numberOfBits > 8)
		{
			throw new Exception("numberOfBits is too big to fit in a byte");
		}
		string value = RemoveBitsAsString(numberOfBits);
		return Convert.ToByte(value, 2);
	}

	public uint RemoveBitsAsUint(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return 0u;
		}
		if (numberOfBits > 32)
		{
			throw new Exception("numberOfBits is too big to fit in a uint");
		}
		string value = RemoveBitsAsString(numberOfBits);
		return Convert.ToUInt32(value, 2);
	}

	public ulong RemoveBitsAsUlong(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return 0uL;
		}
		if (numberOfBits > 64)
		{
			throw new Exception("numberOfBits is too big to fit in a ulong");
		}
		string value = RemoveBitsAsString(numberOfBits);
		return Convert.ToUInt64(value, 2);
	}

	public uint RemoveBitsAsUintLittleEndian(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return 0u;
		}
		if (numberOfBits > 32)
		{
			throw new Exception("numberOfBits is too big to fit in a uint");
		}
		if (numberOfBits % 8 != 0)
		{
			throw new Exception("Byte aligned number of bits not specified");
		}
		string text = "";
		switch (numberOfBits)
		{
		case 8:
			text = RemoveBitsAsString(8);
			break;
		case 16:
		{
			string text11 = RemoveBitsAsString(16);
			string text12 = text11.Substring(0, 8);
			string text13 = text11.Substring(8, 8);
			text = text13 + text12;
			break;
		}
		case 24:
		{
			string text7 = RemoveBitsAsString(24);
			string text8 = text7.Substring(0, 8);
			string text9 = text7.Substring(8, 8);
			string text10 = text7.Substring(16, 8);
			text = text10 + text9 + text8;
			break;
		}
		case 32:
		{
			string text2 = RemoveBitsAsString(32);
			string text3 = text2.Substring(0, 8);
			string text4 = text2.Substring(8, 8);
			string text5 = text2.Substring(16, 8);
			string text6 = text2.Substring(24, 8);
			text = text6 + text5 + text4 + text3;
			break;
		}
		default:
			throw new Exception("Unsupported number of bits: " + numberOfBits);
		}
		return Convert.ToUInt32(text, 2);
	}

	public ulong RemoveBitsAsUlongLittleEndian(int numberOfBits)
	{
		if (numberOfBits == 0)
		{
			return 0uL;
		}
		if (numberOfBits > 64)
		{
			throw new Exception("numberOfBits is too big to fit in a ulong");
		}
		if (numberOfBits % 8 != 0)
		{
			throw new Exception("Byte aligned number of bits not specified");
		}
		string text = "";
		switch (numberOfBits)
		{
		case 8:
			text = RemoveBitsAsString(8);
			break;
		case 16:
		{
			string text41 = RemoveBitsAsString(16);
			string text42 = text41.Substring(0, 8);
			string text43 = text41.Substring(8, 8);
			text = text43 + text42;
			break;
		}
		case 24:
		{
			string text37 = RemoveBitsAsString(24);
			string text38 = text37.Substring(0, 8);
			string text39 = text37.Substring(8, 8);
			string text40 = text37.Substring(16, 8);
			text = text40 + text39 + text38;
			break;
		}
		case 32:
		{
			string text32 = RemoveBitsAsString(32);
			string text33 = text32.Substring(0, 8);
			string text34 = text32.Substring(8, 8);
			string text35 = text32.Substring(16, 8);
			string text36 = text32.Substring(24, 8);
			text = text36 + text35 + text34 + text33;
			break;
		}
		case 40:
		{
			string text26 = RemoveBitsAsString(40);
			string text27 = text26.Substring(0, 8);
			string text28 = text26.Substring(8, 8);
			string text29 = text26.Substring(16, 8);
			string text30 = text26.Substring(24, 8);
			string text31 = text26.Substring(32, 8);
			text = text31 + text30 + text29 + text28 + text27;
			break;
		}
		case 48:
		{
			string text19 = RemoveBitsAsString(48);
			string text20 = text19.Substring(0, 8);
			string text21 = text19.Substring(8, 8);
			string text22 = text19.Substring(16, 8);
			string text23 = text19.Substring(24, 8);
			string text24 = text19.Substring(32, 8);
			string text25 = text19.Substring(40, 8);
			text = text25 + text24 + text23 + text22 + text21 + text20;
			break;
		}
		case 56:
		{
			string text11 = RemoveBitsAsString(56);
			string text12 = text11.Substring(0, 8);
			string text13 = text11.Substring(8, 8);
			string text14 = text11.Substring(16, 8);
			string text15 = text11.Substring(24, 8);
			string text16 = text11.Substring(32, 8);
			string text17 = text11.Substring(40, 8);
			string text18 = text11.Substring(48, 8);
			text = text18 + text17 + text16 + text15 + text14 + text13 + text12;
			break;
		}
		case 64:
		{
			string text2 = RemoveBitsAsString(64);
			string text3 = text2.Substring(0, 8);
			string text4 = text2.Substring(8, 8);
			string text5 = text2.Substring(16, 8);
			string text6 = text2.Substring(24, 8);
			string text7 = text2.Substring(32, 8);
			string text8 = text2.Substring(40, 8);
			string text9 = text2.Substring(48, 8);
			string text10 = text2.Substring(56, 8);
			text = text10 + text9 + text8 + text7 + text6 + text5 + text4 + text3;
			break;
		}
		default:
			throw new Exception("Unsupported number of bits: " + numberOfBits);
		}
		return Convert.ToUInt64(text, 2);
	}

	public void ChangeBitsAsString(int location, string bitString)
	{
		if (location + bitString.Length > sb.Length)
		{
			throw new Exception("location + bitString.Length runs past the end");
		}
		sb.Remove(location, bitString.Length);
		sb.Insert(location, bitString);
	}

	public void ChangeBitsAsByte(int location, byte b)
	{
		ChangeBitsAsByte(location, b, 8);
	}

	public void ChangeBitsAsByte(int location, byte b, int numberOfBits)
	{
		if (location + numberOfBits > sb.Length)
		{
			throw new Exception("location + numberOfBits runs past the end");
		}
		string text = Convert.ToString(b, 2).PadLeft(numberOfBits, '0');
		if (text.Length > numberOfBits)
		{
			throw new Exception("Value exceeds number of bits");
		}
		sb.Remove(location, numberOfBits);
		sb.Insert(location, text);
	}

	public void ChangeBitsAsUint(int location, uint u)
	{
		ChangeBitsAsUint(location, u, 32);
	}

	public void ChangeBitsAsUintLittleEndian(int location, uint u)
	{
		ChangeBitsAsUintLittleEndian(location, u, 32);
	}

	public void ChangeBitsAsUint(int location, uint u, int numberOfBits)
	{
		if (location + numberOfBits > sb.Length)
		{
			throw new Exception("location + numberOfBits runs past the end");
		}
		string text = Convert.ToString(u, 2).PadLeft(numberOfBits, '0');
		if (text.Length > numberOfBits)
		{
			throw new Exception("Value exceeds number of bits");
		}
		sb.Remove(location, numberOfBits);
		sb.Insert(location, text);
	}

	public void ChangeBitsAsUintLittleEndian(int location, uint u, int numberOfBits)
	{
		if (location + numberOfBits > sb.Length)
		{
			throw new Exception("location + numberOfBits runs past the end");
		}
		if (numberOfBits % 8 != 0)
		{
			throw new Exception("Byte aligned number of bits not specified");
		}
		uint num = 0u;
		switch (numberOfBits)
		{
		case 8:
			if (u > 255)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num = u;
			break;
		case 16:
			if (u > 65535)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 8;
			num |= (u & 0xFF00) >> 8;
			break;
		case 24:
			if (u > 16777215)
			{
				throw new Exception("Initial value exceeds number of bits");
			}
			num |= (u & 0xFF) << 16;
			num |= u & 0xFF00u;
			num |= (u & 0xFF0000) >> 16;
			break;
		case 32:
			num |= (u & 0xFF) << 24;
			num |= (u & 0xFF00) << 8;
			num |= (u & 0xFF0000) >> 8;
			num |= (u & 0xFF000000u) >> 24;
			break;
		default:
			throw new Exception("Unsupported number of bits: " + numberOfBits);
		}
		string text = Convert.ToString(num, 2).PadLeft(numberOfBits, '0');
		if (text.Length > numberOfBits)
		{
			throw new Exception("Value exceeds number of bits");
		}
		sb.Remove(location, numberOfBits);
		sb.Insert(location, text);
	}

	public override string ToString()
	{
		return sb.ToString();
	}

	public byte[] ToByteArray()
	{
		string text = sb.ToString();
		int num = 8 - text.Length % 8;
		if (num == 8)
		{
			num = 0;
		}
		string text2 = new string('0', num);
		text += text2;
		byte[] array = new byte[text.Length / 8];
		int num2 = 0;
		while (text.Length > 0)
		{
			string value = text.Substring(0, 8);
			array[num2] = Convert.ToByte(value, 2);
			text = text.Remove(0, 8);
			num2++;
		}
		return array;
	}

	public void FromByteArray(byte[] byteArray)
	{
		FromByteArray(byteArray, byteArray.Length);
	}

	public void FromByteArray(byte[] byteArray, int length)
	{
		sb.Length = 0;
		for (int i = 0; i < length; i++)
		{
			string value = Convert.ToString(byteArray[i], 2).PadLeft(8, '0');
			sb.Append(value);
		}
	}

	public int GetNumberOfBits()
	{
		return sb.Length;
	}
}
