/**
     * Uses the passed path elements (resolved) to try to select the best of the possible trails.
     * Returns null only if nothing matches at all.
     * BEST-EFFORT.
     * <p>
     * TODO: REVIEW: the possibility of each path elem matching multiple category IDs makes this extremely
     * complicated; so we ignore the specific implications and just match as much as possible.
     * <p>
     * For a trail to be selected, it must "end with" the pathElems; after that, the best trail is one that
     * has smallest length.
     */
protected List<String> findBestTrailForUrlPathElems(Delegator delegator, List<List<String>> possibleTrails, List<AltUrlPartResults> pathElems) throws GenericEntityException {
        if (pathElems.isEmpty()) return null;
        List<String> bestTrail = null;
        for(List<String> trail : possibleTrails) {
            if (pathElems.size() > trail.size()) continue; // sure to fail
            ListIterator<AltUrlPartResults> pit = pathElems.listIterator(pathElems.size());
            ListIterator<String> tit = trail.listIterator(trail.size());
            boolean matched = true;
            while(matched && pit.hasPrevious()) {
                AltUrlPartResults urlInfos = pit.previous();
                String categoryId = tit.previous();
                // simplistic check: ignores exact vs name-only matches, but may be good enough
                if (!urlInfos.containsKey(categoryId)) {
                    matched = false;
                }
            }
            if (matched) {
                if (trail.size() == pathElems.size()) { // ideal case
                    bestTrail = trail;
                    break;
                } else if (bestTrail == null || trail.size() < bestTrail.size()) { // smaller = better
                    bestTrail = trail;
                }
            }
        }
        return bestTrail;
    }
protected List<String> findBestTrailForUrlPathElems(Delegator delegator, List<List<String>> possibleTrails, List<AltUrlPartResults> pathElems) throws GenericEntityException {
if (pathElems.isEmpty()) return null;
List<String> bestTrail = null;
for(List<String> trail : possibleTrails) {
if (pathElems.size() > trail.size()) continue; // sure to fail
ListIterator<AltUrlPartResults> pit = pathElems.listIterator(pathElems.size());
ListIterator<String> tit = trail.listIterator(trail.size());
boolean matched = true;
while(matched && pit.hasPrevious()) {
AltUrlPartResults urlInfos = pit.previous();
String categoryId = tit.previous();
// simplistic check: ignores exact vs name-only matches, but may be good enough
if (!urlInfos.containsKey(categoryId)) {
matched = false;
}
}
if (matched) {
if (trail.size() == pathElems.size()) { // ideal case
bestTrail = trail;
break;
} else if (bestTrail == null || trail.size() < bestTrail.size()) { // smaller = better
bestTrail = trail;
}
}
}
return bestTrail;
}
protected List<String> findBestTrailForUrlPathElems(Delegator delegator, List<List<String>> possibleTrails, List<AltUrlPartResults> pathElems) throws GenericEntityException {
if (pathElems.isEmpty()) return null;
List<String> bestTrail = null;
for(List<String> trail : possibleTrails) {
if (pathElems.size() > trail.size()) continue; // sure to fail
ListIterator<AltUrlPartResults> pit = pathElems.listIterator(pathElems.size());
ListIterator<String> tit = trail.listIterator(trail.size());
boolean matched = true;
while(matched && pit.hasPrevious()) {
AltUrlPartResults urlInfos = pit.previous();
String categoryId = tit.previous();
// simplistic check: ignores exact vs name-only matches, but may be good enough
if (!urlInfos.containsKey(categoryId)) {
matched = false;
}
}
if (matched) {
if (trail.size() == pathElems.size()) { // ideal case
bestTrail = trail;
break;
} else if (bestTrail == null || trail.size() < bestTrail.size()) { // smaller = better
bestTrail = trail;
}
}
}
return bestTrail;
}
protected List<String> findBestTrailForUrlPathElems(Delegator delegator, List<List<String>> possibleTrails, List<AltUrlPartResults> pathElems) throws GenericEntityException {
if (pathElems.isEmpty()) return null;
List<String> bestTrail = null;
for(List<String> trail : possibleTrails) {
if (pathElems.size() > trail.size()) continue; // sure to fail
ListIterator<AltUrlPartResults> pit = pathElems.listIterator(pathElems.size());
ListIterator<String> tit = trail.listIterator(trail.size());
boolean matched = true;
while(matched && pit.hasPrevious()) {
AltUrlPartResults urlInfos = pit.previous();
String categoryId = tit.previous();
// simplistic check: ignores exact vs name-only matches, but may be good enough
if (!urlInfos.containsKey(categoryId)) {
matched = false;
}
}
if (matched) {
if (trail.size() == pathElems.size()) { // ideal case
bestTrail = trail;
break;
} else if (bestTrail == null || trail.size() < bestTrail.size()) { // smaller = better
bestTrail = trail;
}
}
}
return bestTrail;
}