/** * Copyright © 2002 Instituto Superior Técnico * * This file is part of FenixEdu Academic. * * FenixEdu Academic 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. * * FenixEdu Academic 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 FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.academic.domain.organizationalStructure; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import org.apache.commons.collections.Predicate; import org.apache.commons.lang.StringUtils; import org.fenixedu.bennu.core.domain.Bennu; public class UnitName extends UnitName_Base implements Comparable<UnitName> { public static class UnitNameLimitedOrderedSet extends TreeSet<UnitName> { protected final int maxElements; public UnitNameLimitedOrderedSet(final int maxElements) { super(); this.maxElements = maxElements; } @Override public boolean add(final UnitName unitName) { if (size() < maxElements) { return super.add(unitName); } final UnitName lastUnitName = last(); if (lastUnitName.compareTo(unitName) > 0) { remove(lastUnitName); return super.add(unitName); } return false; } public boolean containsExactSameName(final UnitName unitName) { for (UnitName forUnitName : this) { if (forUnitName.getUnit().getName().equals(unitName.getUnit().getName())) { return true; } } return false; } } public static class InternalUnitNameAndTypeLimitedOrderedSet extends UnitNameLimitedOrderedSet { private final Class<? extends Unit> unitType; public InternalUnitNameAndTypeLimitedOrderedSet(int maxElements, Class<? extends Unit> unitType) { super(maxElements); this.unitType = unitType; } @Override public boolean add(UnitName unitName) { if (size() < maxElements && unitName.getUnit().getClass().equals(unitType)) { return super.add(unitName); } final UnitName lastUnitName = isEmpty() ? null : last(); if (lastUnitName != null && lastUnitName.compareTo(unitName) > 0 && unitName.getUnit().getClass().equals(unitType)) { remove(lastUnitName); return super.add(unitName); } return false; } } public static class InternalUnitNameLimitedOrderedSet extends UnitNameLimitedOrderedSet { public InternalUnitNameLimitedOrderedSet(final int maxElements) { super(maxElements); } @Override public boolean add(final UnitName unitName) { return unitName.getIsExternalUnit() ? false : super.add(unitName); } } public static class ExternalUnitNameLimitedOrderedSet extends UnitNameLimitedOrderedSet { private final Predicate predicate; public ExternalUnitNameLimitedOrderedSet(final int maxElements) { this(maxElements, null); } public ExternalUnitNameLimitedOrderedSet(final int maxElements, final Predicate predicate) { super(maxElements); this.predicate = predicate; } @Override public boolean add(final UnitName unitName) { return (predicate == null || predicate.evaluate(unitName)) && unitName.getIsExternalUnit() ? super.add(unitName) : false; } } public static class ExternalAcademicUnitNameLimitedOrderedSet extends UnitNameLimitedOrderedSet { private final Unit institutionUnit = Bennu.getInstance().getInstitutionUnit(); public ExternalAcademicUnitNameLimitedOrderedSet(final int maxElements) { super(maxElements); } @Override public boolean add(final UnitName unitName) { String code = unitName.getUnit().getCode(); return unitName.getIsExternalUnit() && !StringUtils.isEmpty(code) && StringUtils.isNumeric(code) && super.add(unitName); } } public UnitName(Unit unit) { super(); this.setRootDomainObject(Bennu.getInstance()); setUnit(unit); setIsExternalUnit(Boolean.valueOf(!unit.isInternal())); } @Override public int compareTo(UnitName unitName) { final int stringCompare = getName().compareTo(unitName.getName()); return stringCompare == 0 ? getExternalId().compareTo(unitName.getExternalId()) : stringCompare; } @Override public void setName(String name) { super.setName(UnitNamePart.normalize(name)); UnitNamePart.reindex(this); } private static boolean containsAll(final String normalizedUnitName, final String[] nameParts) { for (final String namePart : nameParts) { if (normalizedUnitName.indexOf(namePart) == -1) { return false; } } return true; } public static void find(final UnitNameLimitedOrderedSet unitNameLimitedOrderedSet, final String name, final int size) { final String[] nameParts = UnitNamePart.getNameParts(name); if (nameParts.length > 0) { final UnitNamePart unitNamePart = UnitNamePart.find(nameParts[0]); if (unitNamePart != null && nameParts.length == 1) { unitNameLimitedOrderedSet.addAll(unitNamePart.getUnitNameSet()); } else { final Set<UnitName> unitNames = unitNamePart == null ? Bennu.getInstance().getUnitNameSet() : unitNamePart.getUnitNameSet(); for (final UnitName unitName : unitNames) { final String normalizedUnitName = unitName.getName(); if (containsAll(normalizedUnitName, nameParts)) { unitNameLimitedOrderedSet.add(unitName); } } } } } public static void findExternalInstitution(final UnitNameLimitedOrderedSet unitNameLimitedOrderedSet, final String name, final int size, final UnitNameLimitedOrderedSet resultSet) { find(unitNameLimitedOrderedSet, name, size); Set<UnitName> restOfTheUnitNames = new HashSet<UnitName>(); Set<UnitName> unitNamesWithScore = new HashSet<UnitName>(); String[] nameParts = UnitNamePart.getNameParts(name); //adding first the units with more "score" for (UnitName unitName : unitNameLimitedOrderedSet) { if (unitName.getUnit().getCode() != null) { if (containsAllExactWords(unitName.getName(), nameParts)) { if (!resultSet.containsExactSameName(unitName)) { resultSet.add(unitName); if (resultSet.size() == size) { return; } } } else { unitNamesWithScore.add(unitName); } } else { restOfTheUnitNames.add(unitName); } } //adding the unitNames with some score addDifferentUnitNames(size, resultSet, unitNamesWithScore); //adding the rest of the units until size addDifferentUnitNames(size, resultSet, restOfTheUnitNames); } private static void addDifferentUnitNames(final int size, final UnitNameLimitedOrderedSet resultSet, Set<UnitName> unitNamesWithScore) { for (UnitName unitName : unitNamesWithScore) { if (unitName.getUnit().getCode() == null) { if (!resultSet.containsExactSameName(unitName)) { resultSet.add(unitName); if (resultSet.size() == size) { return; } } } } } private static boolean containsAllExactWords(final String normalizedUnitName, final String[] nameParts) { final String[] unitNameParts = UnitNamePart.getNameParts(normalizedUnitName); for (final String namePart : nameParts) { if (namePart.length() > 3) { if (!existsCompleteNamePart(unitNameParts, namePart)) { return false; } } } return true; } private static boolean existsCompleteNamePart(final String[] unitNameParts, final String namePart) { for (String unitPart : unitNameParts) { if (unitPart.equalsIgnoreCase(namePart)) { return true; } } return false; } public static void findExactWords(final UnitNameLimitedOrderedSet unitNameLimitedOrderedSet, final String name) { final String[] nameParts = UnitNamePart.getNameParts(name); if (nameParts.length > 0) { final UnitNamePart unitNamePart = UnitNamePart.find(nameParts[0]); if (unitNamePart != null && nameParts.length == 1) { unitNameLimitedOrderedSet.addAll(unitNamePart.getUnitNameSet()); } else { final Set<UnitName> unitNames = unitNamePart == null ? Bennu.getInstance().getUnitNameSet() : unitNamePart.getUnitNameSet(); for (final UnitName unitName : unitNames) { final String normalizedUnitName = unitName.getName(); if (containsAllExactWords(normalizedUnitName, nameParts)) { if (!existsTheSameCode(unitName, unitNameLimitedOrderedSet)) { unitNameLimitedOrderedSet.add(unitName); } } } } } } private static boolean existsTheSameCode(UnitName unitName, UnitNameLimitedOrderedSet unitNameLimitedOrderedSet) { for (UnitName unitNameTemp : unitNameLimitedOrderedSet) { if (StringUtils.isEmpty(unitName.getUnit().getCode()) || !StringUtils.isNumeric(unitName.getUnit().getCode())) { return false; } if (unitName.getUnit().getCode().equals(unitNameTemp.getUnit().getCode())) { return true; } } return false; } public static Collection<UnitName> findInternalUnitWithType(final String name, final int size, Class<? extends Unit> unitType) { InternalUnitNameAndTypeLimitedOrderedSet internalUnitNameAndTypeLimitedOrderedSet = new InternalUnitNameAndTypeLimitedOrderedSet(size, unitType); find(internalUnitNameAndTypeLimitedOrderedSet, name, size); return internalUnitNameAndTypeLimitedOrderedSet; } public static Collection<UnitName> findInternalUnit(final String name, final int size) { final InternalUnitNameLimitedOrderedSet unitNameLimitedOrderedSet = new InternalUnitNameLimitedOrderedSet(size); find(unitNameLimitedOrderedSet, name, size); return unitNameLimitedOrderedSet; } public static Collection<UnitName> findExternalUnit(final String name, final int size) { final ExternalUnitNameLimitedOrderedSet unitNameLimitedOrderedSet = new ExternalUnitNameLimitedOrderedSet(size); find(unitNameLimitedOrderedSet, name, size); return unitNameLimitedOrderedSet; } public static Collection<UnitName> findExternalUnit(final String name, final int size, final Predicate predicate) { final ExternalUnitNameLimitedOrderedSet unitNameLimitedOrderedSet = new ExternalUnitNameLimitedOrderedSet(size, predicate); find(unitNameLimitedOrderedSet, name, size); return unitNameLimitedOrderedSet; } public static Collection<UnitName> findExternalAcademicUnit(final String name, final int size) { final ExternalAcademicUnitNameLimitedOrderedSet academicUnitNameLimitedOrderedSet = new ExternalAcademicUnitNameLimitedOrderedSet(size); findExactWords(academicUnitNameLimitedOrderedSet, name); return academicUnitNameLimitedOrderedSet; } /** * It does a broader search than the specified size, it then chooses the units with the code field filled first and * also exact matches with the complete normalized words then completes the list with the rest of the matches until the size * given * not adding unitNames with the name of the unit if that exact name it's not on the list * * @param name * @param size * @return */ public static Collection<UnitName> findExternalInstitutionUnitWithScore(final String name, final int size) { final ExternalUnitNameLimitedOrderedSet unitNameLimitedOrderedSet = new ExternalUnitNameLimitedOrderedSet(size + 400); final ExternalUnitNameLimitedOrderedSet resultSet = new ExternalUnitNameLimitedOrderedSet(size); findExternalInstitution(unitNameLimitedOrderedSet, name, size, resultSet); return resultSet; } public static Collection<UnitName> find(final String name, final int size) { final UnitNameLimitedOrderedSet unitNameLimitedOrderedSet = new UnitNameLimitedOrderedSet(size); find(unitNameLimitedOrderedSet, name, size); return unitNameLimitedOrderedSet; } public void delete() { final Set<UnitNamePart> unitNameParts = new HashSet<UnitNamePart>(getUnitNamePartSet()); getUnitNamePartSet().clear(); setUnit(null); setRootDomainObject(null); deleteDomainObject(); for (final UnitNamePart unitNamePart : unitNameParts) { unitNamePart.deleteIfEmpty(); } } }