/**
* Copyright (C) 2004 idega Software
*
*/
package com.idega.presentation;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import com.idega.idegaweb.IWMainApplication;
import com.idega.idegaweb.IWUserContext;
import com.idega.util.text.AttributeParser;
/**
* @author <a href="mailto:tryggvi@idega.is">Tryggvi Larusson</a>
* @version 1.0
* HTML based Page component.
* This component can be used to template the look and feel
* of your site in a simple manner. You supply an HTML template
* directly.
* Inside the Layout template tags are used to define "regions" where UIComponent
* components can be added in and rendered dynamically.<br>
* The regions are defined like this:
*
* <code><pre>
* <HTML>... <BODY>... <!-- TemplateBeginEditable name="MyUniqueRegionId1" -->MyUniqueRegionId1<!-- TemplateEndEditable --> ... <table><tr><td><!-- TemplateBeginEditable name="MyUniqueRegionId2" -->MyUniqueRegionId2<!-- TemplateEndEditable --</td></tr></table>
* </pre></code>
*
* This class parses the HTML and looks for the tag <code><pre><!-- TemplateBeginEditable ... ></pre></code>
* Where the first region found becomes the "default".
* This class also parses the <code><pre> <HEAD> </pre></code> attribute contents and includes the things normally found inside
* an idegaWeb Page.
*/
public class HtmlPage extends Page {
private String html;
//private String family = RenderUtils.SMILE_FAMILY;
private Map regionMap;
//This variable sets if regions are treated as facets if set to true. Otherwise they are treated as children
private boolean regionAsFacet=false;
public HtmlPage() {
super();
}
/**
* @return
*/
public void setResource(InputStream htmlStream) {
//String ret = "";
//ret = getHtml();
//if(ret == null && getResourceName() != null) {
//InputStream htmlStream = this.getClass().getClassLoader().getResourceAsStream(getResourceName());
if(htmlStream != null) {
try {
InputStreamReader htmlReader = new InputStreamReader(htmlStream);
StringBuffer html = new StringBuffer();
int nr = 0;
char[] buffer = new char[1024];
while(nr != -1) {
nr = htmlReader.read(buffer);
if(nr != -1) {
html.append(buffer,0,nr);
}
}
setHtml(html.toString());
//ret = getHtml();
htmlReader.close();
} catch(IOException e) {
throw new RuntimeException("Attribute <resourceName> for component <" + getId() + ">. Could not load the html from named resource <>");
}
}
//}
findOutRegions();
//return ret;
}
/**
* Need to render my children myself. Typical for layout
* management components.
*
* @see javax.faces.component.UIComponent#getRendersChildren()
*/
public boolean getRendersChildren() {
return true;
}
/**
* Gets the default (first found) region.
* Returns null if none is found.
* @return
*/
public String getDefaultRegion(){
for (Iterator iter = getRegionIdsMap().keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
Integer value = (Integer) getRegionIdsMap().get(key);
if(value.intValue()==0){
return key;
}
}
return null;
}
/**
*
*/
public List getChildren(){
//return getChildren(getDefaultRegion());
return super.getChildren();
}
/**
*
*/
protected void setChildren(List newChildren)
{
//setChildren(getDefaultRegion(),newChildren);
super.setChildren(newChildren);
}
public UIComponent getRegion(String regionKey){
if(this.regionAsFacet){
Object o = getFacets().get(regionKey);
UIComponent region = (UIComponent) o;
return region;
}
else{
Integer index = (Integer) getRegionIdsMap().get(regionKey);
if(index!=null){
Object o = getChildren().get(index.intValue());
UIComponent child = (UIComponent) o;
return child;
}
else{
return null;
}
}
}
public void setRegion(String regionKey,UIComponent region){
if(this.regionAsFacet){
/*Object previous = */getFacets().get(regionKey);
if(regionKey!=null){
getFacets().put(regionKey,region);
}
}
else{
getChildren().add(region);
}
}
public void add(UIComponent component,String regionId){
UIComponent region = getRegion(regionId);
if(region!=null){
region.getChildren().add(component);
}
else{
getLogger().info("No Region found for regionId="+regionId);
}
}
public void add(UIComponent comp){
add(comp,getDefaultRegion());
}
public void add(PresentationObject po){
add((UIComponent)po);
}
/**
* The Map over the regions.
* Has as a key the regionId and as the value the index of
* the corresponding HtmlPageRegion object int the getChildren() List.
* @return
*/
private Map getRegionIdsMap() {
if (this.regionMap==null){
this.regionMap=new HashMap();
}
return this.regionMap;
}
/**
* Returns all the regionIds as Strings
* @return
*/
public Set getRegionIds(){
return getRegionIdsMap().keySet();
}
private void findOutRegions(){
String template = getHtml();
if(template != null) {
String[] parts = template.split("<!-- TemplateBeginEditable");
//out.write(parts[0]);
int regionIndex=0;
for (int i = 1; i < parts.length; i++) {
String part = parts[i];
String[] t = part.split("TemplateEndEditable -->");
String toParse = t[0];
String[] a1=toParse.split("name=\"");
String[] a2 = a1[1].split("\"");
String regionId=a2[0];
getRegionIdsMap().put(regionId,new Integer(regionIndex));
//instanciate the region in the children list:
HtmlPageRegion region = new HtmlPageRegion();
region.setRegionId(regionId);
setRegion(regionId,region);
//getChildren().add(region);
//getChildren().set(regionIndex,region);
regionIndex++;
}
}
}
/**
* Overrided from Page
*/
public void encodeBegin(FacesContext context)throws IOException{
//Does nothing here
}
/**
* Overrided from Page
* @throws IOException
*/
public void encodeChildren(FacesContext context) throws IOException{
//Does just call the print(iwc) method below:
callPrint(context);
}
/**
* Overrided from Page
*/
public void encodeEnd(FacesContext context)throws IOException{
//Does nothing here
}
/**
* @see javax.faces.component.UIComponent#encodeChildren(javax.faces.context.FacesContext)
*/
//public void encodeChildren(FacesContext ctx) throws IOException {
public void print(IWContext ctx) throws IOException {
Writer out;
//ResponseWriter out = ctx.getResponseWriter();
//RenderUtils.ensureAllTagsFinished();
if(IWMainApplication.useJSF){
out = ctx.getResponseWriter();
}
else{
out = ctx.getWriter();
}
String template = getHtml();
if(template != null) {
//Process the HEAD first:
Pattern headOpensPattern = Pattern.compile("<head>", Pattern.CASE_INSENSITIVE);
String[] headOpensSplit = headOpensPattern.split(template);
//String[] headOpensSplit = template.split("<head>");
String preHead = headOpensSplit[0];
String postHeadOpens = headOpensSplit[1];
out.write(preHead);
out.write("<head>");
Pattern headClosesPattern = Pattern.compile("</head>", Pattern.CASE_INSENSITIVE);
String[] headClosesSplit = headClosesPattern.split(postHeadOpens);
// String[] headClosesSplit = postHeadOpens.split("</head>");
String headContent = headClosesSplit[0];
String body = headClosesSplit[1];
//Get the contents from the superclass first
out.write(getHeadContents(ctx));
Script associatedScript = getAssociatedScript();
renderChild(ctx,associatedScript);
//then printout the head contents from the html page
//find out where the title is in the head:
String htmlTitle="";
try{
//Try to find where the TITLE tag is in the HEAD:
Pattern titlePattern = Pattern.compile("<title>", Pattern.CASE_INSENSITIVE);
String[] titleSplit = titlePattern.split(headContent);
//String[] titleSplit = headContent.split("<title>");
String preTitleHead= titleSplit[0];
String postTitleOpens = titleSplit[1];
Pattern postTitlePattern = Pattern.compile("</title>", Pattern.CASE_INSENSITIVE);
String[] postTitleSplit = postTitlePattern.split(postTitleOpens);
//String[] postTitleSplit = postTitleOpens.split("</title>");
htmlTitle = postTitleSplit[0];
String postTitleHead = postTitleSplit[1];
//Print out all befor the TITLE tag in the HEAD
out.write(preTitleHead);
//Print out the title from the idegaWeb page
String locTitle = this.getLocalizedTitle(ctx);
out.write("<title>");
if(locTitle!=null && !locTitle.equals("")){
out.write(locTitle);
}
else{
out.write(htmlTitle);
}
out.write("</title>");
//Print out all after the TITLE tag in the HEAD
out.write(postTitleHead);
}
catch(ArrayIndexOutOfBoundsException ae){
//If there is an error (title not found)
//then just write out the whole head contents + idegaWeb Title
out.write(headContent);
String locTitle = this.getLocalizedTitle(ctx);
out.write("<title>");
if(locTitle!=null && !locTitle.equals("")){
out.write(locTitle);
}
else{
out.write(htmlTitle);
}
out.write("</title>");
}
out.write("</head>");
String[] htmlBody = body.split("<body");
int index = 0;
if (htmlBody.length > 1) {
out.write(htmlBody[index++]);
}
body = htmlBody[index];
String attributes = body.substring(0, body.indexOf(">"));
Map attributeMap = AttributeParser.parse(attributes);
Iterator iter = attributeMap.keySet().iterator();
while (iter.hasNext()) {
String attribute = (String) iter.next();
String value = (String) attributeMap.get(attribute);
if (attribute.equals("onload")) {
this.setMarkupAttributeMultivalued("onload", value);
}
if (attribute.equals("onunload")) {
this.setMarkupAttributeMultivalued("onunload", value);
}
else {
if (!isMarkupAttributeSet(attribute)) {
setMarkupAttribute(attribute, value);
}
}
}
out.write("<body " + getMarkupAttributesString() + " >\n");
body = body.substring(body.indexOf(">") + 1);
//Process the template regions:
String[] parts = body.split("<!-- TemplateBeginEditable");
out.write(parts[0]);
for (int i = 1; i < parts.length; i++) {
String part = parts[i];
String[] t = part.split("TemplateEndEditable -->");
String toParse = t[0];
String[] a1=toParse.split("name=\"");
String[] a2 = a1[1].split("\"");
String regionId=a2[0];
//int childNumber = Integer.parseInt(t[0]) - 1;
try{
UIComponent region = getRegion(regionId);
renderChild(ctx,region);
}
catch(ClassCastException cce){
cce.printStackTrace();
}
out.write(t[1]);
}
} else {
//out.startElement("p",null);
out.write("Template file could not be found.");
//out.endElement("p");
List children = getChildren();
for (Iterator iter = children.iterator(); iter.hasNext();) {
UIComponent element = (UIComponent) iter.next();
renderChild(ctx,element);
}
}
}
/**
* @see javax.faces.component.UIPanel#saveState(javax.faces.context.FacesContext)
*/
public Object saveState(FacesContext ctx) {
Object values[] = new Object[4];
values[0] = super.saveState(ctx);
values[1] = getHtml();
values[2] = this.regionMap;
values[3] = Boolean.valueOf(this.regionAsFacet);
//values[2] = getResourceName();
return values;
}
/**
* @see javax.faces.component.UIPanel#restoreState(javax.faces.context.FacesContext, java.lang.Object)
*/
public void restoreState(FacesContext ctx, Object state) {
Object values[] = (Object[])state;
super.restoreState(ctx, values[0]);
setHtml((String)values[1]);
this.regionMap = (Map)values[2];
this.regionAsFacet = ((Boolean)values[3]).booleanValue();
//setResourceName((String)values[2]);
}
/**
* @return
*/
public String getHtml() {
return this.html;
}
/**
* @param string
*/
public void setHtml(String string) {
this.html = string;
findOutRegions();
}
// /**
// * @see javax.faces.component.UIComponent#decode(javax.faces.context.FacesContext)
// */
// public void decode(FacesContext ctx) {
// List children = getChildren();
// for (Iterator iter = children.iterator(); iter.hasNext();) {
// UIComponent comp = (UIComponent) iter.next();
// comp.decode(ctx);
// }
// }
/* (non-Javadoc)
* @see com.idega.presentation.PresentationObject#main(com.idega.presentation.IWContext)
*/
public Object clone(IWUserContext iwc, boolean askForPermission){
HtmlPage newPage = (HtmlPage) super.clone(iwc,askForPermission);
if(this.regionMap!=null){
newPage.regionMap=(Map)((HashMap) this.regionMap).clone();
}
return newPage;
}
public void main(IWContext iwc) throws Exception {
// TODO Auto-generated method stub
super.main(iwc);
}
/* (non-Javadoc)
* @see com.idega.presentation.PresentationObject#_main(com.idega.presentation.IWContext)
*/
public void _main(IWContext iwc) throws Exception {
// TODO Auto-generated method stub
super._main(iwc);
}
/**
* This variable gets if regions are treated as facets if set to true.
* Default is false.
* @return Returns the regionAsFacet.
*/
protected boolean isRegionAsFacet() {
return this.regionAsFacet;
}
/**
* This sets if regions are treated as facets if set to true. Otherwise they are treated as children.
* Default value is set to false.
* @param regionAsFacet The regionAsFacet to set.
*/
protected void setRegionAsFacet(boolean regionAsFacet) {
this.regionAsFacet = regionAsFacet;
}
public Map getFacets(){
if(this.facetMap==null){
this.facetMap = new HtmlPageRegionFacetMap(this);
}
return this.facetMap;
}
}