using System;
using System.Globalization;
using System.Text;
using Decal.Adapter.NetParser;
using Decal.Adapter.Support;

namespace Decal.Adapter;

/// <summary>
/// Represents Message data
/// </summary>
public class MessageStruct : MarshalByRefObject
{
	internal struct MessageField
	{
		internal string Name;

		internal MemberParserType Type;

		internal object Value;

		internal int Offset;

		internal int Length;
	}

	internal byte[] mData;

	internal int mOffset;

	internal int mLength;

	internal MemberParser mParser;

	internal MessageStruct mParent;

	internal int mIndex;

	internal bool mParsed;

	internal int mCount;

	internal MessageField[] mFields;

	/// <summary>
	/// Returns the number of fields (or vector length)
	/// </summary>
	public virtual int Count
	{
		get
		{
			if (!mParsed)
			{
				Parse();
			}
			return mCount;
		}
	}

	/// <summary>
	/// Returns the specified field data
	/// </summary>
	/// <param name="index">Field index</param>
	/// <returns>Field value</returns>
	public virtual object this[int index]
	{
		get
		{
			if (!mParsed)
			{
				Parse();
			}
			if (index >= 0 && index < mCount)
			{
				return mFields[index].Value;
			}
			return null;
		}
	}

	/// <summary>
	/// Returns the specified field data
	/// </summary>
	/// <param name="name">Field name</param>
	/// <returns>Field value</returns>
	public virtual object this[string name]
	{
		get
		{
			if (!mParsed)
			{
				Parse();
			}
			int num = IndexFromName(name);
			if (num >= 0 && num < mCount)
			{
				return mFields[num].Value;
			}
			return null;
		}
	}

	/// <summary>
	/// Returns the raw bytes for this field
	/// </summary>
	public virtual byte[] RawData
	{
		get
		{
			if (mParent != null)
			{
				return mParent.RawValue(mIndex);
			}
			byte[] array = (byte[])Array.CreateInstance(typeof(byte), mData.Length);
			Buffer.BlockCopy(mData, 0, array, 0, mData.Length);
			return array;
		}
	}

	/// <summary>
	/// Returns the next object in the (parent) vector
	/// </summary>
	public virtual object Next
	{
		get
		{
			if (mParent == null)
			{
				return null;
			}
			return mParent[mIndex + 1];
		}
	}

	/// <summary>
	/// Returns the parent field
	/// </summary>
	public virtual MessageStruct Parent => mParent;

	internal MessageStruct()
	{
	}

	internal MessageStruct(byte[] Data, int Offset, MemberParser Parser)
	{
		mData = (byte[])Array.CreateInstance(typeof(byte), Data.Length);
		Buffer.BlockCopy(Data, 0, mData, 0, mData.Length);
		mOffset = Offset;
		mParser = Parser;
		mCount = -1;
	}

	internal MessageStruct(byte[] Data, int Offset, MemberParser Parser, MessageStruct Parent, int Index)
	{
		mData = Data;
		mOffset = Offset;
		mParser = Parser;
		mParent = Parent;
		mIndex = Index;
		mCount = -1;
	}

	internal MessageStruct(byte[] Data, int Offset, MemberParser Parser, int Length, MessageStruct Parent, int Index)
	{
		mData = Data;
		mOffset = Offset;
		mParser = Parser;
		mParent = Parent;
		mIndex = Index;
		mCount = Length;
	}

	internal int ObjectToIndex(object vIndex)
	{
		string text = vIndex as string;
		int num = -1;
		num = (string.IsNullOrEmpty(text) ? Util.UnboxTo<int>(vIndex) : IndexFromName(text));
		if (num >= 0 && num < mCount)
		{
			return num;
		}
		return -1;
	}

	/// <summary>
	/// Return the field name for the specified index
	/// </summary>
	/// <param name="index">Field index</param>
	/// <returns>Name of the field</returns>
	public virtual string Name(int index)
	{
		if (!mParsed)
		{
			Parse();
		}
		if (index >= 0 && index < mCount)
		{
			return mFields[index].Name;
		}
		return null;
	}

	/// <summary>
	/// Returns the passed in value?
	/// </summary>
	/// <param name="memberName"></param>
	/// <returns></returns>
	public virtual string Name(string memberName)
	{
		if (!mParsed)
		{
			Parse();
		}
		int num = IndexFromName(memberName);
		if (num >= 0 && num < mCount)
		{
			return mFields[num].Name;
		}
		return null;
	}

