using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Indy.IL2CPU {
	public static class VTablesImpl {
		// this field seems to be always empty, but the VTablesImpl class is embedded in the final exe.
		public static VTable[] mTypes;
		public static bool IsInstance(int aObjectType, int aDesiredObjectType) {
			int xCurrentType = aObjectType;
			if (aObjectType == 0) {
				return true;
			}
			do {
				if (xCurrentType == aDesiredObjectType) {
					return true;
				}
				if (xCurrentType == mTypes[xCurrentType].BaseTypeIdentifier) {
					return false;
				}
				xCurrentType = mTypes[xCurrentType].BaseTypeIdentifier;
			} while (xCurrentType != 0);
			return false;
		}

		public static void LoadTypeTable(int aTypeCount) {
			//mTypes = new VTable[aTypeCount];
		}

		public static void SetTypeInfo(int aType, int aBaseType, int[] aMethodIndexes, int[] aMethodAddresses, char[] aName) {
			mTypes[aType] = new VTable();
			mTypes[aType].BaseTypeIdentifier = aBaseType;
			mTypes[aType].MethodIndexes = aMethodIndexes;
			mTypes[aType].MethodAddresses = aMethodAddresses;
			mTypes[aType].Name = aName;
		}

		public static string GetTypeName(int aType) {
			return new String(mTypes[aType].Name);
		}

		public static void SetMethodInfo(int aType, int aMethodIndex, int aMethodIdentifier, int aMethodAddress, char[] aName) {
			mTypes[aType].MethodIndexes[aMethodIndex] = aMethodIdentifier;
			mTypes[aType].MethodAddresses[aMethodIndex] = aMethodAddress;
		}

		private static void WriteNumber(uint aValue, byte aBitCount) {
			uint xValue = aValue;
			byte xCurrentBits = aBitCount;
			Console.Write("0x");
			while (xCurrentBits >= 4) {
				xCurrentBits -= 4;
				byte xCurrentDigit = (byte)((xValue >> xCurrentBits) & 0xF);
				string xDigitString = null;
				switch (xCurrentDigit) {
					case 0:
						xDigitString = "0";
						goto default;
					case 1:
						xDigitString = "1";
						goto default;
					case 2:
						xDigitString = "2";
						goto default;
					case 3:
						xDigitString = "3";
						goto default;
					case 4:
						xDigitString = "4";
						goto default;
					case 5:
						xDigitString = "5";
						goto default;
					case 6:
						xDigitString = "6";
						goto default;
					case 7:
						xDigitString = "7";
						goto default;
					case 8:
						xDigitString = "8";
						goto default;
					case 9:
						xDigitString = "9";
						goto default;
					case 10:
						xDigitString = "A";
						goto default;
					case 11:
						xDigitString = "B";
						goto default;
					case 12:
						xDigitString = "C";
						goto default;
					case 13:
						xDigitString = "D";
						goto default;
					case 14:
						xDigitString = "E";
						goto default;
					case 15:
						xDigitString = "F";
						goto default;
					default:
						Console.Write(xDigitString);
						break;
				}
			}
		}

		public static int GetMethodAddressForType(int aType, int aMethodIndex) {
			if (aType == 0) {
				for (int i = 0; i < mTypes[0].MethodIndexes.Length; i++) {
					if (mTypes[0].MethodIndexes[i] == aMethodIndex) {
						return mTypes[0].MethodAddresses[i];
					}
				}
			} else {
				//Console.WriteLine("Checking for MethodAddress");
				//Console.Write("    Type = ");
				//Console.Write(aType.ToString());
				//Console.Write(", Method = ");
				//Console.WriteLine(aMethodIndex.ToString());
				do {
					//Console.Write("Checking type ");
					//Console.WriteLine(aType.ToString());
					for (int i = 0; i < mTypes[aType].MethodIndexes.Length; i++) {
						//Console.Write("    ");
						//Console.WriteLine(mTypes[aType].MethodIndexes[i].ToString());
						if (mTypes[aType].MethodIndexes[i] == aMethodIndex) {
							//Console.WriteLine("Found!");
							return mTypes[aType].MethodAddresses[i];
						}
					}
					aType = mTypes[aType].BaseTypeIdentifier;
				} while (aType != 0);
			}
			throw new Exception("Cannot find virtual method!");
		}
	}
	[StructLayout(LayoutKind.Explicit, Size = 16)]
	public struct VTable {
		[FieldOffset(0)]
		public int BaseTypeIdentifier;
		[FieldOffset(4)]
		public char[] Name;
		[FieldOffset(8)]
		public int[] MethodIndexes;
		[FieldOffset(12)]
		public int[] MethodAddresses;
	}
}