using System;
using System.Collections.Generic;
using System.Linq;

namespace Indy.IL2CPU.IL {
	partial class ILReader {
		private static byte GetOperandSize(OpCodeEnum aOpCode) {
			switch (aOpCode) {
				case OpCodeEnum.Add:
				case OpCodeEnum.Add_Ovf:
				case OpCodeEnum.Add_Ovf_Un:
				case OpCodeEnum.And:
				case OpCodeEnum.Arglist:
				case OpCodeEnum.Break:
				case OpCodeEnum.Ceq:
				case OpCodeEnum.Cgt:
				case OpCodeEnum.Cgt_Un:
				case OpCodeEnum.Ckfinite:
				case OpCodeEnum.Clt:
				case OpCodeEnum.Clt_Un:
				case OpCodeEnum.Conv_I:
				case OpCodeEnum.Conv_I1:
				case OpCodeEnum.Conv_I2:
				case OpCodeEnum.Conv_I4:
				case OpCodeEnum.Conv_I8:
				case OpCodeEnum.Conv_Ovf_I:
				case OpCodeEnum.Conv_Ovf_I_Un:
				case OpCodeEnum.Conv_Ovf_I1:
				case OpCodeEnum.Conv_Ovf_I1_Un:
				case OpCodeEnum.Conv_Ovf_I2:
				case OpCodeEnum.Conv_Ovf_I2_Un:
				case OpCodeEnum.Conv_Ovf_I4:
				case OpCodeEnum.Conv_Ovf_I4_Un:
				case OpCodeEnum.Conv_Ovf_I8:
				case OpCodeEnum.Conv_Ovf_I8_Un:
				case OpCodeEnum.Conv_Ovf_U:
				case OpCodeEnum.Conv_Ovf_U_Un:
				case OpCodeEnum.Conv_Ovf_U1:
				case OpCodeEnum.Conv_Ovf_U1_Un:
				case OpCodeEnum.Conv_Ovf_U2:
				case OpCodeEnum.Conv_Ovf_U2_Un:
				case OpCodeEnum.Conv_Ovf_U4:
				case OpCodeEnum.Conv_Ovf_U4_Un:
				case OpCodeEnum.Conv_Ovf_U8:
				case OpCodeEnum.Conv_Ovf_U8_Un:
				case OpCodeEnum.Conv_R_Un:
				case OpCodeEnum.Conv_R4:
				case OpCodeEnum.Conv_R8:
				case OpCodeEnum.Conv_U:
				case OpCodeEnum.Conv_U1:
				case OpCodeEnum.Conv_U2:
				case OpCodeEnum.Conv_U4:
				case OpCodeEnum.Conv_U8:
				case OpCodeEnum.Cpblk:
				case OpCodeEnum.Div:
				case OpCodeEnum.Div_Un:
				case OpCodeEnum.Dup:
				case OpCodeEnum.Endfilter:
				case OpCodeEnum.Endfinally:
				case OpCodeEnum.Initblk:
				case OpCodeEnum.Ldarg_0:
				case OpCodeEnum.Ldarg_1:
				case OpCodeEnum.Ldarg_2:
				case OpCodeEnum.Ldarg_3:
				case OpCodeEnum.Ldc_I4_0:
				case OpCodeEnum.Ldc_I4_1:
				case OpCodeEnum.Ldc_I4_2:
				case OpCodeEnum.Ldc_I4_3:
				case OpCodeEnum.Ldc_I4_4:
				case OpCodeEnum.Ldc_I4_5:
				case OpCodeEnum.Ldc_I4_6:
				case OpCodeEnum.Ldc_I4_7:
				case OpCodeEnum.Ldc_I4_8:
				case OpCodeEnum.Ldc_I4_M1:
				case OpCodeEnum.Ldelem_I:
				case OpCodeEnum.Ldelem_I1:
				case OpCodeEnum.Ldelem_I2:
				case OpCodeEnum.Ldelem_I4:
				case OpCodeEnum.Ldelem_I8:
				case OpCodeEnum.Ldelem_R4:
				case OpCodeEnum.Ldelem_R8:
				case OpCodeEnum.Ldelem_Ref:
				case OpCodeEnum.Ldelem_U1:
				case OpCodeEnum.Ldelem_U2:
				case OpCodeEnum.Ldelem_U4:
				case OpCodeEnum.Ldind_I:
				case OpCodeEnum.Ldind_I1:
				case OpCodeEnum.Ldind_I2:
				case OpCodeEnum.Ldind_I4:
				case OpCodeEnum.Ldind_I8:
				case OpCodeEnum.Ldind_R4:
				case OpCodeEnum.Ldind_R8:
				case OpCodeEnum.Ldind_Ref:
				case OpCodeEnum.Ldind_U1:
				case OpCodeEnum.Ldind_U2:
				case OpCodeEnum.Ldind_U4:
				case OpCodeEnum.Ldlen:
				case OpCodeEnum.Ldloc_0:
				case OpCodeEnum.Ldloc_1:
				case OpCodeEnum.Ldloc_2:
				case OpCodeEnum.Ldloc_3:
				case OpCodeEnum.Ldnull:
				case OpCodeEnum.Localloc:
				case OpCodeEnum.Mul:
				case OpCodeEnum.Mul_Ovf:
				case OpCodeEnum.Mul_Ovf_Un:
				case OpCodeEnum.Neg:
				case OpCodeEnum.Nop:
				case OpCodeEnum.Not:
				case OpCodeEnum.Or:
				case OpCodeEnum.Pop:
				case OpCodeEnum.Prefix1:
				case OpCodeEnum.Prefix2:
				case OpCodeEnum.Prefix3:
				case OpCodeEnum.Prefix4:
				case OpCodeEnum.Prefix5:
				case OpCodeEnum.Prefix6:
				case OpCodeEnum.Prefix7:
				case OpCodeEnum.Prefixref:
				case OpCodeEnum.Readonly:
				case OpCodeEnum.Refanytype:
				case OpCodeEnum.Rem:
				case OpCodeEnum.Rem_Un:
				case OpCodeEnum.Ret:
				case OpCodeEnum.Rethrow:
				case OpCodeEnum.Shl:
				case OpCodeEnum.Shr:
				case OpCodeEnum.Shr_Un:
				case OpCodeEnum.Stelem_I:
				case OpCodeEnum.Stelem_I1:
				case OpCodeEnum.Stelem_I2:
				case OpCodeEnum.Stelem_I4:
				case OpCodeEnum.Stelem_I8:
				case OpCodeEnum.Stelem_R4:
				case OpCodeEnum.Stelem_R8:
				case OpCodeEnum.Stelem_Ref:
				case OpCodeEnum.Stind_I:
				case OpCodeEnum.Stind_I1:
				case OpCodeEnum.Stind_I2:
				case OpCodeEnum.Stind_I4:
				case OpCodeEnum.Stind_I8:
				case OpCodeEnum.Stind_R4:
				case OpCodeEnum.Stind_R8:
				case OpCodeEnum.Stind_Ref:
				case OpCodeEnum.Stloc_0:
				case OpCodeEnum.Stloc_1:
				case OpCodeEnum.Stloc_2:
				case OpCodeEnum.Stloc_3:
				case OpCodeEnum.Sub:
				case OpCodeEnum.Sub_Ovf:
				case OpCodeEnum.Sub_Ovf_Un:
				case OpCodeEnum.Switch:
				case OpCodeEnum.Tailcall:
				case OpCodeEnum.Throw:
				case OpCodeEnum.Volatile:
				case OpCodeEnum.Xor:
					return 0;
				case OpCodeEnum.Beq_S:
				case OpCodeEnum.Bge_S:
				case OpCodeEnum.Bge_Un_S:
				case OpCodeEnum.Bgt_S:
				case OpCodeEnum.Bgt_Un_S:
				case OpCodeEnum.Ble_S:
				case OpCodeEnum.Ble_Un_S:
				case OpCodeEnum.Blt_S:
				case OpCodeEnum.Blt_Un_S:
				case OpCodeEnum.Bne_Un_S:
				case OpCodeEnum.Br_S:
				case OpCodeEnum.Brfalse_S:
				case OpCodeEnum.Brtrue_S:
				case OpCodeEnum.Ldarg_S:
				case OpCodeEnum.Ldarga_S:
				case OpCodeEnum.Ldc_I4_S:
				case OpCodeEnum.Ldloc_S:
				case OpCodeEnum.Ldloca_S:
				case OpCodeEnum.Leave_S:
				case OpCodeEnum.Starg_S:
				case OpCodeEnum.Stloc_S:
				case OpCodeEnum.Unaligned:
					return 8;
				case OpCodeEnum.Ldarg:
				case OpCodeEnum.Ldarga:
				case OpCodeEnum.Ldloc:
				case OpCodeEnum.Ldloca:
				case OpCodeEnum.Starg:
				case OpCodeEnum.Stloc:
					return 16;
				case OpCodeEnum.Beq:
				case OpCodeEnum.Bge:
				case OpCodeEnum.Bge_Un:
				case OpCodeEnum.Bgt:
				case OpCodeEnum.Bgt_Un:
				case OpCodeEnum.Ble:
				case OpCodeEnum.Ble_Un:
				case OpCodeEnum.Blt:
				case OpCodeEnum.Blt_Un:
				case OpCodeEnum.Bne_Un:
				case OpCodeEnum.Box:
				case OpCodeEnum.Br:
				case OpCodeEnum.Brfalse:
				case OpCodeEnum.Brtrue:
				case OpCodeEnum.Call:
				case OpCodeEnum.Calli:
				case OpCodeEnum.Callvirt:
				case OpCodeEnum.Castclass:
				case OpCodeEnum.Constrained:
				case OpCodeEnum.Cpobj:
				case OpCodeEnum.Initobj:
				case OpCodeEnum.Isinst:
				case OpCodeEnum.Jmp:
				case OpCodeEnum.Ldc_I4:
				case OpCodeEnum.Ldc_R4:
				case OpCodeEnum.Ldelem:
				case OpCodeEnum.Ldelema:
				case OpCodeEnum.Ldfld:
				case OpCodeEnum.Ldflda:
				case OpCodeEnum.Ldftn:
				case OpCodeEnum.Ldobj:
				case OpCodeEnum.Ldsfld:
				case OpCodeEnum.Ldsflda:
				case OpCodeEnum.Ldstr:
				case OpCodeEnum.Ldtoken:
				case OpCodeEnum.Ldvirtftn:
				case OpCodeEnum.Leave:
				case OpCodeEnum.Mkrefany:
				case OpCodeEnum.Newarr:
				case OpCodeEnum.Newobj:
				case OpCodeEnum.Refanyval:
				case OpCodeEnum.Sizeof:
				case OpCodeEnum.Stelem:
				case OpCodeEnum.Stfld:
				case OpCodeEnum.Stobj:
				case OpCodeEnum.Stsfld:
				case OpCodeEnum.Unbox:
				case OpCodeEnum.Unbox_Any:
					return 32;
				case OpCodeEnum.Ldc_I8:
				case OpCodeEnum.Ldc_R8:
					return 64;
				default:
					throw new NotSupportedException("OpCode not supported: " + aOpCode.ToString());
			}
		}

