/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jetbrains.java.decompiler.code;

import org.jetbrains.java.decompiler.code.optinstructions.ALOAD;
import org.jetbrains.java.decompiler.code.optinstructions.ANEWARRAY;
import org.jetbrains.java.decompiler.code.optinstructions.ASTORE;
import org.jetbrains.java.decompiler.code.optinstructions.BIPUSH;
import org.jetbrains.java.decompiler.code.optinstructions.CHECKCAST;
import org.jetbrains.java.decompiler.code.optinstructions.DLOAD;
import org.jetbrains.java.decompiler.code.optinstructions.DSTORE;
import org.jetbrains.java.decompiler.code.optinstructions.FLOAD;
import org.jetbrains.java.decompiler.code.optinstructions.FSTORE;
import org.jetbrains.java.decompiler.code.optinstructions.GETFIELD;
import org.jetbrains.java.decompiler.code.optinstructions.GETSTATIC;
import org.jetbrains.java.decompiler.code.optinstructions.GOTO;
import org.jetbrains.java.decompiler.code.optinstructions.GOTO_W;
import org.jetbrains.java.decompiler.code.optinstructions.IINC;
import org.jetbrains.java.decompiler.code.optinstructions.ILOAD;
import org.jetbrains.java.decompiler.code.optinstructions.INSTANCEOF;
import org.jetbrains.java.decompiler.code.optinstructions.INVOKEDYNAMIC;
import org.jetbrains.java.decompiler.code.optinstructions.INVOKEINTERFACE;
import org.jetbrains.java.decompiler.code.optinstructions.INVOKESPECIAL;
import org.jetbrains.java.decompiler.code.optinstructions.INVOKESTATIC;
import org.jetbrains.java.decompiler.code.optinstructions.INVOKEVIRTUAL;
import org.jetbrains.java.decompiler.code.optinstructions.ISTORE;
import org.jetbrains.java.decompiler.code.optinstructions.JSR;
import org.jetbrains.java.decompiler.code.optinstructions.JSR_W;
import org.jetbrains.java.decompiler.code.optinstructions.LDC;
import org.jetbrains.java.decompiler.code.optinstructions.LDC2_W;
import org.jetbrains.java.decompiler.code.optinstructions.LDC_W;
import org.jetbrains.java.decompiler.code.optinstructions.LLOAD;
import org.jetbrains.java.decompiler.code.optinstructions.LOOKUPSWITCH;
import org.jetbrains.java.decompiler.code.optinstructions.LSTORE;
import org.jetbrains.java.decompiler.code.optinstructions.MULTIANEWARRAY;
import org.jetbrains.java.decompiler.code.optinstructions.NEW;
import org.jetbrains.java.decompiler.code.optinstructions.NEWARRAY;
import org.jetbrains.java.decompiler.code.optinstructions.PUTFIELD;
import org.jetbrains.java.decompiler.code.optinstructions.PUTSTATIC;
import org.jetbrains.java.decompiler.code.optinstructions.RET;
import org.jetbrains.java.decompiler.code.optinstructions.SIPUSH;
import org.jetbrains.java.decompiler.code.optinstructions.TABLESWITCH;

public class ConstantsUtil {

  public static String getName(int opcode) {
    return opcodeNames[opcode];
  }

  public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {

    Instruction instr = getInstructionInstance(opcode, bytecode_version);
    instr.wide = wide;
    instr.group = group;
    instr.bytecode_version = bytecode_version;
    instr.setOperands(operands);

    return instr;
  }

  private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
    try {
      Instruction instr;

      if ((opcode >= CodeConstants.opc_ifeq && opcode <= CodeConstants.opc_if_acmpne) || opcode == CodeConstants.opc_ifnull
          || opcode == CodeConstants.opc_ifnonnull) {
        instr = new IfInstruction();
      } else {

        Class cl = opcodeClasses[opcode];

        if (opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {
          cl = null; // instruction unused in Java 6 and before
        }

        if (cl == null) {
          instr = new Instruction();
        } else {
          instr = (Instruction) cl.newInstance();
        }
      }

      instr.opcode = opcode;
      return instr;
    } catch (Exception ex) {
      return null;
    }
  }

