package lt.inventi.wicket.component.breadcrumb; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.wicket.MetaDataKey; import org.apache.wicket.Session; class BreadcrumbTrailHistory implements Serializable { private static final MetaDataKey<BreadcrumbTrailHistory> CONTAINER = new MetaDataKey<BreadcrumbTrailHistory>(){ /* empty */ }; private static BreadcrumbTrailHistory get() { Session session = Session.get(); BreadcrumbTrailHistory container = session.getMetaData(CONTAINER); if (container == null) { container = new BreadcrumbTrailHistory(); session.setMetaData(CONTAINER, container); } if (session.isTemporary()) { session.bind(); } return container; } static void extendTrail(String maybeTrailId, Breadcrumb newCrumb) { BreadcrumbTrailHistory history = get(); Breadcrumb crumb = history.useExistingCrumbIfPossible(newCrumb); PersistentList previousTrail = history.breadcrumbMap.get(maybeTrailId); if (BreadcrumbsSettings.isCompactionEnabled()) { previousTrail = compact(previousTrail, crumb); } history.breadcrumbMap.put(crumb.getId(), new PersistentList(previousTrail, crumb)); } private static PersistentList compact(PersistentList trail, Breadcrumb crumb) { if (trail == null) { return null; } PersistentList next = trail; while (true) { if (next.tail.getType().equals(crumb.getType())) { return next.first; } if (next.first == null) { break; } next = next.first; } return trail; } /** * Tries to get the nth breadcrumb from the end for the provided trail id. * <p> * In case provided trail id is null or no breadcrumb history exists for the * id, nothing is returned. * * @param maybeTrailId * @return (trail size - n)th breadcrumb from the history associated with * the provided trail or null if no trail exists */ static Breadcrumb getLastBreadcrumbFor(String maybeTrailId) { BreadcrumbTrailHistory history = get(); if (maybeTrailId != null && history.breadcrumbMap.containsKey(maybeTrailId)) { PersistentList trail = history.breadcrumbMap.get(maybeTrailId); return trail.tail; } return null; } static Breadcrumb getPenultimateBreadcrumbFor(String maybeTrailId) { BreadcrumbTrailHistory history = get(); if (maybeTrailId != null && history.breadcrumbMap.containsKey(maybeTrailId)) { PersistentList trail = history.breadcrumbMap.get(maybeTrailId); if (trail.first != null) { return trail.first.tail; } } return null; } static List<Breadcrumb> getTrail(String trailId) { return get().breadcrumbMap.get(trailId).toList(); } private final Map<String, Breadcrumb> crumbsByPageIdClass = new HashMap<String, Breadcrumb>(); private final Map<String, PersistentList> breadcrumbMap = new LinkedHashMap<String, PersistentList>(); /** * This allows us to update breadcrumb titles in the existing trails. We * also share breadcrumb objects across trails instead of always storing new * ones on each render. */ private Breadcrumb useExistingCrumbIfPossible(Breadcrumb newCrumb) { Breadcrumb crumb = crumbsByPageIdClass.get(newCrumb.getStableId()); if (crumb != null) { crumb.updateWith(newCrumb); } else { crumb = newCrumb; crumbsByPageIdClass.put(crumb.getStableId(), crumb); } return crumb; } private static class PersistentList implements Serializable { final PersistentList first; final Breadcrumb tail; PersistentList(PersistentList first, Breadcrumb tail) { this.first = first; this.tail = tail; } public List<Breadcrumb> toList() { List<Breadcrumb> result = new ArrayList<Breadcrumb>(); result.add(tail); if (first == null) { return result; } PersistentList prev = first; while (prev != null) { result.add(prev.tail); prev = prev.first; } Collections.reverse(result); return result; } } }