package sophomore.classfile;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author inagaki
 */
public class DescriptorParser {
	/**
	 *
	 */
	private static final String objPattern  = "L[a-z\\\\.]*[0-9a-zA-Z_\\$\\.]+";

	/**
	 *
	 * @param desc
	 * @return
	 */
	public static String parse(String desc) {
		String primPattern = "(B|\\[B|C|\\[C|D|\\[D|F|\\[F|V|I|\\[I"
								+ "|J|\\[J|S|\\[S|Z|\\[Z|\\(|\\))";
		desc = desc.replace("/", ".");
		String obj = "(" + objPattern + "|\\[" + objPattern + ")";
		Matcher m = Pattern.compile(obj + "|" + primPattern).matcher(desc);
		StringBuilder sb = new StringBuilder();
		while(m.find()) {
			String s = m.group();
			if(s.startsWith("[")) { // primitive array
				if(s.length() == 2) {
					sb.append(parseType(s.substring(1))).append("[]");
				} else { // object array
					sb.append(s.subSequence(2, s.length())).append("[]");
				}
			} else if(s.startsWith("L")) { // object
				sb.append(s.subSequence(1, s.length()));
			} else if(s.equals("V")) { // void
				sb.append(parseType(s));
			} else if(!parseType(s).equals("")) { // primitive
				sb.append(parseType(s));
			} else if(s.matches("\\(|\\)")) {
				sb.append(s);
				continue;
			} else {
				continue;
			}
			sb.append(",");
		}
		return sb.toString().substring(0, sb.toString().length()-1);
	}

	/**
	 *
	 * @param desc
	 * @return
	 */
	public static String[] parseImportClass(String desc) {
		List<String> classes = new ArrayList<>();
		desc = desc.replace("/", ".");
		Matcher m = Pattern.compile("(" + objPattern + ")").matcher(desc);
		while(m.find()) {
			String s = m.group();
			if(s.startsWith("L") && !s.matches("Ljava\\.lang\\.[A-Z][a-zA-Z\\.]+")) {
				classes.add(s.substring(1, s.length()));
			}
		}
		if(classes.isEmpty()) {
			return new String[0];
		}
		return classes.toArray(new String[0]);
	}

	/**
	 *
	 * @param head
	 * @return
	 */
	private static String parseType(String head) {
		switch(head) {
			case "B": return "byte";
			case "C": return "char";
			case "D": return "double";
			case "F": return "float";
			case "I": return "int";
			case "J": return "long";
			case "S": return "short";
			case "Z": return "boolean";
			case "V": return "void";
			default : return "";
		}
	}
}
@@ -486,16 +486,53 @@
 %7C%5C%5C))%22;%0A
+%09%09String genericsPattern = %22T%5BA-Z%5D%22;%0A
 %09%09desc =
@@ -617,16 +617,87 @@
  + %22)%22;%0A
+%09%09String gen = %22(%22 + genericsPattern + %22%7C%5C%5C%5B%22 + genericsPattern + %22)%22;%0A
 %09%09Matche
@@ -741,16 +741,28 @@
 mPattern
+ + %22%7C%22 + gen
 ).matche
@@ -1008,16 +1008,28 @@
  object 
+or generics 
 array%0A%09%09
@@ -1121,16 +1121,37 @@
 ith(%22L%22)
+ %7C%7C s.startsWith(%22T%22)
 ) %7B // o
@@ -1155,16 +1155,28 @@
 / object
+ or generics
 %0A%09%09%09%09sb.
@@ -2445,18 +2445,117 @@
 %0A%09%09%09
-default : 
+case %22(%22:%0A%09%09%09case %22)%22: return %22%22;%0A%09%09%09default :%0A%09%09%09%09System.out.println(%22%3E%3E%3E unknown type %5C%22%22+head+%22%5C%22.%22);%0A%09%09%09%09
 retu

modify for generics type.