  private static final String[] opcodeNames = { "nop", //    "nop",
      "aconst_null", //    "aconst_null",
      "iconst_m1", //    "iconst_m1",
      "iconst_0", //    "iconst_0",
      "iconst_1", //    "iconst_1",
      "iconst_2", //    "iconst_2",
      "iconst_3", //    "iconst_3",
      "iconst_4", //    "iconst_4",
      "iconst_5", //    "iconst_5",
      "lconst_0", //    "lconst_0",
      "lconst_1", //    "lconst_1",
      "fconst_0", //    "fconst_0",
      "fconst_1", //    "fconst_1",
      "fconst_2", //    "fconst_2",
      "dconst_0", //    "dconst_0",
      "dconst_1", //    "dconst_1",
      "bipush", //    "bipush",
      "sipush", //    "sipush",
      "ldc", //    "ldc",
      "ldc_w", //    "ldc_w",
      "ldc2_w", //    "ldc2_w",
      "iload", //    "iload",
      "lload", //    "lload",
      "fload", //    "fload",
      "dload", //    "dload",
      "aload", //    "aload",
      "iload_0", //    "iload_0",
      "iload_1", //    "iload_1",
      "iload_2", //    "iload_2",
      "iload_3", //    "iload_3",
      "lload_0", //    "lload_0",
      "lload_1", //    "lload_1",
      "lload_2", //    "lload_2",
      "lload_3", //    "lload_3",
      "fload_0", //    "fload_0",
      "fload_1", //    "fload_1",
      "fload_2", //    "fload_2",
      "fload_3", //    "fload_3",
      "dload_0", //    "dload_0",
      "dload_1", //    "dload_1",
      "dload_2", //    "dload_2",
      "dload_3", //    "dload_3",
      "aload_0", //    "aload_0",
      "aload_1", //    "aload_1",
      "aload_2", //    "aload_2",
      "aload_3", //    "aload_3",
      "iaload", //    "iaload",
      "laload", //    "laload",
      "faload", //    "faload",
      "daload", //    "daload",
      "aaload", //    "aaload",
      "baload", //    "baload",
      "caload", //    "caload",
      "saload", //    "saload",
      "istore", //    "istore",
      "lstore", //    "lstore",
      "fstore", //    "fstore",
      "dstore", //    "dstore",
      "astore", //    "astore",
      "istore_0", //    "istore_0",
      "istore_1", //    "istore_1",
      "istore_2", //    "istore_2",
      "istore_3", //    "istore_3",
      "lstore_0", //    "lstore_0",
      "lstore_1", //    "lstore_1",
      "lstore_2", //    "lstore_2",
      "lstore_3", //    "lstore_3",
      "fstore_0", //    "fstore_0",
      "fstore_1", //    "fstore_1",
      "fstore_2", //    "fstore_2",
      "fstore_3", //    "fstore_3",
      "dstore_0", //    "dstore_0",
      "dstore_1", //    "dstore_1",
      "dstore_2", //    "dstore_2",
      "dstore_3", //    "dstore_3",
      "astore_0", //    "astore_0",
      "astore_1", //    "astore_1",
      "astore_2", //    "astore_2",
      "astore_3", //    "astore_3",
      "iastore", //    "iastore",
      "lastore", //    "lastore",
      "fastore", //    "fastore",
      "dastore", //    "dastore",
      "aastore", //    "aastore",
      "bastore", //    "bastore",
      "castore", //    "castore",
      "sastore", //    "sastore",
      "pop", //    "pop",
      "pop2", //    "pop2",
      "dup", //    "dup",
      "dup_x1", //    "dup_x1",
      "dup_x2", //    "dup_x2",
      "dup2", //    "dup2",
      "dup2_x1", //    "dup2_x1",
      "dup2_x2", //    "dup2_x2",
      "swap", //    "swap",
      "iadd", //    "iadd",
      "ladd", //    "ladd",
      "fadd", //    "fadd",
      "dadd", //    "dadd",
      "isub", //    "isub",
      "lsub", //    "lsub",
      "fsub", //    "fsub",
      "dsub", //    "dsub",
      "imul", //    "imul",
      "lmul", //    "lmul",
      "fmul", //    "fmul",
      "dmul", //    "dmul",
      "idiv", //    "idiv",
      "ldiv", //    "ldiv",
      "fdiv", //    "fdiv",
      "ddiv", //    "ddiv",
      "irem", //    "irem",
      "lrem", //    "lrem",
      "frem", //    "frem",
      "drem", //    "drem",
      "ineg", //    "ineg",
      "lneg", //    "lneg",
      "fneg", //    "fneg",
      "dneg", //    "dneg",
      "ishl", //    "ishl",
      "lshl", //    "lshl",
      "ishr", //    "ishr",
      "lshr", //    "lshr",
      "iushr", //    "iushr",
      "lushr", //    "lushr",
      "iand", //    "iand",
      "land", //    "land",
      "ior", //    "ior",
      "lor", //    "lor",
      "ixor", //    "ixor",
      "lxor", //    "lxor",
      "iinc", //    "iinc",
      "i2l", //    "i2l",
      "i2f", //    "i2f",
      "i2d", //    "i2d",
      "l2i", //    "l2i",
      "l2f", //    "l2f",
      "l2d", //    "l2d",
      "f2i", //    "f2i",
      "f2l", //    "f2l",
      "f2d", //    "f2d",
      "d2i", //    "d2i",
      "d2l", //    "d2l",
      "d2f", //    "d2f",
      "i2b", //    "i2b",
      "i2c", //    "i2c",
      "i2s", //    "i2s",
      "lcmp", //    "lcmp",
      "fcmpl", //    "fcmpl",
      "fcmpg", //    "fcmpg",
      "dcmpl", //    "dcmpl",
      "dcmpg", //    "dcmpg",
      "ifeq", //    "ifeq",
      "ifne", //    "ifne",
      "iflt", //    "iflt",
      "ifge", //    "ifge",
      "ifgt", //    "ifgt",
      "ifle", //    "ifle",
      "if_icmpeq", //    "if_icmpeq",
      "if_icmpne", //    "if_icmpne",
      "if_icmplt", //    "if_icmplt",
      "if_icmpge", //    "if_icmpge",
      "if_icmpgt", //    "if_icmpgt",
      "if_icmple", //    "if_icmple",
      "if_acmpeq", //    "if_acmpeq",
      "if_acmpne", //    "if_acmpne",
      "goto", //    "goto",
      "jsr", //    "jsr",
      "ret", //    "ret",
      "tableswitch", //    "tableswitch",
      "lookupswitch", //    "lookupswitch",
      "ireturn", //    "ireturn",
      "lreturn", //    "lreturn",
      "freturn", //    "freturn",
      "dreturn", //    "dreturn",
      "areturn", //    "areturn",
      "return", //    "return",
      "getstatic", //    "getstatic",
      "putstatic", //    "putstatic",
      "getfield", //    "getfield",
      "putfield", //    "putfield",
      "invokevirtual", //    "invokevirtual",
      "invokespecial", //    "invokespecial",
      "invokestatic", //    "invokestatic",
      "invokeinterface", //    "invokeinterface",
      //"xxxunusedxxx",		//    "xxxunusedxxx", Java 6 and before
      "invokedynamic", //    "invokedynamic", Java 7 and later
      "new", //    "new",
      "newarray", //    "newarray",
      "anewarray", //    "anewarray",
      "arraylength", //    "arraylength",
      "athrow", //    "athrow",
      "checkcast", //    "checkcast",
      "instanceof", //    "instanceof",
      "monitorenter", //    "monitorenter",
      "monitorexit", //    "monitorexit",
      "wide", //    "wide",
      "multianewarray", //    "multianewarray",
      "ifnull", //    "ifnull",
      "ifnonnull", //    "ifnonnull",
      "goto_w", //    "goto_w",
      "jsr_w" //    "jsr_w"
  };

