package com.baislsl.decompiler.instruction;

import com.baislsl.decompiler.DecompileException;
import com.baislsl.decompiler.engine.Value;
import com.baislsl.decompiler.structure.constantPool.ClassTag;
import com.baislsl.decompiler.structure.constantPool.MethodrefTag;
import com.baislsl.decompiler.structure.constantPool.NameAndTypeTag;
import com.baislsl.decompiler.utils.descriptor.Descriptor;
import com.baislsl.decompiler.utils.descriptor.MethodDescriptor;
import com.baislsl.decompiler.utils.descriptor.VoidDescriptor;

import java.util.ArrayList;
import java.util.List;

public class INVOKESPECIAL extends Instruction {
    @Override
    public void exec() throws DecompileException {
        super.exec();
        MethodrefTag methodrefTag = (MethodrefTag) clazz.getConstantPool(get2u());
        NameAndTypeTag nameAndTypeIndexCp = (NameAndTypeTag) clazz.getConstantPool(methodrefTag.getNameAndTypeIndex());
        String descriptor = clazz.getUTF8Info(nameAndTypeIndexCp.getDescriptorIndex());
        MethodDescriptor methodDescriptor = new MethodDescriptor(descriptor);
        int cnt = methodDescriptor.getParamSize();
        Descriptor returnDescriptor = methodDescriptor.getReturnDescriptor();

        List<Value> parameters = new ArrayList<>();
        for (int i = 0; i < cnt; i++) {
            parameters.add(opStack.pop());
        }
        Value objectRef = opStack.pop();
        StringBuilder ans = new StringBuilder();
        StringBuilder param = new StringBuilder();
        if (parameters.size() != 0)
            param.append(parameters.get(0));
        for (int i = 1; i < parameters.size(); i++) {
            param.append(", ").append(parameters.get(i));
        }

        String methodName = methodrefTag.getName(clazz);
        if (methodName.contains("<init>")) {
            // constructor
            ans.append("new ")
                    .append(methodrefTag.getClassName(clazz))
                    .append("(")
                    .append(param)
                    .append(")");
            objectRef.setValue(ans.toString());
        } else if (isCallSuperClassMethod(objectRef, methodrefTag.getClassName(clazz))) {
            // super method
            ans.append("super")
                    .append(".")
                    .append(methodrefTag.getName(clazz))
                    .append("(")
                    .append(param)
                    .append(")");
            if (returnDescriptor instanceof VoidDescriptor) {
                result.append(ans).append(";\n");
            } else {
                opStack.push(new Value(ans.toString(), false));
            }
        } else {
            // private method
            ans.append(objectRef)
                    .append(".")
                    .append(methodrefTag.getName(clazz))
                    .append("(")
                    .append(param)
                    .append(")");
            if (returnDescriptor instanceof VoidDescriptor) {
                result.append(ans).append(";\n");
            } else {
                opStack.push(new Value(ans.toString(), false));
            }
        }


    }

    private boolean isCallSuperClassMethod(Value objectRef, String className) throws DecompileException {
        if (!objectRef.toString().equals("this"))
            return false;
        ClassTag superClassTag = (ClassTag) clazz.getConstantPool(clazz.getSuperClass());
        String name = clazz.getUTF8Info(superClassTag.getNameIndex()).replaceAll("/", ".");
        return name.equals(className);
    }
}

@@ -1825,16 +1825,290 @@
 tructor%0A
+            if (isCallSuperClassMethod(objectRef, methodrefTag.getClassName(clazz))) %7B%0A                // call super constructor%0A                result.append(%22super(%22)%0A                        .append(param)%0A                        .append(%22);%5Cn%22);%0A            %7D else %7B%0A    
         
@@ -2130,16 +2130,20 @@
 %22new %22)%0A
+    
         
@@ -2208,32 +2208,36 @@
                 
+    
 .append(%22(%22)%0A   
@@ -2225,32 +2225,36 @@
    .append(%22(%22)%0A
+    
                 
@@ -2284,32 +2284,36 @@
                 
+   
+ 
 .append(%22)%22);%0A  
@@ -2302,32 +2302,36 @@
   .append(%22)%22);%0A
+    
             obje
@@ -2358,24 +2358,38 @@
 oString());%0A
+            %7D%0A
         %7D el

update invokespecial to enable super constructor