/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.richfaces.renderkit.html;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.ajax4jsf.component.JavaScriptParameter;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.InternetResource;
import org.richfaces.component.UIContextMenu;
import org.richfaces.renderkit.TemplateEncoderRendererBase;
import org.xml.sax.ContentHandler;

/**
 * @author Maksim Kaszynski
 *
 */
public class ContextMenuRendererBase extends
		TemplateEncoderRendererBase {

	private final ContextMenuRendererDelegate delegate = 
		new ContextMenuRendererDelegate();

	private final InternetResource[] ownScripts  = {
		getResource("/org/richfaces/renderkit/html/scripts/json/json-dom.js"),
		getResource("/org/richfaces/renderkit/html/scripts/utils.js"),
		getResource("/org/richfaces/renderkit/html/scripts/context-menu.js")
	
	};
	
	private final InternetResource[] scripts;
	
	public ContextMenuRendererBase() {
		InternetResource[] delegateScripts = delegate.getScripts();
		scripts = new InternetResource[delegateScripts.length + ownScripts.length];
		
		System.arraycopy(delegateScripts, 0, scripts, 0, delegateScripts.length);
		System.arraycopy(ownScripts, 0, scripts, delegateScripts.length, ownScripts.length);
	}
	
	protected InternetResource[] getScripts() {
		return scripts;
	}
	
	protected InternetResource[] getStyles() {
		return delegate.getStyles();
	}
	
	protected Class getComponentClass() {
		return delegate.getComponentClass();
	}


	protected void doEncodeBegin(ResponseWriter writer, FacesContext context,
			UIComponent component) throws IOException {
		writer.startElement(HTML.DIV_ELEM, component);
		writer.writeAttribute(HTML.id_ATTRIBUTE, component.getClientId(context), "id");
	}
	
	
	public void renderChildren(FacesContext context, UIComponent component)
			throws IOException {
		delegate.encodeChildren(context, component);
	}
	

	public void encodeChildren(FacesContext context, UIComponent component)
	throws IOException {
		UIContextMenu menu = (UIContextMenu) component;
		ResponseWriter writer = context.getResponseWriter();
		
		String event = menu.getEvent();
		
		if (event == null) {
			throw new FacesException("Attribute 'event' is not set for component " + component.getClientId(context));
		}
		
		writer.startElement("script", component);
		writer.writeText("new Richfaces.ContextMenu('", null);
		writer.writeText(component.getClientId(context), null);
		writer.writeText("', ", null);
		writer.writeText(menu.getShowDelay() + ", ", null);
		writeScriptBody(context, component, true);
		writer.writeText(")", null);
		writer.writeText(getClientAttachmentOptions(context, menu), null);
		writer.writeText(";", null);
		
		if (menu.isDisableDefaultMenu()) {
			writer.writeText("Richfaces.disableDefaultHandler('", null);
			writer.writeText(event, null);
			writer.writeText("');", null);
		}
		
		writer.endElement("script");
	}

	private String getClientAttachmentOptions(FacesContext context, UIContextMenu contextMenu) {
		String result = "";
		if (contextMenu.isAttached()) {
			JSFunction function = new JSFunction(".attachToParent");
			UIComponent parent = contextMenu.getParent();
			String parentId = parent.getClientId(context);
			
			function.addParameter(parentId);

			String event = contextMenu.getEvent();
			
			function.addParameter(event);
			
			Map params = new LinkedHashMap();
			List children = contextMenu.getChildren();
			
			for (Iterator iterator = children.iterator(); iterator.hasNext();) {
				UIComponent kid = (UIComponent) iterator.next();
				
				if (kid instanceof UIParameter) {
					UIParameter parameter = (UIParameter) kid;
					String name = parameter.getName();
					Object value = parameter.getValue();
					
					if (parameter instanceof JavaScriptParameter && 
							((JavaScriptParameter) parameter).isNoEscape()) {
						value = new JSReference(String.valueOf(value));
					}
					
					params.put(name, value);
				}
				
			}
			
			function.addParameter(params);
			result = function.toScript();
		}
		return result; 
	}
	
	protected void doEncodeEnd(ResponseWriter writer, FacesContext context,
			UIComponent component) throws IOException {
		writer.endElement(HTML.DIV_ELEM);
	}
	
	protected ContentHandler createContentHandler(Writer writer) {
		return new ContextMenuContentHandler(writer, "Richfaces.evalMacro(\"", "\", context)");
	}
}
