// ================================================================== // This file is part of Player API. // // Player API is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // Player API is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and the GNU General Public License along with Player API. // If not, see . // ================================================================== package api.player.client; import java.util.*; public final class ClientPlayerBaseSorter { public ClientPlayerBaseSorter(List list, Map allBaseSuperiors, Map allBaseInferiors, String methodName) { this.list = list; this.allBaseSuperiors = allBaseSuperiors; this.allBaseInferiors = allBaseInferiors; this.methodName = methodName; } public void Sort() { if(list.size() <= 1) return; if(explicitInferiors != null) explicitInferiors.clear(); if(explicitSuperiors != null) explicitSuperiors.clear(); if(directInferiorsMap != null) directInferiorsMap.clear(); if(allInferiors != null) allInferiors.clear(); for(int i = 0; i < list.size(); i++) { String baseId = list.get(i); String[] inferiorNames = allBaseInferiors.get(baseId); boolean hasInferiors = inferiorNames != null && inferiorNames.length > 0; String[] superiorNames = allBaseSuperiors.get(baseId); boolean hasSuperiors = superiorNames != null && superiorNames.length > 0; if((hasInferiors || hasSuperiors) && directInferiorsMap == null) directInferiorsMap = new Hashtable>(); if(hasInferiors) explicitInferiors = build(baseId, explicitInferiors, directInferiorsMap, null, inferiorNames); if(hasSuperiors) explicitSuperiors = build(baseId, explicitSuperiors, null, directInferiorsMap, superiorNames); } if(directInferiorsMap != null) { for(int i = 0; i < list.size() - 1; i++) for(int n = i + 1; n < list.size(); n++) { String left = list.get(i); String right = list.get(n); Set leftInferiors = null, rightInferiors = null; if(explicitInferiors != null) { leftInferiors = explicitInferiors.get(left); rightInferiors = explicitInferiors.get(right); } Set leftSuperiors = null, rightSuperiors = null; if(explicitSuperiors != null) { leftSuperiors = explicitSuperiors.get(left); rightSuperiors = explicitSuperiors.get(right); } boolean leftWantsToBeInferiorToRight = leftSuperiors != null && leftSuperiors.contains(right); boolean leftWantsToBeSuperiorToRight = leftInferiors != null && leftInferiors.contains(right); boolean rightWantsToBeInferiorToLeft = rightSuperiors != null && rightSuperiors.contains(left); boolean rightWantsToBeSuperiorToLeft = rightInferiors != null && rightInferiors.contains(left); if(leftWantsToBeInferiorToRight && rightWantsToBeInferiorToLeft) throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. '" + left + "' wants to be inferior to '" + right + "' and '" + right + "' wants to be inferior to '" + left + "'"); if(leftWantsToBeSuperiorToRight && rightWantsToBeSuperiorToLeft) throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. '" + left + "' wants to be superior to '" + right + "' and '" + right + "' wants to be superior to '" + left + "'"); if(leftWantsToBeInferiorToRight && leftWantsToBeSuperiorToRight) throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. '" + left + "' wants to be superior and inferior to '" + right + "'"); if(rightWantsToBeInferiorToLeft && rightWantsToBeSuperiorToLeft) throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. '" + right + "' wants to be superior and inferior to '" + left + "'"); } if(allInferiors == null) allInferiors = new Hashtable>(); for(int i = 0; i < list.size(); i++) build(list.get(i), null); } if (withoutSuperiors == null) withoutSuperiors = new LinkedList(); int offset = 0; int size = list.size(); while(size > 1) { withoutSuperiors.clear(); for(int i = offset; i < offset + size; i++) withoutSuperiors.add(list.get(i)); if(allInferiors != null) for(int i = offset; i < offset + size; i++) { Set inferiors = allInferiors.get(list.get(i)); if (inferiors != null) withoutSuperiors.removeAll(inferiors); } boolean initial = true; for(int i = offset; i < offset + size; i++) { String key = list.get(i); if(withoutSuperiors.contains(key)) { if(initial) { Set inferiors = null; if(allInferiors != null) inferiors = allInferiors.get(key); if(inferiors == null || inferiors.isEmpty()) { withoutSuperiors.remove(key); size--; offset++; continue; } } list.remove(i--); size--; } initial = false; } list.addAll(offset + size, withoutSuperiors); } } private Set build(String type, String startType) { Set inferiors = allInferiors.get(type); if(inferiors == null) { inferiors = build(type, null, startType != null ? startType : type); if(inferiors == null) inferiors = Empty; allInferiors.put(type, inferiors); } return inferiors; } private Set build(String type, Set inferiors, String startType) { Set directInferiors = directInferiorsMap.get(type); if(directInferiors == null) return inferiors; if(inferiors == null) inferiors = new HashSet(); Iterator iter = directInferiors.iterator(); while(iter.hasNext()) { String inferiorType = iter.next(); if(inferiorType == startType) throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. Circular superiosity found including '" + startType + "'"); if(list.contains(inferiorType)) inferiors.add(inferiorType); Set inferiorSet; try { inferiorSet = build(inferiorType, startType); } catch(UnsupportedOperationException uoe) { throw new UnsupportedOperationException("Can not sort ClientPlayerBase classes for method '" + methodName + "'. Circular superiosity found including '" + inferiorType + "'", uoe); } if(inferiorSet != Empty) inferiors.addAll(inferiorSet); } return inferiors; } private static Map> build(String baseId, Map> map, Map> directMap, Map> otherDirectMap, String[] names) { if(map == null) map = new Hashtable>(); Set types = new HashSet(); for(int n = 0; n < names.length; n++) { if(names[n] != null) types.add(names[n]); } if(directMap != null) getOrCreateSet(directMap, baseId).addAll(types); if(otherDirectMap != null) { Iterator iter = types.iterator(); while(iter.hasNext()) getOrCreateSet(otherDirectMap, iter.next()).add(baseId); } map.put(baseId, types); return map; } private static Set getOrCreateSet(Map> map, String key) { Set value = map.get(key); if(value != null) return value; value = new HashSet(); map.put(key, value); return value; } private Map> explicitInferiors; private Map> explicitSuperiors; private Map> directInferiorsMap; private Map> allInferiors; private List withoutSuperiors; private final List list; private final Map allBaseSuperiors; private final Map allBaseInferiors; private final String methodName; private static final Set Empty = new HashSet(); }