/*
* Copyright (c) 2013 Tom Parker <thpr@users.sourceforge.net> This program 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 2.1 of the License, or (at your option) any later
* version.
*
* This program 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
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package compare;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Set;
import pcgen.base.lang.StringUtil;
import pcgen.base.test.InequalityTester;
import pcgen.base.util.AbstractMapToList;
import pcgen.base.util.HashMapToList;
import pcgen.base.util.MapToList;
public class IdentityHashMapInequality implements
InequalityTest<IdentityHashMap>
{
@Override
public String testInequality(IdentityHashMap m1, IdentityHashMap m2,
InequalityTester t, String location)
{
Collection<String> reasons = new ArrayList<>();
Set<?> k1 = m1.keySet();
Set<?> k2 = m2.keySet();
if (k1.size() != k2.size())
{
return "IMI=@" + location + ": Inequality in Map Key Size: "
+ m1.keySet() + " " + m2.keySet();
}
AbstractMapToList<Integer, Integer> matches =
new HashMapToList<>();
if (!k1.equals(k2))
{
String result = processKeys(location, k1, k2, matches);
if (result != null)
{
return result;
}
}
if (!m1.values().equals(m2.values()))
{
if (matches.isEmpty())
{
String result = processKeys(location, k1, k2, matches);
if (result != null)
{
return result;
}
}
return processValues(location, m1.values(), m2.values(), matches);
}
return reasons.isEmpty() ? null : StringUtil.join(reasons, "\n");
}
private static String processKeys(String location, Iterable<?> k1, Iterable<?> k2,
MapToList<Integer, Integer> matches)
{
/*
* Walk through this establishing an "order"... Order needs to be kept
* and then passed to values...
*/
int i = 0;
for (final Object key1 : k1)
{
int j = 0;
for (final Object key2 : k2)
{
if (key1.equals(key2))
{
matches.addToListFor(i, j);
}
j++;
}
if (!matches.containsListFor(i))
{
return "@IMI" + location + ":k: " + key1 + " not found in map2";
}
i++;
}
return null;
}
private static String processValues(String location, Collection<?> v1,
Collection<?> v2, AbstractMapToList<Integer, Integer> potential)
{
MapToList<Integer, Integer> matches =
new HashMapToList<>();
List<Object> values1 = new ArrayList<>(v1);
List<Object> values2 = new ArrayList<>(v2);
for (final Integer loc1 : potential.getKeySet())
{
Object o1 = values1.get(loc1);
for (final Integer loc2 : potential.getListFor(loc1))
{
Object o2 = values2.get(loc2);
if (o1.equals(o2))
{
matches.addToListFor(loc1, loc2);
}
}
}
if (potential.equals(matches))
{
return null;
}
//If not then we have keys that are .equals but not == and different targets :/
Collection<Integer> used = new ArrayList<>();
for (final Integer m1 : matches.getKeySet())
{
if (matches.sizeOfListFor(m1) == 1)
{
Integer single = matches.getElementInList(m1, 0);
if (used.contains(single))
{
return "@IMI" + location + ":v:Value found single match twice";
}
used.add(single);
}
}
if (used.size() == matches.size())
{
//They all only matched once :)
return null;
}
return "This is a 'development of IdentityHashMapInequality is not complete message";
}
}