		private static OpCodeEnum GetNonShortcutOpCode(OpCodeEnum aOpCode) {
			switch (aOpCode) {
				case OpCodeEnum.Beq_S:
					return OpCodeEnum.Beq;
				case OpCodeEnum.Bge_S:
					return OpCodeEnum.Bge;
				case OpCodeEnum.Bge_Un_S:
					return OpCodeEnum.Bge_Un;
				case OpCodeEnum.Bgt_S:
					return OpCodeEnum.Bgt;
				case OpCodeEnum.Bgt_Un_S:
					return OpCodeEnum.Bgt_Un;
				case OpCodeEnum.Ble_S:
					return OpCodeEnum.Ble;
				case OpCodeEnum.Ble_Un_S:
					return OpCodeEnum.Ble_Un;
				case OpCodeEnum.Blt_S:
					return OpCodeEnum.Blt;
				case OpCodeEnum.Blt_Un_S:
					return OpCodeEnum.Blt_Un;
				case OpCodeEnum.Bne_Un_S:
					return OpCodeEnum.Bne_Un;
				case OpCodeEnum.Br_S:
					return OpCodeEnum.Br;
				case OpCodeEnum.Brfalse_S:
					return OpCodeEnum.Brfalse;
				case OpCodeEnum.Brtrue_S:
					return OpCodeEnum.Brtrue;
				case OpCodeEnum.Ldarg_0:
					return OpCodeEnum.Ldarg;
				case OpCodeEnum.Ldarg_1:
					return OpCodeEnum.Ldarg;
				case OpCodeEnum.Ldarg_2:
					return OpCodeEnum.Ldarg;
				case OpCodeEnum.Ldarg_3:
					return OpCodeEnum.Ldarg;
				case OpCodeEnum.Ldarg_S:
					return OpCodeEnum.Ldarg;
				case OpCodeEnum.Ldarga_S:
					return OpCodeEnum.Ldarga;
				case OpCodeEnum.Ldc_I4_0:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_1:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_2:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_3:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_4:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_5:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_6:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_7:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_8:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_M1:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldc_I4_S:
					return OpCodeEnum.Ldc_I4;
				case OpCodeEnum.Ldloc_0:
					return OpCodeEnum.Ldloc;
				case OpCodeEnum.Ldloc_1:
					return OpCodeEnum.Ldloc;
				case OpCodeEnum.Ldloc_2:
					return OpCodeEnum.Ldloc;
				case OpCodeEnum.Ldloc_3:
					return OpCodeEnum.Ldloc;
				case OpCodeEnum.Ldloc_S:
					return OpCodeEnum.Ldloc;
				case OpCodeEnum.Ldloca_S:
					return OpCodeEnum.Ldloca;
				case OpCodeEnum.Leave_S:
					return OpCodeEnum.Leave;
				case OpCodeEnum.Starg_S:
					return OpCodeEnum.Starg;
				case OpCodeEnum.Stloc_0:
					return OpCodeEnum.Stloc;
				case OpCodeEnum.Stloc_1:
					return OpCodeEnum.Stloc;
				case OpCodeEnum.Stloc_2:
					return OpCodeEnum.Stloc;
				case OpCodeEnum.Stloc_3:
					return OpCodeEnum.Stloc;
				case OpCodeEnum.Stloc_S:
					return OpCodeEnum.Stloc;
				default:
					return aOpCode;
			}
		}

