package jas.spawner.refactor.entities;
import jas.common.JASLog;
import jas.common.helper.sort.TopologicalSort;
import jas.common.helper.sort.TopologicalSort.DirectedGraph;
import jas.common.helper.sort.TopologicalSortingException;
import jas.spawner.modern.math.SetAlgebra;
import jas.spawner.modern.math.SetAlgebra.OPERATION;
import jas.spawner.refactor.entities.Group.ContentGroup;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.toposort.ModSortingException.SortingExceptionData;
/** Groups composed of a Mapping Object where each is defined by a unique String */
public interface ListContentGroup extends ContentGroup<List<String>> {
public String iD();
public Set<String> results();
public List<String> content();
public static class Parser {
/**
* @param mappings: Base Unit of composition for a group
* @param keyToMap Prefix key To corresponding groups i.e. A| -> LivingAttributes
*/
public static void parseGroupContents(MutableContentGroup<List<String>> mutableGroup, Mappings mappings,
Groups<? extends ContentGroup<List<String>>>... maps) {
/* Evaluate contents and fill in jasNames */
for (String contentComponent : mutableGroup.content()) {
OPERATION operation;
if (contentComponent.startsWith("-")) {
contentComponent = contentComponent.substring(1);
operation = OPERATION.COMPLEMENT;
} else if (contentComponent.startsWith("&")) {
contentComponent = contentComponent.substring(1);
operation = OPERATION.INTERSECT;
} else {
operation = OPERATION.UNION;
if (contentComponent.startsWith("+")) {
contentComponent = contentComponent.substring(1);
}
}
Set<String> results = new HashSet<String>(mutableGroup.results());
if (mappings.mappingToKey().containsKey(contentComponent)) {
SetAlgebra.operate(results, Sets.newHashSet(contentComponent), operation);
} else {
boolean foundMatch = false;
for (Groups<? extends ContentGroup<List<String>>> map : maps) {
if (contentComponent.startsWith(map.key())) {
ContentGroup<List<String>> groupToAdd = map.iDToGroup().get(
contentComponent.substring(map.key().length()));
if (groupToAdd != null) {
SetAlgebra.operate(mutableGroup.results(), groupToAdd.results(), operation);
foundMatch = true;
break;
}
}
}
if (!foundMatch) {
JASLog.log().severe("Error processing %s content from %s. The component %s does not exist.",
mutableGroup.iD(), mutableGroup.content().toString(), contentComponent);
}
}
mutableGroup.setResults(results);
}
}
}
// TODO: This could (should?) be more generic? i.e. interace Sortable
public static class Sorter {
public static <T extends ListContentGroup> List<T> getSortedGroups(Groups<T> groups) {
/* Evaluate each group, ensuring entries are valid mappings or Groups and */
DirectedGraph<T> groupGraph = new DirectedGraph<T>();
for (T livingGroup : groups.iDToGroup().values()) {
groupGraph.addNode(livingGroup);
}
for (T currentGroup : groups.iDToGroup().values()) {
for (String contentComponent : currentGroup.content()) {
for (T possibleGroup : groups.iDToGroup().values()) {
if (contentComponent.startsWith(groups.key())
&& contentComponent.substring(groups.key().length()).equals(possibleGroup.iD())) {
groupGraph.addEdge(possibleGroup, currentGroup);
}
}
}
}
List<T> sortedList;
try {
sortedList = TopologicalSort.topologicalSort(groupGraph);
} catch (TopologicalSortingException sortException) {
SortingExceptionData<T> exceptionData = sortException.getExceptionData();
JASLog.log().severe(
"A circular reference was detected when processing entity groups. Groups in the cycle were: ");
int i = 1;
for (T invalidGroups : exceptionData.getVisitedNodes()) {
JASLog.log().severe("Group %s: %s containing %s", i++, invalidGroups.iD(),
invalidGroups.content().toString());
}
throw sortException;
}
return sortedList;
}
}
}