/******************************************************************************* * Copyright (c) 2015 Jeff Martin. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public * License v3.0 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation ******************************************************************************/ package cuchaz.enigma.convert; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map.Entry; import java.util.Set; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ClassEntry; public class ClassMatching { private ClassForest m_sourceClasses; private ClassForest m_destClasses; private BiMap<ClassEntry, ClassEntry> m_knownMatches; public ClassMatching(ClassIdentifier sourceIdentifier, ClassIdentifier destIdentifier) { m_sourceClasses = new ClassForest(sourceIdentifier); m_destClasses = new ClassForest(destIdentifier); m_knownMatches = HashBiMap.create(); } public void addKnownMatches(BiMap<ClassEntry, ClassEntry> knownMatches) { m_knownMatches.putAll(knownMatches); } public void match(Iterable<ClassEntry> sourceClasses, Iterable<ClassEntry> destClasses) { for(ClassEntry sourceClass : sourceClasses) if(!m_knownMatches.containsKey(sourceClass)) m_sourceClasses.add(sourceClass); for(ClassEntry destClass : destClasses) if(!m_knownMatches.containsValue(destClass)) m_destClasses.add(destClass); } public Collection<ClassMatch> matches() { List<ClassMatch> matches = Lists.newArrayList(); for(Entry<ClassEntry, ClassEntry> entry : m_knownMatches.entrySet()) matches.add(new ClassMatch(entry.getKey(), entry.getValue())); for(ClassIdentity identity : m_sourceClasses.identities()) matches.add(new ClassMatch(m_sourceClasses.getClasses(identity), m_destClasses.getClasses(identity))); for(ClassIdentity identity : m_destClasses.identities()) if(!m_sourceClasses.containsIdentity(identity)) matches.add(new ClassMatch(new ArrayList<ClassEntry>(), m_destClasses.getClasses(identity))); return matches; } public Collection<ClassEntry> sourceClasses() { Set<ClassEntry> classes = Sets.newHashSet(); for(ClassMatch match : matches()) classes.addAll(match.sourceClasses); return classes; } public Collection<ClassEntry> destClasses() { Set<ClassEntry> classes = Sets.newHashSet(); for(ClassMatch match : matches()) classes.addAll(match.destClasses); return classes; } public BiMap<ClassEntry, ClassEntry> uniqueMatches() { BiMap<ClassEntry, ClassEntry> uniqueMatches = HashBiMap.create(); for(ClassMatch match : matches()) if(match.isMatched() && !match.isAmbiguous()) uniqueMatches.put(match.getUniqueSource(), match.getUniqueDest()); return uniqueMatches; } public Collection<ClassMatch> ambiguousMatches() { List<ClassMatch> ambiguousMatches = Lists.newArrayList(); for(ClassMatch match : matches()) if(match.isMatched() && match.isAmbiguous()) ambiguousMatches.add(match); return ambiguousMatches; } public Collection<ClassEntry> unmatchedSourceClasses() { List<ClassEntry> classes = Lists.newArrayList(); for(ClassMatch match : matches()) if(!match.isMatched() && !match.sourceClasses.isEmpty()) classes.addAll(match.sourceClasses); return classes; } public Collection<ClassEntry> unmatchedDestClasses() { List<ClassEntry> classes = Lists.newArrayList(); for(ClassMatch match : matches()) if(!match.isMatched() && !match.destClasses.isEmpty()) classes.addAll(match.destClasses); return classes; } @Override public String toString() { // count the ambiguous classes int numAmbiguousSource = 0; int numAmbiguousDest = 0; for(ClassMatch match : ambiguousMatches()) { numAmbiguousSource += match.sourceClasses.size(); numAmbiguousDest += match.destClasses.size(); } StringBuilder buf = new StringBuilder(); buf.append(String.format("%20s%8s%8s\n", "", "Source", "Dest")); buf.append(String.format("%20s%8d%8d\n", "Classes", sourceClasses() .size(), destClasses().size())); buf.append(String.format("%20s%8d%8d\n", "Uniquely matched", uniqueMatches().size(), uniqueMatches().size())); buf.append(String.format("%20s%8d%8d\n", "Ambiguously matched", numAmbiguousSource, numAmbiguousDest)); buf.append(String.format("%20s%8d%8d\n", "Unmatched", unmatchedSourceClasses().size(), unmatchedDestClasses().size())); return buf.toString(); } }