package refdiff.evaluation;

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

public enum RefactoringType {

	RENAME_CLASS("Rename Class", "Rename Class (.+) renamed to (.+)"),
	MOVE_CLASS("Move Class", "Move Class (.+) moved to (.+)"),
	MOVE_RENAME_CLASS("Move And Rename Class", ".+"),
	EXTRACT_INTERFACE("Extract Interface", "Extract Interface (.+) from classes \\[(.+)\\]", 2),
	EXTRACT_SUPERCLASS("Extract Superclass", "Extract Superclass (.+) from classes \\[(.+)\\]", 2),

	RENAME_METHOD("Rename Method", "Rename Method (.+) renamed to (.+) in class (.+)"),
	CHANGE_METHOD_SIGNATURE("Change Method Signature", "Change Method Signature (.+) to (.+) in class (.+)"),
	PULL_UP_OPERATION("Pull Up Method", "Pull Up Method (.+) from class (.+) to (.+) from class (.+)", 1, 2),
	PUSH_DOWN_OPERATION("Push Down Method", "Push Down Method (.+) from class (.+) to (.+) from class (.+)", 3, 4),
	MOVE_OPERATION("Move Method", "Move Method (.+) from class (.+) to (.+) from class (.+)"),
	EXTRACT_OPERATION("Extract Method", "Extract Method (.+) extracted from (.+) in class (.+)", 2),
	INLINE_OPERATION("Inline Method", "Inline Method (.+) inlined to (.+) in class (.+)", 2),

	PULL_UP_ATTRIBUTE("Pull Up Attribute", "Pull Up Attribute (.+) from class (.+) to class (.+)", 2),
	PUSH_DOWN_ATTRIBUTE("Push Down Attribute", "Push Down Attribute (.+) from class (.+) to class (.+)", 3),
	MOVE_ATTRIBUTE("Move Attribute", "Move Attribute (.+) from class (.+) to class (.+)"),

	MOVE_CLASS_FOLDER("Move Class Folder", ".+"),
	//EXTRACT_SUPERTYPE("Extract Supertype", "Extract Supertype (.+) from classes \\[(.+)\\]", 2),
	MERGE_OPERATION("Merge Method", ".+"),
	EXTRACT_AND_MOVE_OPERATION("Extract And Move Method", ".+"),
	CONVERT_ANONYMOUS_CLASS_TO_TYPE("Convert Anonymous Class to Type", ".+"),
	INTRODUCE_POLYMORPHISM("Introduce Polymorphism", ".+"),
	RENAME_PACKAGE("Rename Package", "Rename Package (.+) to (.+)");

	private String displayName;
	private Pattern regex;
	private int[] aggregateGroups;

	private RefactoringType(String displayName, String regex, int ... aggregateGroups) {
		this.displayName = displayName;
		this.regex = Pattern.compile(regex);
		this.aggregateGroups = aggregateGroups;
	}
	
	public Pattern getRegex() {
		return regex;
	}
	
	public String getDisplayName() {
		return this.displayName;
	}
	
	public String getAbbreviation() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < this.displayName.length(); i++) {
			char c = this.displayName.charAt(i);
			if (Character.isLetter(c) && Character.isUpperCase(c)) {
				sb.append(c);
			}
		}
		return sb.toString();
	}
	
	public String aggregate(String refactoringDescription) {
		Matcher m = regex.matcher(refactoringDescription);
		if (m.matches()) {
			StringBuilder sb = new StringBuilder();
			int current = 0;
			int replace = 0;
			for (int g = 1; g <= m.groupCount(); g++) {
				sb.append(refactoringDescription, current, m.start(g));
				if (aggregateGroups.length > replace && g == aggregateGroups[replace]) {
					sb.append('*');
					replace++;
				} else {
					sb.append(refactoringDescription, m.start(g), m.end(g));
				}
				current = m.end(g);
			}
			sb.append(refactoringDescription, current, refactoringDescription.length());
			return sb.toString();
		} else {
			throw new RuntimeException("Pattern not matched: " + refactoringDescription);
		}
	}
	
	public static RefactoringType extractFromDescription(String refactoringDescription) {
		for (RefactoringType refType : RefactoringType.values()) {
			if (refactoringDescription.startsWith(refType.getDisplayName())) {
				return refType;
			}
		}
		throw new RuntimeException("Unknown refactoring type: " + refactoringDescription);
	}
	
	public String getGroup(String refactoringDescription, int group) {
		Matcher m = regex.matcher(refactoringDescription);
		if (m.matches()) {
			return m.group(group);
		} else {
			throw new RuntimeException("Pattern not matched: " + refactoringDescription);
		}
	}
	
	public static RefactoringType fromName(String name) {
		String lcName = name.toLowerCase();
		for (RefactoringType rt : RefactoringType.values()) {
			if (lcName.equals(rt.getDisplayName().toLowerCase())) {
				return rt;
			}
		}
		throw new IllegalArgumentException("refactoring type not known " + name);
	}
}

@@ -126,21 +126,19 @@
 e %7B%0D%0A%0D%0A%09
-RENAM
+MOV
 E_CLASS(
@@ -138,21 +138,19 @@
 _CLASS(%22
-Renam
+Mov
 e Class%22
@@ -152,21 +152,19 @@
 lass%22, %22
-Renam
+Mov
 e Class 
@@ -164,29 +164,27 @@
  Class (.+) 
-renam
+mov
 ed to (.+)%22)
@@ -192,33 +192,38 @@
 %0D%0A%09MOVE_
-CLASS
+OPERATION
 (%22Move 
-Class
+Method
 %22, %22Move
@@ -223,35 +223,62 @@
 , %22Move 
-Class (.+) moved to
+Method (.+) from class (.+) to (.+) from class
  (.+)%22),
@@ -323,32 +323,187 @@
 Class%22, %22.+%22),%0D%0A
+%09RENAME_CLASS(%22Rename Class%22, %22Rename Class (.+) renamed to (.+)%22),%0D%0A%09RENAME_METHOD(%22Rename Method%22, %22Rename Method (.+) renamed to (.+) in class (.+)%22),%0D%0A
 %09EXTRACT_INTERFA
@@ -685,94 +685,8 @@
 %0D%0A%0D%0A
-%09RENAME_METHOD(%22Rename Method%22, %22Rename Method (.+) renamed to (.+) in class (.+)%22),%0D%0A
 %09CHA
@@ -1015,101 +1015,8 @@
 ),%0D%0A
-%09MOVE_OPERATION(%22Move Method%22, %22Move Method (.+) from class (.+) to (.+) from class (.+)%22),%0D%0A
 %09EXT

Reorder refactorings