/**
 * License Agreement.
 *
 *  JBoss RichFaces - Ajax4jsf Component Library
 *
 * 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;

import java.util.HashMap;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import org.ajax4jsf.javascript.DnDScript;
import org.ajax4jsf.javascript.PrototypeScript;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.richfaces.component.Draggable;
import org.richfaces.component.Dropzone;
import org.richfaces.event.DnDEvent;
import org.richfaces.event.DragEvent;
import org.richfaces.renderkit.DnDEventsExchangeMailer.EventCallback;

/**
 * @author shura
 *
 */
public class DraggableRendererContributor implements RendererContributor {
	
	public final static String DRAG_SOURCE_ID = "dragSourceId";
	
	private static final EventCallback dragEventsCallback = new EventCallback() {

		void processEvent(DnDEvent dndEvent, UIComponent source,
				FacesContext facesContext, Object type, Object value) {

			DragEvent dragEvent = (DragEvent) dndEvent;
			dragEvent.setDropTarget((Dropzone) source); 
			dragEvent.setDropValue(value);
			dragEvent.setAcceptedTypes(type);
		}
	};

	private static DraggableRendererContributor instance;

	private DraggableRendererContributor() {
		super();
	}

	public static synchronized RendererContributor getInstance() {
		if (instance == null) {
			instance = new DraggableRendererContributor();
		}
		
		return instance;
	}
	public class DraggableOptions extends ScriptOptions {

		public DraggableOptions(Draggable draggable) {
			//TODO by nick - change this cast
			super((UIComponent) draggable);

			addOption("dragType", draggable.getDragType());
			addEventHandler("ondragstart", draggable.getOndragstart());
			addEventHandler("ondragend", draggable.getOndragend());
		}
		
	}

	public void decode(FacesContext context, UIComponent component, CompositeRenderer compositeRenderer) {
		DnDEventsExchangeMailer eventsExchanger = DnDEventsExchangeMailer.getInstance(context);
		String clientId = component.getClientId(context);
		Map paramMap = context.getExternalContext().getRequestParameterMap();

		if(clientId.equals(paramMap.get(DRAG_SOURCE_ID))){
			String dropTargetId = (String) paramMap.get(DropzoneRendererContributor.DROP_TARGET_ID);
			
			if (compositeRenderer != null) {
				compositeRenderer.contributorDecodeCallback(component, context, this, dropTargetId);
			}

			Draggable draggable = (Draggable) component;
			
			eventsExchanger.mailEvent(dropTargetId, component,
					context, new DragEvent(component), dragEventsCallback, draggable.getDragType(), 
					draggable.getDragValue(), true);
		}
	}	
	
	public String[] getStyleDependencies() {
		return new String[] {
			"/org/richfaces/renderkit/html/css/dragIndicator.xcss"
		};
	}
	
	public String[] getScriptDependencies() {
		return new String[] {
				PrototypeScript.class.getName(),
				"/org/richfaces/renderkit/html/scripts/json/json-mini.js",
				DnDScript.class.getName(),
				"/org/richfaces/renderkit/html/scripts/utils.js",
				"/org/richfaces/renderkit/html/scripts/json/json-dom.js",
				"/org/richfaces/renderkit/html/scripts/dnd/dnd-common.js",
				"/org/richfaces/renderkit/html/scripts/dnd/dnd-draggable.js"
			};
	}
	
	public ScriptOptions buildOptions(FacesContext context, UIComponent component) {
		if (component instanceof Draggable) {
			Draggable draggable = (Draggable) component;
			
			DraggableOptions options =  new DraggableOptions(draggable);

			Map eventOptions = AjaxRendererUtils.buildEventOptions(context, component);
			Map parameters = (Map) eventOptions.get("parameters");

			if (parameters == null) {
				parameters = new HashMap();
			}
			
			String clientId = component.getClientId(context);
			
			parameters.put(DRAG_SOURCE_ID, clientId);
			
			options.addOption("parameters", parameters);
			
			String indicatorId = draggable.getResolvedDragIndicator(context);
			if (indicatorId == null) {
				String simpleId = draggable.getDragIndicator();
				if (simpleId != null) {
					UIComponent indicator = component.findComponent(simpleId);
					if (indicator != null) {
						indicatorId = indicator.getClientId(context);
					}
				}
			}
			
			if (indicatorId != null) {
				options.addOption("dragIndicator", indicatorId);
			}
			
			return options;
		}

		return null;
	}
	
	public String getScriptContribution(FacesContext context,
			UIComponent component) {
		// TODO Auto-generated method stub
		return null;
	}

	public Class getAcceptableClass() {
		return Draggable.class;
	}

}
