package com.ninty.classfile;

import com.ninty.classfile.constantpool.ConstantPoolInfos;
import com.sun.org.apache.bcel.internal.classfile.ClassFormatException;

import java.nio.ByteBuffer;
import java.util.Arrays;

/**
 * Created by ninty on 2017/7/9.
 */
public class ClassFile {
    int magic; //u4
    int minorVersion; //u2
    int majorVersion; //u2
    ConstantPoolInfos constantPoolInfos;
    int accessFlags; //u2
    int thisClass; // u2
    int superClass; //u2
    InterfaceInfo[] interfaceInfos;
    MemberInfo[] filedInfos;
    MemberInfo[] methodInfos;
    AttributeInfo[] attributeInfos;

    public ClassFile(byte[] datas) {
        resolve(datas);
    }

    private void resolve(byte[] datas) {
        ByteBuffer bb = ByteBuffer.wrap(datas);
        magic = bb.getInt();
        checkMagic();
        minorVersion = bb.getChar();
        majorVersion = bb.getChar();
        checkVersion();
        fillConstantPoll(bb);
        accessFlags = bb.getChar();
        thisClass = bb.getChar();
        superClass = bb.getChar();
        fillInterfaceInfos(bb);
        fillFiledInfos(bb);
        fillMethodInfos(bb);
        fillAttributeInfo(bb);
    }

    private void checkMagic() {
        if (magic != 0xCAFEBABE) {
            throw new ClassFormatException("shoud start with 0xCAFEBABE");
        }
    }

    private void checkVersion() {
        switch (majorVersion) {
            case 45:
                return;
            case 46:
            case 47:
            case 48:
            case 49:
            case 50:
            case 51:
            case 52:
                if (minorVersion == 0) {
                    return;
                }
        }
        throw new UnsupportedClassVersionError("majorVersion:" + majorVersion + ", minorVersion:" + minorVersion);
    }

    private void fillConstantPoll(ByteBuffer bb) {
        constantPoolInfos = new ConstantPoolInfos(bb);
    }

    private void fillInterfaceInfos(ByteBuffer bb) {
        int interfaceCount = bb.getChar();
        interfaceInfos = new InterfaceInfo[interfaceCount];
    }

    private void fillFiledInfos(ByteBuffer bb) {
        int filedCount = bb.getChar();
        filedInfos = new MemberInfo[filedCount];
    }

    private void fillMethodInfos(ByteBuffer bb) {
        int methodCount = bb.getChar();
        methodInfos = new MemberInfo[methodCount];
    }

    private void fillAttributeInfo(ByteBuffer bb) {
        int attributeCount = bb.getChar();
        attributeInfos = new AttributeInfo[attributeCount];
    }

    @Override
    public String toString() {
        return "ClassFile{" +
                "magic=" + magic +
                ", minorVersion=" + minorVersion +
                ", majorVersion=" + majorVersion +
                ", accessFlags=" + accessFlags +
                ", thisClass=" + thisClass +
                ", superClass=" + superClass +
                ", interfaceInfos=" + Arrays.toString(interfaceInfos) +
                ", filedInfos=" + Arrays.toString(filedInfos) +
                ", methodInfos=" + Arrays.toString(methodInfos) +
                ", attributeInfos=" + Arrays.toString(attributeInfos) +
                '}';
    }
}


@@ -372,31 +372,17 @@
 lInfos c
-onstantPoolInfo
+p
 s;%0A    i
@@ -410,36 +410,36 @@
     
-int thisClass; // u2
+String className;
 %0A    
+Str
 in
-t
+g
  sup
@@ -449,32 +449,24 @@
 lass
-; //u2%0A    InterfaceInfo
+Name;%0A    String
 %5B%5D i
@@ -473,20 +473,20 @@
 nterface
-Info
+Name
 s;%0A    M
@@ -542,44 +542,8 @@
 fos;
-%0A    AttributeInfo%5B%5D attributeInfos;
 %0A%0A  
@@ -924,20 +924,37 @@
     
-thisClass = 
+className = cps.getClassName(
 bb.g
@@ -953,32 +953,33 @@
 ame(bb.getChar()
+)
 ;%0A        superC
@@ -982,19 +982,45 @@
 perClass
- = 
+Name = cps.getSuperClassName(
 bb.getCh
@@ -1015,32 +1015,33 @@
 ame(bb.getChar()
+)
 ;%0A        fillIn
@@ -1119,39 +1119,8 @@
 b);%0A
-        fillAttributeInfo(bb);%0A
     
@@ -1818,31 +1818,17 @@
        c
-onstantPoolInfo
+p
 s = new 
@@ -1970,28 +1970,28 @@
 nterface
-Info
+Name
 s = new 
 Interfac
@@ -1986,38 +1986,156 @@
 new 
-InterfaceInfo%5BinterfaceCount%5D;
+String%5BinterfaceCount%5D;%0A        for (int i = 0; i %3C interfaceCount; i++) %7B%0A            interfaceNames%5Bi%5D = cps.getClassName(bb.getChar());%0A        %7D
 %0A   
@@ -2434,170 +2434,8 @@
  %7D%0A%0A
-    private void fillAttributeInfo(ByteBuffer bb) %7B%0A        int attributeCount = bb.getChar();%0A        attributeInfos = new AttributeInfo%5BattributeCount%5D;%0A    %7D%0A%0A
     
@@ -2724,25 +2724,25 @@
 ass=%22 + 
-thisClass
+className
  +%0A     
@@ -2780,16 +2780,20 @@
 perClass
+Name
  +%0A     
@@ -2850,20 +2850,20 @@
 nterface
-Info
+Name
 s) +%0A   
@@ -2993,80 +2993,8 @@
 ) +%0A
-                %22, attributeInfos=%22 + Arrays.toString(attributeInfos) +%0A
     

resolve name directly if it's possible