  private static final Class[] opcodeClasses = { null, //    "nop",
      null, //    "aconst_null",
      null, //    "iconst_m1",
      null, //    "iconst_0",
      null, //    "iconst_1",
      null, //    "iconst_2",
      null, //    "iconst_3",
      null, //    "iconst_4",
      null, //    "iconst_5",
      null, //    "lconst_0",
      null, //    "lconst_1",
      null, //    "fconst_0",
      null, //    "fconst_1",
      null, //    "fconst_2",
      null, //    "dconst_0",
      null, //    "dconst_1",
      BIPUSH.class, //    "bipush",
      SIPUSH.class, //    "sipush",
      LDC.class, //    "ldc",
      LDC_W.class, //    "ldc_w",
      LDC2_W.class, //    "ldc2_w",
      ILOAD.class, //    "iload",
      LLOAD.class, //    "lload",
      FLOAD.class, //    "fload",
      DLOAD.class, //    "dload",
      ALOAD.class, //    "aload",
      null, //    "iload_0",
      null, //    "iload_1",
      null, //    "iload_2",
      null, //    "iload_3",
      null, //    "lload_0",
      null, //    "lload_1",
      null, //    "lload_2",
      null, //    "lload_3",
      null, //    "fload_0",
      null, //    "fload_1",
      null, //    "fload_2",
      null, //    "fload_3",
      null, //    "dload_0",
      null, //    "dload_1",
      null, //    "dload_2",
      null, //    "dload_3",
      null, //    "aload_0",
      null, //    "aload_1",
      null, //    "aload_2",
      null, //    "aload_3",
      null, //    "iaload",
      null, //    "laload",
      null, //    "faload",
      null, //    "daload",
      null, //    "aaload",
      null, //    "baload",
      null, //    "caload",
      null, //    "saload",
      ISTORE.class, //    "istore",
      LSTORE.class, //    "lstore",
      FSTORE.class, //    "fstore",
      DSTORE.class, //    "dstore",
      ASTORE.class, //    "astore",
      null, //    "istore_0",
      null, //    "istore_1",
      null, //    "istore_2",
      null, //    "istore_3",
      null, //    "lstore_0",
      null, //    "lstore_1",
      null, //    "lstore_2",
      null, //    "lstore_3",
      null, //    "fstore_0",
      null, //    "fstore_1",
      null, //    "fstore_2",
      null, //    "fstore_3",
      null, //    "dstore_0",
      null, //    "dstore_1",
      null, //    "dstore_2",
      null, //    "dstore_3",
      null, //    "astore_0",
      null, //    "astore_1",
      null, //    "astore_2",
      null, //    "astore_3",
      null, //    "iastore",
      null, //    "lastore",
      null, //    "fastore",
      null, //    "dastore",
      null, //    "aastore",
      null, //    "bastore",
      null, //    "castore",
      null, //    "sastore",
      null, //    "pop",
      null, //    "pop2",
      null, //    "dup",
      null, //    "dup_x1",
      null, //    "dup_x2",
      null, //    "dup2",
      null, //    "dup2_x1",
      null, //    "dup2_x2",
      null, //    "swap",
      null, //    "iadd",
      null, //    "ladd",
      null, //    "fadd",
      null, //    "dadd",
      null, //    "isub",
      null, //    "lsub",
      null, //    "fsub",
      null, //    "dsub",
      null, //    "imul",
      null, //    "lmul",
      null, //    "fmul",
      null, //    "dmul",
      null, //    "idiv",
      null, //    "ldiv",
      null, //    "fdiv",
      null, //    "ddiv",
      null, //    "irem",
      null, //    "lrem",
      null, //    "frem",
      null, //    "drem",
      null, //    "ineg",
      null, //    "lneg",
      null, //    "fneg",
      null, //    "dneg",
      null, //    "ishl",
      null, //    "lshl",
      null, //    "ishr",
      null, //    "lshr",
      null, //    "iushr",
      null, //    "lushr",
      null, //    "iand",
      null, //    "land",
      null, //    "ior",
      null, //    "lor",
      null, //    "ixor",
      null, //    "lxor",
      IINC.class, //    "iinc",
      null, //    "i2l",
      null, //    "i2f",
      null, //    "i2d",
      null, //    "l2i",
      null, //    "l2f",
      null, //    "l2d",
      null, //    "f2i",
      null, //    "f2l",
      null, //    "f2d",
      null, //    "d2i",
      null, //    "d2l",
      null, //    "d2f",
      null, //    "i2b",
      null, //    "i2c",
      null, //    "i2s",
      null, //    "lcmp",
      null, //    "fcmpl",
      null, //    "fcmpg",
      null, //    "dcmpl",
      null, //    "dcmpg",
      null, //    "ifeq",
      null, //    "ifne",
      null, //    "iflt",
      null, //    "ifge",
      null, //    "ifgt",
      null, //    "ifle",
      null, //    "if_icmpeq",
      null, //    "if_icmpne",
      null, //    "if_icmplt",
      null, //    "if_icmpge",
      null, //    "if_icmpgt",
      null, //    "if_icmple",
      null, //    "if_acmpeq",
      null, //    "if_acmpne",
      GOTO.class, //    "goto",
      JSR.class, //    "jsr",
      RET.class, //    "ret",
      TABLESWITCH.class, //    "tableswitch",
      LOOKUPSWITCH.class, //    "lookupswitch",
      null, //    "ireturn",
      null, //    "lreturn",
      null, //    "freturn",
      null, //    "dreturn",
      null, //    "areturn",
      null, //    "return",
      GETSTATIC.class, //    "getstatic",
      PUTSTATIC.class, //    "putstatic",
      GETFIELD.class, //    "getfield",
      PUTFIELD.class, //    "putfield",
      INVOKEVIRTUAL.class, //    "invokevirtual",
      INVOKESPECIAL.class, //    "invokespecial",
      INVOKESTATIC.class, //    "invokestatic",
      INVOKEINTERFACE.class, //    "invokeinterface",
      INVOKEDYNAMIC.class, //    "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
      NEW.class, //    "new",
      NEWARRAY.class, //    "newarray",
      ANEWARRAY.class, //    "anewarray",
      null, //    "arraylength",
      null, //    "athrow",
      CHECKCAST.class, //    "checkcast",
      INSTANCEOF.class, //    "instanceof",
      null, //    "monitorenter",
      null, //    "monitorexit",
      null, //    "wide",
      MULTIANEWARRAY.class, //    "multianewarray",
      null, //    "ifnull",
      null, //    "ifnonnull",
      GOTO_W.class, //    "goto_w",
      JSR_W.class //    "jsr_w"
  };
}
