/******************************************************************************* * 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.Iterator; import java.util.Map; import java.util.Set; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ClassEntry; public class ClassMatches implements Iterable<ClassMatch> { Collection<ClassMatch> m_matches; Map<ClassEntry, ClassMatch> m_matchesBySource; Map<ClassEntry, ClassMatch> m_matchesByDest; BiMap<ClassEntry, ClassEntry> m_uniqueMatches; Map<ClassEntry, ClassMatch> m_ambiguousMatchesBySource; Map<ClassEntry, ClassMatch> m_ambiguousMatchesByDest; Set<ClassEntry> m_unmatchedSourceClasses; Set<ClassEntry> m_unmatchedDestClasses; public ClassMatches() { this(new ArrayList<ClassMatch>()); } public ClassMatches(Collection<ClassMatch> matches) { m_matches = matches; m_matchesBySource = Maps.newHashMap(); m_matchesByDest = Maps.newHashMap(); m_uniqueMatches = HashBiMap.create(); m_ambiguousMatchesBySource = Maps.newHashMap(); m_ambiguousMatchesByDest = Maps.newHashMap(); m_unmatchedSourceClasses = Sets.newHashSet(); m_unmatchedDestClasses = Sets.newHashSet(); for(ClassMatch match : matches) indexMatch(match); } public void add(ClassMatch match) { m_matches.add(match); indexMatch(match); } public void remove(ClassMatch match) { for(ClassEntry sourceClass : match.sourceClasses) { m_matchesBySource.remove(sourceClass); m_uniqueMatches.remove(sourceClass); m_ambiguousMatchesBySource.remove(sourceClass); m_unmatchedSourceClasses.remove(sourceClass); } for(ClassEntry destClass : match.destClasses) { m_matchesByDest.remove(destClass); m_uniqueMatches.inverse().remove(destClass); m_ambiguousMatchesByDest.remove(destClass); m_unmatchedDestClasses.remove(destClass); } m_matches.remove(match); } public int size() { return m_matches.size(); } @Override public Iterator<ClassMatch> iterator() { return m_matches.iterator(); } private void indexMatch(ClassMatch match) { if(!match.isMatched()) { // unmatched m_unmatchedSourceClasses.addAll(match.sourceClasses); m_unmatchedDestClasses.addAll(match.destClasses); }else if(match.isAmbiguous()) { // ambiguously matched for(ClassEntry entry : match.sourceClasses) m_ambiguousMatchesBySource.put(entry, match); for(ClassEntry entry : match.destClasses) m_ambiguousMatchesByDest.put(entry, match); }else // uniquely matched m_uniqueMatches.put(match.getUniqueSource(), match.getUniqueDest()); for(ClassEntry entry : match.sourceClasses) m_matchesBySource.put(entry, match); for(ClassEntry entry : match.destClasses) m_matchesByDest.put(entry, match); } public BiMap<ClassEntry, ClassEntry> getUniqueMatches() { return m_uniqueMatches; } public Set<ClassEntry> getUnmatchedSourceClasses() { return m_unmatchedSourceClasses; } public Set<ClassEntry> getUnmatchedDestClasses() { return m_unmatchedDestClasses; } public Set<ClassEntry> getAmbiguouslyMatchedSourceClasses() { return m_ambiguousMatchesBySource.keySet(); } public ClassMatch getAmbiguousMatchBySource(ClassEntry sourceClass) { return m_ambiguousMatchesBySource.get(sourceClass); } public ClassMatch getMatchBySource(ClassEntry sourceClass) { return m_matchesBySource.get(sourceClass); } public ClassMatch getMatchByDest(ClassEntry destClass) { return m_matchesByDest.get(destClass); } public void removeSource(ClassEntry sourceClass) { ClassMatch match = m_matchesBySource.get(sourceClass); if(match != null) { remove(match); match.sourceClasses.remove(sourceClass); if(!match.sourceClasses.isEmpty() || !match.destClasses.isEmpty()) add(match); } } public void removeDest(ClassEntry destClass) { ClassMatch match = m_matchesByDest.get(destClass); if(match != null) { remove(match); match.destClasses.remove(destClass); if(!match.sourceClasses.isEmpty() || !match.destClasses.isEmpty()) add(match); } } }