package com.celements.navigation; import javax.annotation.concurrent.Immutable; import javax.validation.constraints.NotNull; import org.python.google.common.base.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.model.reference.SpaceReference; import com.celements.model.util.ModelUtils; import com.celements.navigation.presentation.IPresentationTypeRole; import com.celements.web.service.IWebUtilsService; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.xpn.xwiki.web.Utils; @Immutable public final class NavigationConfig { private final static Logger LOGGER = LoggerFactory.getLogger(NavigationConfig.class); public static final NavigationConfig DEFAULTS = new NavigationConfig(); public static final int UNLIMITED_ITEMS_PER_PAGE = -1; public static final int DEFAULT_MIN_LEVEL = 1; public static final int DEFAULT_MAX_LEVEL = 100; public static final String PAGE_MENU_DATA_TYPE = "pageMenu"; public static final String LIST_LAYOUT_TYPE = "list"; public static class Builder { // Required parameters private boolean enabled; // Optional parameters - initialized to Optional.absent() private Optional<String> configName = Optional.absent(); private Optional<Integer> fromHierarchyLevel = Optional.absent(); private Optional<Integer> toHierarchyLevel = Optional.absent(); private Optional<Integer> showInactiveToLevel = Optional.absent(); private Optional<String> menuPart = Optional.absent(); private Optional<SpaceReference> nodeSpaceRef = Optional.absent(); private Optional<String> dataType = Optional.absent(); private Optional<String> layoutType = Optional.absent(); private Optional<Integer> nrOfItemsPerPage = Optional.absent(); private Optional<String> presentationTypeHint = Optional.absent(); private Optional<String> cmCssClass = Optional.absent(); public Builder() { enabled = true; } public Builder disable() { enabled = false; return this; } public Builder configName(@NotNull String val) { configName = Optional.of(Strings.emptyToNull(val)); return this; } public Builder fromHierarchyLevel(int val) { fromHierarchyLevel = Optional.of(val); return this; } public Builder toHierarchyLevel(int val) { toHierarchyLevel = Optional.of(val); return this; } public Builder showInactiveToLevel(int val) { showInactiveToLevel = Optional.of(val); return this; } public Builder menuPart(@NotNull String val) { menuPart = Optional.of(Strings.emptyToNull(val)); return this; } public Builder nodeSpaceRef(@NotNull SpaceReference val) { Preconditions.checkNotNull(val); nodeSpaceRef = Optional.of(getModelUtils().cloneRef(val, SpaceReference.class)); return this; } public Builder dataType(@NotNull String val) { dataType = Optional.of(Strings.emptyToNull(val)); return this; } public Builder layoutType(@NotNull String val) { layoutType = Optional.of(Strings.emptyToNull(val)); return this; } public Builder nrOfItemsPerPage(int val) { if ((val == UNLIMITED_ITEMS_PER_PAGE) || (val > 0)) { nrOfItemsPerPage = Optional.of(val); } return this; } public Builder presentationTypeHint(@NotNull String val) { presentationTypeHint = Optional.of(Strings.emptyToNull(val)); return this; } public Builder cmCssClass(@NotNull String val) { cmCssClass = Optional.of(Strings.emptyToNull(val)); return this; } public NavigationConfig build() { return new NavigationConfig(this); } } private final boolean enabled; private final Optional<String> configName; private final Optional<Integer> fromHierarchyLevel; private final Optional<Integer> toHierarchyLevel; private final Optional<Integer> showInactiveToLevel; private final Optional<String> menuPart; private final Optional<SpaceReference> nodeSpaceRef; private final Optional<String> dataType; private final Optional<String> layoutType; private final Optional<Integer> nrOfItemsPerPage; private final Optional<String> presentationTypeHint; private final Optional<String> cmCssClass; private NavigationConfig() { this(new Builder().disable()); } private NavigationConfig(@NotNull Builder builder) { this.enabled = builder.enabled; this.configName = builder.configName; this.fromHierarchyLevel = builder.fromHierarchyLevel; this.toHierarchyLevel = builder.toHierarchyLevel; this.showInactiveToLevel = builder.showInactiveToLevel; this.menuPart = builder.menuPart; this.nodeSpaceRef = builder.nodeSpaceRef; this.dataType = builder.dataType; this.layoutType = builder.layoutType; this.nrOfItemsPerPage = builder.nrOfItemsPerPage; this.presentationTypeHint = builder.presentationTypeHint; this.cmCssClass = builder.cmCssClass; } @NotNull final public NavigationConfig overlay(@NotNull NavigationConfig newConf) { boolean newEnabled = enabled || newConf.enabled; if (newEnabled) { Builder b = new Builder(); b.configName = newConf.configName.or(configName); b.fromHierarchyLevel = newConf.fromHierarchyLevel.or(fromHierarchyLevel); b.toHierarchyLevel = newConf.toHierarchyLevel.or(toHierarchyLevel); b.showInactiveToLevel = newConf.showInactiveToLevel.or(showInactiveToLevel); b.menuPart = newConf.menuPart.or(menuPart); b.dataType = newConf.dataType.or(dataType); b.nodeSpaceRef = newConf.nodeSpaceRef.or(nodeSpaceRef); b.layoutType = newConf.layoutType.or(layoutType); b.nrOfItemsPerPage = newConf.nrOfItemsPerPage.or(nrOfItemsPerPage); b.presentationTypeHint = newConf.presentationTypeHint.or(presentationTypeHint); b.cmCssClass = newConf.cmCssClass.or(cmCssClass); return b.build(); } else { return DEFAULTS; } } public boolean isEnabled() { return enabled; } @NotNull public String getConfigName() { return configName.or(""); } public int getFromHierarchyLevel() { return Math.max(fromHierarchyLevel.or(DEFAULT_MIN_LEVEL), DEFAULT_MIN_LEVEL); } public int getToHierarchyLevel() { return toHierarchyLevel.or(DEFAULT_MAX_LEVEL); } public int getShowInactiveToLevel() { return showInactiveToLevel.or(DEFAULT_MIN_LEVEL - 1); } @NotNull public String getMenuPart() { return menuPart.or(""); } @NotNull public Optional<SpaceReference> getNodeSpaceRef() { if (nodeSpaceRef.isPresent()) { return Optional.of(getModelUtils().cloneRef(nodeSpaceRef.get(), SpaceReference.class)); } return Optional.absent(); } @NotNull public String getDataType() { return dataType.or(PAGE_MENU_DATA_TYPE); } @NotNull public String getLayoutType() { return layoutType.or(LIST_LAYOUT_TYPE); } public int getNrOfItemsPerPage() { return Math.max(nrOfItemsPerPage.or(UNLIMITED_ITEMS_PER_PAGE), UNLIMITED_ITEMS_PER_PAGE); } @NotNull public Optional<IPresentationTypeRole> getPresentationType() { String thePresentationTypeHint = presentationTypeHint.or("default"); try { LOGGER.info("setPresentationType to [" + thePresentationTypeHint + "]."); return Optional.of(Utils.getComponent(IWebUtilsService.class).lookup( IPresentationTypeRole.class, thePresentationTypeHint)); } catch (ComponentLookupException failedToLoadException) { LOGGER.error("setPresentationType failed to load IPresentationTypeRole for hint [" + thePresentationTypeHint + "].", failedToLoadException); } return Optional.absent(); } @NotNull public String getCssClass() { return cmCssClass.or(""); } private static ModelUtils getModelUtils() { return Utils.getComponent(ModelUtils.class); } }