/**
 * 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.util.Iterator;

import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;

import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.event.AjaxListener;
import org.ajax4jsf.event.AjaxSource;
import org.ajax4jsf.renderkit.RendererUtils;


/**
 * Quite different from default <code>HtmlForm</code> - process child components
 * not only for submitted form, but if submitted parent <code>AjaxContainer</code>
 * @author shura (latest modification by $Author: alexsmirnov $)
 * @version $Revision: 1.1.2.3 $ $Date: 2007/02/06 16:23:22 $
 *
 */
public abstract class UIAjaxForm extends UIForm implements AjaxComponent, AjaxSource, IterationStateHolder 
{
    public static final String COMPONENT_TYPE = "org.ajax4jsf.Form";
    public static final String FOCUS_DATA_ID = "_A4J.AJAX.focus";

    /* (non-Javadoc)
     * @see javax.faces.component.UIComponent#processDecodes(javax.faces.context.FacesContext)
     */
    public void processDecodes(javax.faces.context.FacesContext context)
    {
        if (context == null) {
			throw new NullPointerException("context");
		}
        decode(context);
        if (mustProcessed(context))
        {
            for (Iterator<UIComponent> it = getFacetsAndChildren(); it.hasNext();)
            {
                UIComponent childOrFacet = (UIComponent) it.next();
                childOrFacet.processDecodes(context);
            }
        }
    }

    
    /* (non-Javadoc)
     * @see javax.faces.component.UIComponent#processValidators(javax.faces.context.FacesContext)
     */
    public void processValidators(javax.faces.context.FacesContext context)
    {
        if (context == null) throw new NullPointerException("context");
        if (mustProcessed(context))
        {
            for (Iterator<UIComponent> it = getFacetsAndChildren(); it.hasNext();)
            {
                UIComponent childOrFacet = (UIComponent) it.next();
                childOrFacet.processValidators(context);
            }
        }
    }
    
    

    /* (non-Javadoc)
     * @see javax.faces.component.UIComponent#processUpdates(javax.faces.context.FacesContext)
     */
    public void processUpdates(javax.faces.context.FacesContext context)
    {
        if (context == null) throw new NullPointerException("context");
        if (mustProcessed(context))
        {
            for (Iterator<UIComponent> it = getFacetsAndChildren(); it.hasNext();)
            {
                UIComponent childOrFacet = (UIComponent) it.next();
                childOrFacet.processUpdates(context);
            }
        }
    }

    /**
     * Test for condition processing decoders/validators/updates
     * @param context current <code>FacesContext</code>
     * @return true if submitted parent AjaxContainer or current form.
     */
    private boolean mustProcessed(FacesContext context)
    {
//        if ( !AjaxContext.getCurrentInstance(context).isAjaxRequest(context)) {
            if (!isSubmitted() ) {
                return false;
            }
//        }
        return true;
    }
    

	/* (non-Javadoc)
	 * @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent)
	 */
	public void broadcast(FacesEvent event) throws AbortProcessingException {
		// perform default
		super.broadcast(event);
		/*if (event instanceof AjaxEvent) {
			// complete re-Render fields. AjaxEvent deliver before render response.
			setupReRender();
		}*/
		if (event instanceof AjaxEvent)
        {
            FacesContext context = this.getFacesContext();
            // complete re-Render fields. AjaxEvent deliver before render
            // response.
            this.setupReRender(context);
            // Put data for send in response
            Object data = this.getData();
            AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
            if (null != data)
            {
                ajaxContext.setResponseData(data);
            }
            String focus = this.getFocus();
            if (null != focus)
            {
                // search for component in tree.
                // XXX - use more pourful search, as in h:outputLabel
                // component.
                UIComponent focusComponent = RendererUtils.getInstance().findComponentFor(this, focus);
                if (null != focusComponent)
                {
                    focus = focusComponent.getClientId(context);
                }
                ajaxContext.getResponseDataMap().put(FOCUS_DATA_ID, focus);
            }
            ajaxContext.setOncomplete(this.getOncomplete());
        }
	}


	/**
	 * Template methods for fill set of resions to render in subclasses.
	 */
	protected void setupReRender() {
		FacesContext context = getFacesContext();
		AjaxContext.getCurrentInstance(context).addRegionsFromComponent(this);
	}

	protected void setupReRender(final FacesContext facesContext){
        AjaxContext.getCurrentInstance(facesContext).addRegionsFromComponent(this);
        this.setupReRender();
    }



	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxSource#addAjaxListener(org.ajax4jsf.framework.ajax.AjaxListener)
	 */
	public void addAjaxListener(AjaxListener listener) {
        addFacesListener(listener);		
	}


	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxSource#getAjaxListeners()
	 */
	public AjaxListener[] getAjaxListeners() {
        AjaxListener al[] = (AjaxListener [])
	    getFacesListeners(AjaxListener.class);
        return (al);

	}


	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxSource#removeAjaxListener(org.ajax4jsf.framework.ajax.AjaxListener)
	 */
	public void removeAjaxListener(AjaxListener listener) {
		removeFacesListener(listener);
		
	}
    
	public abstract boolean isAjaxSubmit();
	
	public abstract void setAjaxSubmit(boolean ajax);
 
	public Object getIterationState() {
		return isSubmitted() ? Boolean.TRUE : Boolean.FALSE;
	}
	
	public void setIterationState(Object state) {
		setSubmitted(Boolean.TRUE.equals(state));
	}
}
