package krasa.formatter.plugin;
import java.util.*;
import krasa.formatter.utils.StringUtils;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.util.MultiValuesMap;
/*not thread safe*/
@SuppressWarnings("Duplicates")
class ImportsSorter452 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<? super String> importsComparator;
public ImportsSorter452(List<String> importOrder, ImportsComparator comparator) {
importsComparator = comparator;
List<String> importOrderCopy = new ArrayList<String>(importOrder);
normalizeStaticOrderItems(importOrderCopy);
putStaticItemIfNotExists(importOrderCopy);
template.addAll(importOrderCopy);
this.allImportOrderItems.addAll(importOrderCopy);
}
@Override
public List<String> sort(List<String> imports) {
filterMatchingImports(imports);
mergeMatchingItems();
mergeNotMatchingItems();
removeNewLines();
return getResult();
}
private void removeNewLines() {
List<String> temp = new ArrayList<String>();
boolean previousWasNewLine = false;
boolean anyContent = false;
for (int i = 0; i < template.size(); i++) {
String s = template.get(i);
if (!anyContent && s.equals(ImportSorterAdapter.N)) {
continue;
}
if (s.equals(ImportSorterAdapter.N)) {
if (previousWasNewLine) {
continue;
} else {
temp.add(s);
}
previousWasNewLine = true;
} else {
previousWasNewLine = false;
anyContent = true;
temp.add(s);
}
}
Collections.reverse(temp);
List<String> temp2 = trimNewLines(temp);
Collections.reverse(temp2);
template = temp2;
}
@NotNull
private List<String> trimNewLines(List<String> temp) {
List<String> temp2 = new ArrayList<String>();
boolean anyContent = false;
for (int i = 0; i < temp.size(); i++) {
String s = temp.get(i);
if (!anyContent && s.equals(ImportSorterAdapter.N)) {
continue;
}
anyContent = true;
temp2.add(s);
}
return temp2;
}
private void putStaticItemIfNotExists(List<String> allImportOrderItems) {
boolean contains = false;
for (int i = 0; i < allImportOrderItems.size(); i++) {
String allImportOrderItem = allImportOrderItems.get(i);
if (allImportOrderItem.equals("static ")) {
contains = true;
}
}
if (!contains) {
allImportOrderItems.add(0, "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(
// 4.5.1+ matches exact package name
orderItem.equals("static ") || orderItem.equals("") ? orderItem : 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() {
Collections.sort(notMatching, importsComparator);
template.add(ImportSorterAdapter.N);
for (int i = 0; i < notMatching.size(); i++) {
String notMatchingItem = notMatching.get(i);
if (!matchesStatic(false, notMatchingItem)) {
continue;
}
boolean isOrderItem = isOrderItem(notMatchingItem, false);
if (!isOrderItem) {
template.add(notMatchingItem);
}
}
template.add(ImportSorterAdapter.N);
}
private boolean isOrderItem(String notMatchingItem, boolean staticItems) {
boolean contains = allImportOrderItems.contains(notMatchingItem);
return contains && matchesStatic(staticItems, notMatchingItem);
}
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, importsComparator);
// 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 + 1 < template.size() && !template.get(i + 1).equals(ImportSorterAdapter.N)
&& !template.get(i).equals(ImportSorterAdapter.N)) {
template.add(i, ImportSorterAdapter.N);
}
template.addAll(i, matchingItems);
if (i != 0 && !template.get(i - 1).equals(ImportSorterAdapter.N)) {
template.add(i, ImportSorterAdapter.N);
}
}
}
// 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;
}
}