package origo.helpers;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import play.modules.origo.core.CachedThemeVariant;
import play.modules.origo.core.Node;
import play.modules.origo.core.Themes;
import play.modules.origo.core.ui.RenderedNode;
import play.modules.origo.core.ui.RenderingContext;
import play.modules.origo.core.ui.UIElement;
import java.util.HashMap;
import java.util.Map;
public class ThemeHelper {
private static final Logger LOG = Logger.getLogger(ThemeHelper.class);
public static RenderedNode decorate(Node node) {
CachedThemeVariant themeVariant = loadTheme(node);
return decorate(node, themeVariant);
}
public static RenderedNode decorate(Node node, CachedThemeVariant themeVariant) {
RenderedNode renderedNode = new RenderedNode(node.getNodeId());
setupRegions(themeVariant, renderedNode);
renderedNode.setTitle(node.getTitle());
renderedNode.setTemplate(ReflectionHelper.getTemplate(themeVariant));
RenderingContext renderingContext = new RenderingContext(themeVariant, node);
for (String region : node.getRegions()) {
for (UIElement uiElement : node.getUIElements(region)) {
String decoratedContent = decorate(uiElement, renderingContext);
if (UIElement.META.equalsIgnoreCase(uiElement.getType())) {
if (Node.HEAD.equalsIgnoreCase(region)) {
renderedNode.addMeta(decoratedContent);
} else {
throw new RuntimeException("META is not allowed outside of head");
}
} else if (UIElement.LINK.equalsIgnoreCase(uiElement.getType())) {
if (Node.HEAD.equalsIgnoreCase(region)) {
renderedNode.addLink(decoratedContent);
} else {
throw new RuntimeException("LINK is not allowed outside of head");
}
} else if (UIElement.SCRIPT.equalsIgnoreCase(uiElement.getType())) {
if (Node.HEAD.equalsIgnoreCase(region)) {
renderedNode.addScript(decoratedContent);
} else {
renderedNode.add(region, decoratedContent);
}
} else if (UIElement.STYLE.equalsIgnoreCase(uiElement.getType())) {
if (Node.HEAD.equalsIgnoreCase(region)) {
renderedNode.addStyle(decoratedContent);
} else {
renderedNode.add(region, decoratedContent);
}
} else {
renderedNode.add(region, decoratedContent);
}
}
}
return renderedNode;
}
/**
* Sets all the regions in the rendered node so the template can access them without
* nullpointer even if the page has no ui elements.
*
* @param themeVariant the theme variant that holds the regions available
* @param renderedNode the node about to rendered
*/
private static void setupRegions(CachedThemeVariant themeVariant, RenderedNode renderedNode) {
Map<String, String> regions = new HashMap<String, String>();
for (String region : themeVariant.regions) {
regions.put(region, "");
}
renderedNode.setRegions(regions);
}
public static String decorate(UIElement uiElement, RenderingContext renderingContext) {
Map<String, play.modules.origo.core.CachedDecorator> decorators = Themes.getDecoratorsForTheme(renderingContext.getThemeVariant().themeId);
renderingContext.nestle(uiElement);
String decoratedOutput = null;
if (decorators.containsKey(uiElement.getType())) {
play.modules.origo.core.CachedDecorator decorator = decorators.get(uiElement.getType());
decoratedOutput = ReflectionHelper.invokeDecorator(decorator, null);
}
if (decoratedOutput == null) {
decoratedOutput = DefaultDecorator.decorate(uiElement, renderingContext);
}
renderingContext.unNestle();
return decoratedOutput;
}
public static String decorateChildren(UIElement parent, RenderingContext renderingContext) {
if (!parent.hasChildren()) {
return null;
}
StringBuilder sb = new StringBuilder();
renderingContext.nestle(parent);
for (UIElement childElement : parent.getChildren()) {
sb.append(decorate(childElement, renderingContext));
}
renderingContext.unNestle();
return sb.toString();
}
private static CachedThemeVariant loadTheme(Node node) {
CachedThemeVariant themeVariant = Themes.getThemeVariant(node.getThemeVariant());
if (themeVariant == null) {
String themeVariantId = SettingsHelper.Core.getThemeVariant();
if (StringUtils.isEmpty(themeVariantId)) {
throw new RuntimeException("No theme set for node and no default theme variant set");
}
LOG.debug("Using default theme variant [" + themeVariantId + "]");
themeVariant = Themes.getThemeVariant(themeVariantId);
}
if (themeVariant == null) {
// TODO: Add some sort of fallback for when a theme is removed
throw new RuntimeException("No theme selected for " + node.toString());
}
return themeVariant;
}
}