package com.revolsys.ui.web.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.jexl.Expression;
import org.apache.log4j.Logger;
import com.revolsys.ui.html.view.Script;
import com.revolsys.ui.html.view.Style;
import com.revolsys.ui.web.exception.ActionException;
import com.revolsys.ui.web.exception.PageNotFoundException;
import com.revolsys.util.JexlUtil;
import com.revolsys.util.UrlUtil;
public class PageController implements SiteNodeController {
private static final Logger log = Logger.getLogger(PageController.class);
/** The list of actions to perform on this page. */
private Collection actions = new ArrayList();
protected List arguments = new ArrayList();
protected Map argumentsMap = new HashMap();
protected List attributes = new ArrayList();
protected HashMap attributesMap = new HashMap();
protected Config config;
private Layout layout;
protected long menuId;
private Map menus = new HashMap();
/** The site node for this page. */
private SiteNode node = new SiteNode(this);
protected Map properties = new HashMap();
/** The list of client side scripts for the page. */
private final Collection scripts = new ArrayList();
protected boolean secure;
/** The list of style sheets for the page. */
private final Collection styles = new ArrayList();
protected String title = "";
private Expression titleExpression;
public PageController() {
}
public PageController(final Config config, final String name) {
this.config = config;
}
public PageController(final PageController page) {
this.node.setNodes(page.getNodes());
// TODO clone
this.actions.addAll(page.getActions());
setPath(page.getPath());
// TODO do a deep clone
this.menus.putAll(page.getMenus());
this.styles.addAll(page.getStyles());
this.scripts.addAll(page.getScripts());
this.menuId = page.menuId;
this.title = page.title;
this.properties.putAll(page.properties);
this.arguments.addAll(page.arguments);
this.argumentsMap.putAll(page.argumentsMap);
this.attributes.addAll(page.attributes);
this.attributesMap.putAll(page.attributesMap);
}
public void addArgument(final Argument argument) {
if (!hasArgument(argument.getName())) {
this.arguments.add(argument);
this.argumentsMap.put(argument.getName(), argument);
}
if (argument.isInheritable()) {
// TODOhow to add this to sub pages
// for (Iterator pages = this.pages.values().iterator(); pages.hasNext();)
// {
// Page page = (Page)pages.next();
// addArgument(argument);
// }
}
}
public void addField(final Attribute attribute) {
if (!hasArgument(attribute.getName())) {
this.attributes.add(attribute);
this.attributesMap.put(attribute.getName(), attribute);
}
if (attribute.isInheritable()) {
// TODO deal with inheritance
}
}
public void addMenu(final com.revolsys.ui.model.Menu menu) {
this.menus.put(menu.getName(), menu);
}
public void addProperty(final String name, final String value) {
this.properties.put(name, value);
}
@Override
public Object clone() {
return new PageController(this);
}
@Override
public boolean equals(final Object o) {
if (o instanceof PageController) {
final PageController p = (PageController)o;
if (super.equals(o) && p.menuId == this.menuId && p.getPath().equals(getPath())
&& (p.title == this.title
|| p.title != null && this.title != null && p.title.equals(this.title))
&& p.properties.equals(this.properties)) {
return true;
}
}
return false;
}
/**
* Forward the request to the specified resource.
*
* @param servletContext The servlet context.
* @param request the parameters of the client request
* @param response the response sent back to the client
* @param path the path to the resource to forward to
* @exception ServletException if there was a problem handling the request
* @exception IOException if an input output error occurs when handling the
* request
*/
public void forward(final ServletContext servletContext, final HttpServletRequest request,
final HttpServletResponse response, final String path) throws ServletException, IOException {
if (!response.isCommitted()) {
servletContext.getRequestDispatcher(path).forward(request, response);
}
}
public String getAbsolutePath() {
return WebUiContext.get().getConfig().getBasePath() + this.node.getFullPath();
}
/**
* @return Returns the actions.
*/
public Collection getActions() {
return this.actions;
}
public List getArguments() {
return this.arguments;
}
/**
* @return Returns the config.
*/
public Config getConfig() {
return this.config;
}
public List getFields() {
return this.attributes;
}
public String getFullPath() {
if (this.secure) {
return getAbsolutePath() + ".wps";
} else {
return getAbsolutePath() + ".wp";
}
}
public String getFullUrl() {
return getFullUrl(Collections.EMPTY_MAP);
}
public String getFullUrl(final Map parameters) {
final WebUiContext iafContext = WebUiContext.get();
final Map uriParameters = new HashMap(parameters);
if (iafContext != null) {
final HttpServletRequest request = iafContext.getRequest();
if (request != null) {
for (final Iterator arguments = this.arguments.iterator(); arguments.hasNext();) {
final Argument argument = (Argument)arguments.next();
final String name = argument.getName();
if (!uriParameters.containsKey(name)) {
final String value = request.getParameter(name);
if (value != null) {
uriParameters.put(name, value);
}
}
}
}
}
return UrlUtil.getUrl(getFullPath(), uriParameters);
}
public Layout getLayout() {
return this.layout;
}
public Menu getMenu(final String name) {
return (Menu)this.menus.get(name);
}
public long getMenuId() {
return this.menuId;
}
public Collection getMenuList() {
return this.menus.values();
}
/**
* @return Returns the menus.
*/
public Map getMenus() {
return this.menus;
}
/**
* @return Returns the node.
*/
@Override
public SiteNode getNode() {
return this.node;
}
public Collection getNodes() {
return this.node.getNodes();
}
@Override
public String getPath() {
return this.node.getPath();
}
public String getProperty(final String name) {
return (String)this.properties.get(name);
}
/**
* @return Returns the scripts.
*/
public Collection getScripts() {
return this.scripts;
}
/**
* @return Returns the styles.
*/
public Collection getStyles() {
return this.styles;
}
public String getTitle() {
if (this.titleExpression != null) {
final WebUiContext context = WebUiContext.get();
return (String)context.evaluateExpression(this.titleExpression);
} else {
return this.title;
}
}
// TODO deal with inheritable arguments and attributes
public boolean hasArgument(final String name) {
return this.argumentsMap.containsKey(name);
}
public boolean hasAttribute(final String name) {
return this.attributesMap.containsKey(name);
}
/**
* Generate the hash code for the object.
*
* @return The hashCode.
*/
@Override
public int hashCode() {
return super.hashCode() + (getPath().hashCode() << 2);
}
public void invokeActions(final ServletContext servletContext, final HttpServletRequest request,
final HttpServletResponse response) throws IOException, ServletException {
final Iterator actions = getActions().iterator();
while (actions.hasNext()) {
final Action action = (Action)actions.next();
action.process(request, response);
}
}
public final boolean isSecure() {
return this.secure;
}
@Override
public void process(final ServletContext servletContext, final HttpServletRequest request,
final HttpServletResponse response) throws IOException, ServletException {
// WebUiContext.set(new WebUiContext(config, request.getContextPath(), this,
// request, response, null));
if (isSecure() && !this.secure) {
response.sendRedirect(getFullUrl());
return;
}
processArguments(request);
processAttributes(request);
request.setAttribute("niceConfig", this.config);
final String menuName = request.getParameter("menuName");
request.setAttribute("menuSelected", menuName);
request.setAttribute("title", getTitle());
invokeActions(servletContext, request, response);
final Layout layout = getLayout();
if (layout != null) {
final String file = layout.getFile();
if (file != null && file.length() > 0) {
forward(servletContext, request, response, file);
}
}
}
/**
* @param page
* @param request
* @throws PageNotFoundException
*/
private void processArguments(final HttpServletRequest request) throws ActionException {
for (final Iterator arguments = getArguments().iterator(); arguments.hasNext();) {
final Argument argument = (Argument)arguments.next();
final String name = argument.getName();
Object value = null;
String stringValue = request.getParameter(name);
if (stringValue == null) {
stringValue = argument.getDefault();
}
if (stringValue != null) {
final Class argumentType = argument.getType();
try {
value = argument.valueOf(stringValue);
} catch (final NumberFormatException e) {
throw new PageNotFoundException("Page argument is not a valid number: " + name);
}
}
if (value != null) {
request.setAttribute(name, value);
} else if (argument.isRequired()) {
throw new PageNotFoundException("Missing page argument: " + name);
}
}
}
/**
* @param page
* @param request
* @throws PageNotFoundException
*/
private void processAttributes(final HttpServletRequest request) throws ActionException {
for (final Iterator attributes = getFields().iterator(); attributes.hasNext();) {
final Attribute attribute = (Attribute)attributes.next();
final String name = attribute.getName();
final AttributeLoader loader = attribute.getLoader();
Object value = null;
if (loader != null) {
value = loader.getValue(request);
} else {
value = attribute.getValue();
}
if (value != null) {
request.setAttribute(name, value);
}
}
}
/**
* @param actions The actions to set.
*/
public void setActions(final Collection actions) {
this.actions = actions;
}
/**
* @param config The config to set.
*/
public void setConfig(final Config config) {
this.config = config;
}
public void setLayout(final Layout layout) {
this.layout = layout;
setStyles(layout.getStyles());
setScripts(layout.getScripts());
// layout.setPage((Page)this);
}
public void setMenuId(final long menuId) {
this.menuId = menuId;
}
public void setMenuList(final Collection menus) {
for (final Iterator menuIter = menus.iterator(); menuIter.hasNext();) {
final com.revolsys.ui.model.Menu menu = (com.revolsys.ui.model.Menu)menuIter.next();
addMenu(menu);
}
log.debug(this + ":" + getMenus());
}
/**
* @param menus The menus to set.
*/
public void setMenus(final Map menus) {
this.menus = menus;
}
/**
* @param node The node to set.
*/
@Override
public void setNode(final SiteNode node) {
this.node = node;
}
public void setNodes(final Collection nodes) {
this.node.setNodes(nodes);
}
public void setPath(final String path) {
this.node.setPath(path);
}
/**
* @param scripts The scripts to set.
*/
public void setScripts(final Collection scripts) {
for (final Iterator scriptItet = scripts.iterator(); scriptItet.hasNext();) {
final Object element = scriptItet.next();
if (element instanceof Script) {
final Script script = (Script)element;
this.scripts.add(script);
} else if (element instanceof String) {
final String scriptUrl = (String)element;
this.scripts.add(new Script(scriptUrl));
}
}
}
public final void setSecure(final boolean secure) {
this.secure = secure;
}
/**
* @param styles The styles to set.
*/
public void setStyles(final Collection styles) {
for (final Iterator styleIter = styles.iterator(); styleIter.hasNext();) {
final Object element = styleIter.next();
if (element instanceof Style) {
final Style style = (Style)element;
this.styles.add(style);
} else if (element instanceof String) {
final String styleUrl = (String)element;
this.styles.add(new Style(styleUrl));
}
}
log.debug(styles);
}
public void setTitle(final String title) {
if (title != null) {
this.title = title;
try {
this.titleExpression = JexlUtil.newExpression(title);
} catch (final Exception e) {
log.error(e.getMessage(), e);
}
} else {
// this.title = CaseConverter.toCapitalizedWords(getName());
}
}
// public String toString() {
// return title;
// }
}