package krasa.formatter.plugin;
import java.util.*;
import krasa.formatter.utils.StringUtils;
import com.intellij.openapi.util.MultiValuesMap;
/*not thread safe*/
class ImportsSorter450 implements ImportsSorter {
private List<String> template = new ArrayList<String>();
private MultiValuesMap<String, String> matchingImports = new MultiValuesMap<String, String>();
private ArrayList<String> notMatching = new ArrayList<String>();
private Set<String> allImportOrderItems = new HashSet<String>();
private Comparator<String> comparator;
static List<String> sort(List<String> imports, List<String> importsOrder) {
ImportsSorter importsSorter = new ImportsSorter450(importsOrder);
return importsSorter.sort(imports);
}
@Override
public List<String> sort(List<String> imports) {
filterMatchingImports(imports);
mergeNotMatchingItems(false);
mergeNotMatchingItems(true);
mergeMatchingItems();
return getResult();
}
public ImportsSorter450(List<String> importOrder) {
List<String> importOrderCopy = new ArrayList<String>(importOrder);
normalizeStaticOrderItems(importOrderCopy);
putStaticItemIfNotExists(importOrderCopy);
template.addAll(importOrderCopy);
this.allImportOrderItems.addAll(importOrderCopy);
comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
String containerName1 = allImportOrderItems.contains(o1) ? o1 : StringUtils.getPackage(o1);
String simpleName1 = allImportOrderItems.contains(o1) ? "" : StringUtils.getSimpleName(o1);
String containerName2 = allImportOrderItems.contains(o2) ? o2 : StringUtils.getPackage(o2);
String simpleName2 = allImportOrderItems.contains(o2) ? "" : StringUtils.getSimpleName(o2);
int i = containerName1.compareTo(containerName2);
if (i == 0) {
i = simpleName1.compareTo(simpleName2);
}
return i;
}
};
}
private void putStaticItemIfNotExists(List<String> allImportOrderItems) {
boolean contains = false;
int indexOfFirstStatic = 0;
for (int i = 0; i < allImportOrderItems.size(); i++) {
String allImportOrderItem = allImportOrderItems.get(i);
if (allImportOrderItem.equals("static ")) {
contains = true;
}
if (allImportOrderItem.startsWith("static ")) {
indexOfFirstStatic = i;
}
}
if (!contains) {
allImportOrderItems.add(indexOfFirstStatic, "static ");
}
}
private void normalizeStaticOrderItems(List<String> allImportOrderItems) {
for (int i = 0; i < allImportOrderItems.size(); i++) {
String s = allImportOrderItems.get(i);
if (s.startsWith("\\#") || s.startsWith("#")) {
allImportOrderItems.set(i, s.replace("\\#", "static ").replace("#", "static "));
}
}
}
/**
* returns not matching items and initializes internal state
*/
private void filterMatchingImports(List<String> imports) {
for (String anImport : imports) {
String orderItem = getBestMatchingImportOrderItem(anImport);
if (orderItem != null) {
matchingImports.put(orderItem, anImport);
} else {
notMatching.add(anImport);
}
}
notMatching.addAll(allImportOrderItems);
}
private String getBestMatchingImportOrderItem(String anImport) {
String matchingImport = null;
for (String orderItem : allImportOrderItems) {
if (anImport.startsWith(orderItem)) {
if (matchingImport == null) {
matchingImport = orderItem;
} else {
matchingImport = StringUtils.betterMatching(matchingImport, orderItem, anImport);
}
}
}
return matchingImport;
}
/**
* not matching means it does not match any order item, so it will be appended before or after order items
*/
private void mergeNotMatchingItems(boolean staticItems) {
Collections.sort(notMatching, comparator);
int firstIndexOfOrderItem = getFirstIndexOfOrderItem(notMatching, staticItems);
int indexOfOrderItem = 0;
for (int i = 0; i < notMatching.size(); i++) {
String notMatchingItem = notMatching.get(i);
if (!matchesStatic(staticItems, notMatchingItem)) {
continue;
}
boolean isOrderItem = isOrderItem(notMatchingItem, staticItems);
if (isOrderItem) {
indexOfOrderItem = template.indexOf(notMatchingItem);
} else {
if (indexOfOrderItem == 0 && firstIndexOfOrderItem != 0) {
// insert before alphabetically first order item
template.add(firstIndexOfOrderItem, notMatchingItem);
firstIndexOfOrderItem++;
} else if (firstIndexOfOrderItem == 0) {
// no order is specified
if (template.size() > 0 && (template.get(template.size() - 1).startsWith("static"))) {
// insert N after last static import
template.add(ImportSorterAdapter.N);
}
template.add(notMatchingItem);
} else {
// insert after the previous order item
template.add(indexOfOrderItem + 1, notMatchingItem);
indexOfOrderItem++;
}
}
}
}
private boolean isOrderItem(String notMatchingItem, boolean staticItems) {
boolean contains = allImportOrderItems.contains(notMatchingItem);
return contains && matchesStatic(staticItems, notMatchingItem);
}
/**
* gets first order item from sorted input list, and finds out it's index in template.
*/
private int getFirstIndexOfOrderItem(List<String> notMatching, boolean staticItems) {
int firstIndexOfOrderItem = 0;
for (int i = 0; i < notMatching.size(); i++) {
String notMatchingItem = notMatching.get(i);
if (!matchesStatic(staticItems, notMatchingItem)) {
continue;
}
boolean isOrderItem = isOrderItem(notMatchingItem, staticItems);
if (isOrderItem) {
firstIndexOfOrderItem = template.indexOf(notMatchingItem);
break;
}
}
return firstIndexOfOrderItem;
}
private boolean matchesStatic(boolean staticItems, String notMatchingItem) {
boolean isStatic = notMatchingItem.startsWith("static ");
return (isStatic && staticItems) || (!isStatic && !staticItems);
}
private void mergeMatchingItems() {
for (int i = 0; i < template.size(); i++) {
String item = template.get(i);
if (allImportOrderItems.contains(item)) {
// find matching items for order item
Collection<String> strings = matchingImports.get(item);
if (strings == null || strings.isEmpty()) {
// if there is none, just remove order item
template.remove(i);
i--;
continue;
}
ArrayList<String> matchingItems = new ArrayList<String>(strings);
Collections.sort(matchingItems, comparator);
// replace order item by matching import statements
// this is a mess and it is only a luck that it works :-]
template.remove(i);
if (i != 0 && !template.get(i - 1).equals(ImportSorterAdapter.N)) {
template.add(i, ImportSorterAdapter.N);
i++;
}
if (i < template.size() && !template.get(i).equals(ImportSorterAdapter.N)
&& !template.get(i).equals(ImportSorterAdapter.N)) {
template.add(i, ImportSorterAdapter.N);
}
template.addAll(i, matchingItems);
}
}
// if there is \n on the end, remove it
if (template.size() > 0 && template.get(template.size() - 1).equals(ImportSorterAdapter.N)) {
template.remove(template.size() - 1);
}
}
private List<String> getResult() {
ArrayList<String> strings = new ArrayList<String>();
for (String s : template) {
if (s.equals(ImportSorterAdapter.N)) {
strings.add(s);
} else {
strings.add("import " + s + ";" + ImportSorterAdapter.N);
}
}
return strings;
}
}