/* FacesUtil.java

	Purpose:
		
	Description:
		
	History:
		2013/6/27, Dennis

Copyright (C) 2010 Potix Corporation. All Rights Reserved.

*/
package org.zkoss.zss.jsf.ui.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;

/**
 * Utility to handle faces stuff
 * @author dennis
 *
 */
public class FacesUtil {

	public static FacesContext getContext(){
		FacesContext context = FacesContext.getCurrentInstance();
		if(context==null)
			throw new RuntimeException("faces context not found");
		return context;
	}
	
	public static boolean isAjaxRequest() {
		FacesContext context = getContext();
		return context.getPartialViewContext().isAjaxRequest();
	}
	
	public static UIComponent searchComponent(String id) {
		return searchComponent(null,id);
	}
	
	public static UIComponent searchComponent(UIComponent base, final String id) {
		FacesContext context = FacesContext.getCurrentInstance();
		 
		final char sepChar = UINamingContainer.getSeparatorChar(context);
	    final String SEPARATOR_STRING = String.valueOf(sepChar);
		
		if(id.startsWith(SEPARATOR_STRING)){//absolute
			if(base==null){
				base = context.getViewRoot().getChildren().get(0);
			}
			return base.findComponent(id);
		}
		
		
		UIComponent nc = base; 
		UIComponent targetComp = null;
		
		//look up
		while(nc!=null){
			targetComp = nc.findComponent(id);
			if(targetComp!=null){
				return targetComp;
			}
			
			nc = nc.getParent();
			if(!(nc instanceof NamingContainer)){
				nc = nc.getNamingContainer();
			}
		}
		//visit ui tree
		UIViewRoot root = context.getViewRoot();
		
		targetComp = root.findComponent(id);
		
		if(targetComp!=null){
			return targetComp;
		}
		
		final UIComponent[] found = new UIComponent[1];
		VisitContext visitContext = VisitContext.createVisitContext(context);
		
		root.visitTree(visitContext, new VisitCallback() {
			public VisitResult visit(VisitContext context, UIComponent component) {
				if (component.getId().equals(id)) {
					found[0] = component;
					return VisitResult.COMPLETE;
				}
				return VisitResult.ACCEPT;
			}
		});
		return found[0];
	}
	
	public static String toScriptString(String script) {
		StringBuilder sb = new StringBuilder();
		sb.append("<script type=\"text/javascript\">");
		sb.append(script);
		sb.append("</script>");
		return sb.toString();
	}
	
	private static String getUpdateKey(){
		return "$zssjsf.update";
	}
	
	public static void addUpdateScript(String clientId,String script){
		FacesContext context = FacesContext.getCurrentInstance();
		Map<String,Object> reqm = context.getExternalContext().getRequestMap();
		String key = getUpdateKey();
		List<UpdateScript> us = (List<UpdateScript>)reqm.get(key);
		if(us==null){
			reqm.put(key,us = new ArrayList<UpdateScript>(3));
		}
		us.add(new UpdateScript(clientId,script));
	}
	
	public static void clearUpdateScript(String clientId){
		FacesContext context = FacesContext.getCurrentInstance();
		Map<String,Object> reqm = context.getExternalContext().getRequestMap();
		String key = getUpdateKey();
		List<UpdateScript> us = (List<UpdateScript>)reqm.get(key);
		if(us==null){
			return;
		}
		for(int i=us.size()-1;i>=0;i--){
			if(us.get(i).clientId.equals(clientId)){
				us.remove(i);
			}
		}
	}
	public static void clearUpdateScript(){
		FacesContext context = FacesContext.getCurrentInstance();
		Map<String,Object> reqm = context.getExternalContext().getRequestMap();
		String key = getUpdateKey();
		reqm.remove(key);
	}
	
	public static List<String> getUpdateScript(){
		FacesContext context = FacesContext.getCurrentInstance();
		Map<String,Object> reqm = context.getExternalContext().getRequestMap();
		String key = getUpdateKey();
		List<UpdateScript> us = (List<UpdateScript>)reqm.get(key);
		List<String> scripts = new ArrayList<String>();
		if(us==null){
			return scripts;
		}
		for(UpdateScript s:us){
			scripts.add(s.script);
		}
		return scripts;
	}
	
	static class UpdateScript {
		final String clientId;
		final String script;
		public UpdateScript(String clientId,String script){
			this.clientId = clientId;
			this.script = script;
		}
	}
}