	/// <summary>
	/// Returns the specified child structure
	/// </summary>
	/// <param name="index">Field index</param>
	/// <returns>MessageStruct for the specified field</returns>
	public virtual MessageStruct Struct(int index)
	{
		if (!mParsed)
		{
			Parse();
		}
		if (index >= 0 && index < mCount)
		{
			MemberParserType type = mFields[index].Type;
			if (type == MemberParserType.Struct || type == MemberParserType.Vector)
			{
				return mFields[index].Value as MessageStruct;
			}
		}
		return null;
	}

	/// <summary>
	/// Returns the specified child structure
	/// </summary>
	/// <param name="name">Field name</param>
	/// <returns>MessageStruct for the specified field</returns>
	public virtual MessageStruct Struct(string name)
	{
		if (!mParsed)
		{
			Parse();
		}
		int num = IndexFromName(name);
		if (num >= 0 && num < mCount)
		{
			MemberParserType type = mFields[num].Type;
			if (type == MemberParserType.Struct || type == MemberParserType.Vector)
			{
				return mFields[num].Value as MessageStruct;
			}
		}
		return null;
	}

	/// <summary>
	/// Returns the specified field value
	/// </summary>
	/// <typeparam name="FieldType">Type of the field</typeparam>
	/// <param name="index">Field index</param>
	/// <returns>Field value cast to the specified FieldType</returns>
	public virtual FieldType Value<FieldType>(int index)
	{
		if (!mParsed)
		{
			Parse();
		}
		if (index >= 0 && index < mCount)
		{
			return Util.UnboxTo<FieldType>(mFields[index].Value);
		}
		return default(FieldType);
	}

	/// <summary>
	/// Returns the specified field value
	/// </summary>
	/// <typeparam name="FieldType">Type of the field</typeparam>
	/// <param name="name">Field name</param>
	/// <returns>Field value cast to the specified FieldType</returns>
	public virtual FieldType Value<FieldType>(string name)
	{
		if (!mParsed)
		{
			Parse();
		}
		int num = IndexFromName(name);
		if (num >= 0 && num < mCount)
		{
			return Util.UnboxTo<FieldType>(mFields[num].Value);
		}
		return default(FieldType);
	}

	/// <summary>
	/// Returns the raw bytes of the specified field
	/// </summary>
	/// <param name="index">Field index</param>
	/// <returns>Raw field value</returns>
	public virtual byte[] RawValue(int index)
	{
		if (!mParsed)
		{
			Parse();
		}
		if (index >= 0 && index < mCount)
		{
			int length = mFields[index].Length;
			byte[] array = (byte[])Array.CreateInstance(typeof(byte), length);
			Buffer.BlockCopy(mData, mFields[index].Offset, array, 0, length);
			return array;
		}
		return null;
	}

	/// <summary>
	/// Returns the raw bytes of the specified field
	/// </summary>
	/// <param name="name">Field name</param>
	/// <returns>Raw field value</returns>
	public virtual byte[] RawValue(string name)
	{
		if (!mParsed)
		{
			Parse();
		}
		int num = IndexFromName(name);
		if (num >= 0 && num < mCount)
		{
			int length = mFields[num].Length;
			byte[] array = (byte[])Array.CreateInstance(typeof(byte), length);
			Buffer.BlockCopy(mData, mFields[num].Offset, array, 0, length);
			return array;
		}
		return null;
	}

	internal int IndexFromName(string Name)
	{
		int num = mCount;
		for (int i = 0; i < num; i++)
		{
			if (string.Compare(Name, mFields[i].Name, ignoreCase: true, CultureInfo.InvariantCulture) == 0)
			{
				return i;
			}
		}
		return -1;
	}

	internal void Parse()
	{
		if (mCount == -1)
		{
			ParseStruct();
		}
		else
		{
			ParseVector();
		}
	}

	internal void ParseStruct()
	{
		int length = ParseCounter(mParser);
		mFields = (MessageField[])Array.CreateInstance(typeof(MessageField), length);
		mParsed = true;
		int ByteIndex = mOffset;
		mCount = 0;
		ParseHelper(mParser, ref mCount, ref ByteIndex);
		mLength = ByteIndex - mOffset;
		MessageField[] sourceArray = mFields;
		mFields = (MessageField[])Array.CreateInstance(typeof(MessageField), mCount);
		Array.Copy(sourceArray, mFields, mCount);
	}

