package org.seasar.jsf.render.html;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

import org.seasar.jsf.JsfConstants;
import org.seasar.jsf.component.UIElement;
import org.seasar.jsf.util.BindingUtil;
import org.seasar.jsf.util.RenderUtil;

public class HtmlElementRenderer extends Renderer {

	public void encodeBegin(FacesContext facesContext, UIComponent component)
			throws IOException {

		if (!component.isRendered()) {
			return;
		}
		ResponseWriter writer = facesContext.getResponseWriter();
		if (!(component instanceof UIElement)) {
			throw new IllegalArgumentException("not UIElementNode");
		}
		String tagName = ((UIElement) component).getTagName();
		writer.startElement(tagName, component);
		renderAttributes(writer, component);
	}

	public void encodeEnd(FacesContext facesContext, UIComponent component)
			throws IOException {

		if (!component.isRendered()) {
			return;
		}
		ResponseWriter writer = facesContext.getResponseWriter();
		writer.endElement(((UIElement) component).getTagName());
	}

	/**
	 * @see javax.faces.render.Renderer#getRendersChildren()
	 */
	public boolean getRendersChildren() {
		return true;
	}

	/**
	 * @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext,
	 *      javax.faces.component.UIComponent)
	 */
	public void encodeChildren(FacesContext context, UIComponent component)
			throws IOException {

		if (!component.isRendered()) {
			return;
		}
		RenderUtil.encodeChildren(context, component);
	}

	protected void renderAttributes(ResponseWriter writer, UIComponent component)
			throws IOException {

		UIElement elem = (UIElement) component;
		Map attrs = component.getAttributes();
		for (Iterator i = attrs.keySet().iterator(); i.hasNext();) {
			String attrName = (String) i.next();
			if (attrName.indexOf('.') > 0) {
				continue;
			}
			Object value = getValue(component, attrName);
			renderAttribute(writer, attrName, value, attrName);
		}
		String[] bindingPropertyNames = elem.getBindingPropertyNames();
		for (int i = 0; i < bindingPropertyNames.length; ++i) {
			String name = bindingPropertyNames[i];
			Object value = BindingUtil.getBindingValue(component, name);
			renderAttribute(writer, name, value, name);
		}
	}

	protected Object getValue(UIComponent component, String propertyName) {
		Object value = component.getAttributes().get(propertyName);
		if (value != null) {
			return value;
		}
		return BindingUtil.getBindingValue(component, propertyName);
	}

	protected void renderAttribute(ResponseWriter writer, String attributeName,
			Object value, String propertyName) throws IOException {
		if (value == null) {
			return;
		}
		if (attributeName.equalsIgnoreCase(JsfConstants.STYLE_CLASS_ATTR)) {
			attributeName = JsfConstants.CLASS_ATTR;
		}
		writer.writeAttribute(attributeName, value, propertyName);
	}
}