/** * eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the * <e-UCM> research group. * * Copyright 2005-2010 <e-UCM> research group. * * You can access a list of all the contributors to eAdventure at: * http://e-adventure.e-ucm.es/contributors * * <e-UCM> is a research group of the Department of Software Engineering * and Artificial Intelligence at the Complutense University of Madrid * (School of Computer Science). * * C Profesor Jose Garcia Santesmases sn, * 28040 Madrid (Madrid), Spain. * * For more info please visit: <http://e-adventure.e-ucm.es> or * <http://www.e-ucm.es> * * **************************************************************************** * * This file is part of eAdventure, version 2.0 * * eAdventure 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. * * eAdventure 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 eAdventure. If not, see <http://www.gnu.org/licenses/>. */ package es.eucm.ead.tools; import es.eucm.ead.model.elements.BasicElement; import es.eucm.ead.model.elements.extra.EAdMap; import es.eucm.ead.model.interfaces.features.Identified; import es.eucm.ead.tools.reflection.ReflectionClass; import es.eucm.ead.tools.reflection.ReflectionClassLoader; import es.eucm.ead.tools.reflection.ReflectionField; import java.util.*; public class EAdUtils { public static final char[] ID_CHARS = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', /* * '.', '_', '\'', '?', '¿', '¡', '!', 'ñ', * 'Ñ', 'ç', '+', '-', ' ', '@', '^', '#', * '$', '%', '(', ')',';', ',', '{', '}', * '*', '·', '[', ']', '`', '´' */}; private static Stack<Object> elements1 = new Stack<Object>(); private static Stack<Object> elements2 = new Stack<Object>(); private static ArrayList<Object> compared1 = new ArrayList<Object>(); private static ArrayList<Object> compared2 = new ArrayList<Object>(); private static boolean ignoreId; public static void shuffle(List<?> list, Random rnd) { if (list instanceof RandomAccess) { int size = list.size(); for (int i = size; i > 1; i--) Collections.swap(list, i - 1, rnd.nextInt(i)); } } public static boolean equals(Object o1, Object o2, boolean ignoreId) { return equals(o1, o2, ignoreId, null); } public static boolean equals(Object o1, Object o2, boolean ignoreId, NotEqualHandler handler) { elements1.clear(); elements2.clear(); compared1.clear(); compared2.clear(); EAdUtils.ignoreId = ignoreId; return equalsImpl(o1, o2, handler); } private static boolean equalsImpl(Object o1, Object o2, NotEqualHandler handler) { boolean result = checkStack(o1, o2); boolean alreadyCompared = checkCompared(o1, o2); if (alreadyCompared) { result = true; } else if (result && elements1.indexOf(o1) == -1) { push(o1, o2); if (o1 == o2) { result = true; } else if (o1 == null || o2 == null) { result = false; } else if (o1.getClass() != o2.getClass()) { result = o1 instanceof BasicElement && o2 instanceof BasicElement && ((BasicElement) o1).getId().equals( ((BasicElement) o2).getId()); } else if (o1 instanceof Number || o1 instanceof String || o1 instanceof Boolean) { result = o1.equals(o2); } else if (o1 instanceof List) { List<?> list1 = (List<?>) o1; List<?> list2 = (List<?>) o2; result = (list1.size() == list2.size()); for (int i = 0; i < list1.size() && result; i++) { result = equalsImpl(list1.get(i), list2.get(i), handler); } } else if (o1 instanceof Map) { Map<?, ?> map1 = (Map<?, ?>) o1; Map<?, ?> map2 = (Map<?, ?>) o2; result = map1.size() == map2.size(); Iterator<?> it1 = map1.keySet().iterator(); Iterator<?> it2 = map2.keySet().iterator(); while (result && it1.hasNext()) { Object v1 = it1.next(); Object v2 = it2.next(); result = equalsImpl(v1, v2, handler); } it1 = map1.values().iterator(); it2 = map2.values().iterator(); while (result && it1.hasNext()) { Object v1 = it1.next(); Object v2 = it2.next(); result = equalsImpl(v1, v2, handler); } } else if (o1 instanceof Identified && o2 instanceof Identified) { ReflectionClass<?> clazz = ReflectionClassLoader .getReflectionClass(o1.getClass()); while (clazz != null) { for (ReflectionField f : clazz.getFields()) { if (!result) { break; } if (!f.isStatic() && !f.isTransient()) { if (ignoreId && f.getName().equals("id")) { continue; } Object v1 = f.getFieldValue(o1); Object v2 = f.getFieldValue(o2); result = equalsImpl(v1, v2, handler); } } clazz = clazz.getSuperclass(); } } else { result = o1.equals(o2); } pop(); } if (!result && handler != null) { handler.notEqual(o1, o2); } compared1.add(o1); compared2.add(o2); return result; } private static void push(Object o1, Object o2) { elements1.push(o1); elements2.push(o2); } private static void pop() { elements1.pop(); elements2.pop(); } private static boolean checkStack(Object o1, Object o2) { int index1 = elements1.indexOf(o1); int index2 = elements2.indexOf(o2); return index1 == index2; } private static boolean checkCompared(Object o1, Object o2) { int index1 = compared1.indexOf(o1); int index2 = compared2.indexOf(o2); return index1 != -1 && index1 == index2; } public static String generateId(String prefix, int ordinal) { String id = ""; int id2 = ordinal; boolean oneZero = false; while (!oneZero) { id = ID_CHARS[(id2 % ID_CHARS.length)] + id; id2 /= ID_CHARS.length; if (id2 == 0) { oneZero = true; } } return prefix + id; } public static EAdMap<String> invertMap(EAdMap<String> map) { EAdMap<String> map2 = new EAdMap<String>(); for (Map.Entry<String, String> e : map.entrySet()) { map2.put(e.getValue(), e.getKey()); } return map2; } public interface NotEqualHandler { void notEqual(Object o1, Object o2); } }