	internal void ParseVector()
	{
		int num = mCount;
		mFields = (MessageField[])Array.CreateInstance(typeof(MessageField), num);
		mParsed = true;
		int num2 = mOffset;
		for (int i = 0; i < num; i++)
		{
			mFields[i].Name = i.ToString();
			mFields[i].Offset = num2;
			mFields[i].Type = MemberParserType.Struct;
			MessageStruct messageStruct = new MessageStruct(mData, num2, mParser, this, i);
			messageStruct.ParseStruct();
			mFields[i].Value = messageStruct;
			mFields[i].Length = messageStruct.mLength;
			num2 += messageStruct.mLength;
		}
		mLength = num2 - mOffset;
	}

	internal int ParseCounter(MemberParser Parser)
	{
		int num = 0;
		while (Parser != null)
		{
			num = ((Parser.MemberType != MemberParserType.Case) ? (num + 1) : (num + ParseCounter(Parser.Child)));
			Parser = Parser.Next;
		}
		return num;
	}

	internal void ParseHelper(MemberParser Parser, ref int FieldIndex, ref int ByteIndex)
	{
		Encoding encoding = Encoding.GetEncoding(1252);
		while (Parser != null)
		{
			if (Parser.PreAlignment != 0)
			{
				int num = ByteIndex % Parser.PreAlignment;
				if (num != 0)
				{
					ByteIndex += Parser.PreAlignment - num;
				}
			}
			bool flag = Parser.Condition == MemberParserCondition.None;
			if (!flag)
			{
				MessageStruct messageStruct = this;
				object obj;
				do
				{
					obj = messageStruct[Parser.ConditionField];
					if (obj != null)
					{
						break;
					}
					messageStruct = messageStruct.mParent;
				}
				while (messageStruct != null);
				if (obj != null)
				{
					long num2 = 0L;
					Type type = obj.GetType();
					if (type.Equals(typeof(int)))
					{
						num2 = Convert.ToInt64(obj);
						num2 &= 0xFFFFFFFFu;
					}
					else if (type.Equals(typeof(short)))
					{
						num2 = Convert.ToInt64(obj);
						num2 &= 0xFFFF;
					}
					else if (type.Equals(typeof(byte)))
					{
						num2 = Convert.ToInt64(obj);
						num2 &= 0xFF;
					}
					else if (type.Equals(typeof(long)))
					{
						num2 = Convert.ToInt64(obj);
					}
					num2 ^= Parser.ConditionXor;
					num2 &= Parser.ConditionAnd;
					switch (Parser.Condition)
					{
					case MemberParserCondition.EQ:
						flag = num2 == Parser.ConditionResult;
						break;
					case MemberParserCondition.NE:
						flag = num2 != Parser.ConditionResult;
						break;
					case MemberParserCondition.GE:
						flag = num2 >= Parser.ConditionResult;
						break;
					case MemberParserCondition.GT:
						flag = num2 > Parser.ConditionResult;
						break;
					case MemberParserCondition.LE:
						flag = num2 <= Parser.ConditionResult;
						break;
					case MemberParserCondition.LT:
						flag = num2 < Parser.ConditionResult;
						break;
					}
				}
			}
			if (flag)
			{
				mFields[FieldIndex].Name = Parser.MemberName;
				mFields[FieldIndex].Offset = ByteIndex;
				mFields[FieldIndex].Type = Parser.MemberType;
				switch (Parser.MemberType)
				{
				case MemberParserType.BYTE:
					mFields[FieldIndex].Value = mData[ByteIndex++];
					break;
				case MemberParserType.WORD:
					mFields[FieldIndex].Value = BitConverter.ToInt16(mData, ByteIndex);
					ByteIndex += 2;
					break;
				case MemberParserType.PackedWORD:
				{
					int num6 = mData[ByteIndex++];
					if ((num6 & 0x80) != 0)
					{
						num6 = ((num6 & 0x7F) << 8) | mData[ByteIndex++];
					}
					mFields[FieldIndex].Value = num6;
					break;
				}
				case MemberParserType.DWORD:
					mFields[FieldIndex].Value = BitConverter.ToInt32(mData, ByteIndex);
					ByteIndex += 4;
					break;
				case MemberParserType.PackedDWORD:
				{
					int num6 = BitConverter.ToInt16(mData, ByteIndex);
					ByteIndex += 2;
					if ((num6 & 0x8000) != 0)
					{
						num6 = ((num6 & 0x7FFF) << 16) | (BitConverter.ToInt16(mData, ByteIndex) & 0xFFFF);
						ByteIndex += 2;
					}
					mFields[FieldIndex].Value = num6;
					break;
				}
				case MemberParserType.QWORD:
					mFields[FieldIndex].Value = BitConverter.ToInt64(mData, ByteIndex);
					ByteIndex += 8;
					break;
				case MemberParserType.@float:
					mFields[FieldIndex].Value = BitConverter.ToSingle(mData, ByteIndex);
					ByteIndex += 4;
					break;
				case MemberParserType.@double:
					mFields[FieldIndex].Value = BitConverter.ToDouble(mData, ByteIndex);
					ByteIndex += 8;
					break;
				case MemberParserType.String:
				{
					int num6 = BitConverter.ToInt16(mData, ByteIndex);
					ByteIndex += 2;
					if (num6 == -1)
					{
						num6 = BitConverter.ToInt32(mData, ByteIndex);
						ByteIndex += 4;
					}
					StringBuilder stringBuilder = new StringBuilder(num6);
					for (int j = 0; j < num6; j++)
					{
						stringBuilder.Append(encoding.GetChars(mData, ByteIndex++, 1));
					}
					mFields[FieldIndex].Value = stringBuilder.ToString();
					ByteIndex = (ByteIndex + 3) & -4;
					break;
				}
				case MemberParserType.WString:
				{
					int num6 = mData[ByteIndex++];
					if ((num6 & 0x80) != 0)
					{
						num6 = ((num6 & 0x7F) << 8) | mData[ByteIndex++];
					}
					StringBuilder stringBuilder = new StringBuilder(num6);
					for (int i = 0; i < num6; i++)
					{
						stringBuilder.Append(BitConverter.ToChar(mData, ByteIndex));
						ByteIndex += 2;
					}
					mFields[FieldIndex].Value = stringBuilder.ToString();
					break;
				}
				case MemberParserType.Struct:
				{
					MessageStruct messageStruct = new MessageStruct(mData, ByteIndex, Parser.Child, this, FieldIndex);
					messageStruct.ParseStruct();
					ByteIndex += messageStruct.mLength;
					mFields[FieldIndex].Value = messageStruct;
					break;
				}
				case MemberParserType.Vector:
				{
					MessageStruct messageStruct = this;
					object obj;
					do
					{
						obj = messageStruct[Parser.LengthField];
						if (obj != null)
						{
							break;
						}
						messageStruct = messageStruct.mParent;
					}
					while (messageStruct != null);
					long num4 = 0L;
					if (obj != null)
					{
						Type type2 = obj.GetType();
						if (type2.Equals(typeof(int)))
						{
							num4 = Convert.ToInt64(obj);
							num4 &= 0xFFFFFFFFu;
						}
						else if (type2.Equals(typeof(short)))
						{
							num4 = Convert.ToInt64(obj);
							num4 &= 0xFFFF;
						}
						else if (type2.Equals(typeof(byte)))
						{
							num4 = Convert.ToInt64(obj);
							num4 &= 0xFF;
						}
						else if (type2.Equals(typeof(long)))
						{
							num4 = Convert.ToInt64(obj);
						}
					}
					long num5 = Parser.LengthMask;
					num4 &= num5;
					if (num5 != 0L)
					{
						while ((num5 & 1) == 0L)
						{
							num4 >>= 1;
							num5 >>= 1;
						}
					}
					messageStruct = new MessageStruct(mData, ByteIndex, Parser.Child, (int)num4 + Parser.LengthDelta, this, FieldIndex);
					messageStruct.ParseVector();
					ByteIndex += messageStruct.mLength;
					mFields[FieldIndex].Value = messageStruct;
					break;
				}
				case MemberParserType.Case:
				{
					int num3 = FieldIndex;
					ParseHelper(Parser.Child, ref FieldIndex, ref ByteIndex);
					if (FieldIndex > num3)
					{
						FieldIndex--;
					}
					break;
				}
				}
				mFields[FieldIndex].Length = ByteIndex - mFields[FieldIndex].Offset;
			}
			if (Parser.PostAlignment != 0)
			{
				int num7 = ByteIndex % Parser.PostAlignment;
				if (num7 != 0)
				{
					num7 = Parser.PostAlignment - num7;
					ByteIndex += num7;
					if (flag)
					{
						mFields[FieldIndex].Length += num7;
					}
				}
			}
			if (flag)
			{
				FieldIndex++;
			}
			Parser = Parser.Next;
		}
	}
}