		private static long? GetShortcutOperand(OpCodeEnum aOpCode) {
			switch (aOpCode) {
				case OpCodeEnum.Ldarg_0:
					return 0;
				case OpCodeEnum.Ldarg_1:
					return 1;
				case OpCodeEnum.Ldarg_2:
					return 2;
				case OpCodeEnum.Ldarg_3:
					return 3;
				case OpCodeEnum.Ldc_I4_0:
					return 0;
				case OpCodeEnum.Ldc_I4_1:
					return 1;
				case OpCodeEnum.Ldc_I4_2:
					return 2;
				case OpCodeEnum.Ldc_I4_3:
					return 3;
				case OpCodeEnum.Ldc_I4_4:
					return 4;
				case OpCodeEnum.Ldc_I4_5:
					return 5;
				case OpCodeEnum.Ldc_I4_6:
					return 6;
				case OpCodeEnum.Ldc_I4_7:
					return 7;
				case OpCodeEnum.Ldc_I4_8:
					return 8;
				case OpCodeEnum.Ldc_I4_M1:
					return -1;
				case OpCodeEnum.Ldloc_0:
					return 0;
				case OpCodeEnum.Ldloc_1:
					return 1;
				case OpCodeEnum.Ldloc_2:
					return 2;
				case OpCodeEnum.Ldloc_3:
					return 3;
				case OpCodeEnum.Stloc_0:
					return 0;
				case OpCodeEnum.Stloc_1:
					return 1;
				case OpCodeEnum.Stloc_2:
					return 2;
				case OpCodeEnum.Stloc_3:
					return 3;
				default:
					return null;
			}
		}
	}
}
