/**
 * 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.ajax4jsf.component;

import java.io.IOException;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIPanel;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;

import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.context.AjaxContextImpl;
import org.ajax4jsf.context.InvokerCallback;
import org.ajax4jsf.event.AjaxListener;
import org.ajax4jsf.renderkit.AjaxContainerRenderer;

/**
 * @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
 * @version $Revision: 1.1.2.3 $ $Date: 2007/02/08 15:02:06 $
 * 
 */
public abstract class UIAjaxRegion extends UIPanel implements AjaxContainer {

	private AjaxRegionBrige brige;

	public static final String COMPONENT_TYPE = "org.ajax4jsf.AjaxRegion";

	/**
	 * 
	 */
	public UIAjaxRegion() {
		brige = new AjaxRegionBrige(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
	 */
//	public void encodeBegin(FacesContext context) throws IOException {
//		UIViewRoot root = context.getViewRoot();
//		if (root instanceof AjaxViewRoot) {
//			((AjaxViewRoot) root).addAjaxRegion(this);
//		}
//		super.encodeBegin(context);
//	}

	private InvokerCallback _ajaxInvoker = new InvokerCallback() {

		public void invoke(FacesContext context, UIComponent component) {
			try {
				if (component instanceof AjaxContainer) {
					AjaxContainer ajax = (AjaxContainer) component;
					ajax.encodeAjax(context);
				} else {
					// Container not found, use Root for encode.
					encodeAjax(context);
				}
			} catch (IOException e) {
				throw new FacesException(e);
			}
		}

		public void invokeRoot(FacesContext context) {
			try {
				encodeAjax(context);
			} catch (IOException e) {
				throw new FacesException(e);
			}
		}
	};

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.component.UIComponentBase#encodeChildren(javax.faces.context.FacesContext)
	 */
	public void encodeChildren(FacesContext context) throws IOException {
		// If this region is single child of ViewRoot, encode Ajax response for
		// submitted container.
		UIViewRoot viewRoot = context.getViewRoot();
		AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
		if ( (getParent() == viewRoot) && 
				(viewRoot instanceof AjaxViewRoot) &&
				((AjaxViewRoot) viewRoot).isHavePage() &&
				(ajaxContext.isAjaxRequest())) {
			AjaxContextImpl.invokeOnRegionOrRoot((AjaxViewRoot) viewRoot, context, _ajaxInvoker);
		} else {
			super.encodeChildren(context);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#broadcast(javax.faces.event.FacesEvent)
	 */
	public void broadcast(FacesEvent event) throws AbortProcessingException {
		super.broadcast(event);
		brige.broadcast(event);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#getAjaxListener()
	 */
	public MethodBinding getAjaxListener() {
		return brige.getAjaxListener();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isImmediate()
	 */
	public boolean isImmediate() {
		return brige.isImmediate();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isSubmitted()
	 */
	public boolean isSubmitted() {
		return brige.isSubmitted();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#restoreState(javax.faces.context.FacesContext,
	 *      java.lang.Object)
	 */
	public void restoreState(FacesContext context, Object state) {
		Object[] mystate = (Object[]) state;
		super.restoreState(context, mystate[0]);
		brige.restoreState(context, mystate[1]);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#saveState(javax.faces.context.FacesContext)
	 */
	public Object saveState(FacesContext context) {
		Object[] state = new Object[2];
		state[0] = super.saveState(context);
		state[1] = brige.saveState(context);
		return state;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#setAjaxListener(javax.faces.el.MethodBinding)
	 */
	public void setAjaxListener(MethodBinding ajaxListener) {
		brige.setAjaxListener(ajaxListener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#setImmediate(boolean)
	 */
	public void setImmediate(boolean immediate) {
		brige.setImmediate(immediate);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#setSubmitted(boolean)
	 */
	public void setSubmitted(boolean submitted) {
		brige.setSubmitted(submitted);
	}

	public void addAjaxListener(AjaxListener listener) {
		addFacesListener(listener);
	}

	public AjaxListener[] getAjaxListeners() {
		return (AjaxListener[]) getFacesListeners(AjaxListener.class);
	}

	public void removeAjaxListener(AjaxListener listener) {
		removeFacesListener(listener);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isSelfRendered()
	 */
	public boolean isSelfRendered() {
		return brige.isSelfRendered();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#setSelfRendered(boolean)
	 */
	public void setSelfRendered(boolean selfRendered) {
		brige.setSelfRendered(selfRendered);
	}

	public void encodeAjax(FacesContext context) throws IOException {
		String rendererType = getRendererType();
		if (rendererType != null) {
			((AjaxContainerRenderer) getRenderer(context)).encodeAjax(context,
					this);
		}

	}

}
