package org.richfaces.component;

import javax.faces.application.ViewHandler;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.richfaces.renderkit.DialogWindowUtils;


/**
 * 
 * @author glory
 *
 */

public class DialogOpenListenerImpl implements DialogOpenListener {
	DialogOpenEvent lastProcessedEvent = null;
	/**
	 * This method is invoked during invoke application phase
	 * after navigation handler calculated and set new view id 
	 * (as result of processing an ActionEvent).
	 * Now it is the best time two interfere into its logic 
	 * and 'redistribute' views in parent and child windows.
	 */
	public void processDialogOpen(DialogOpenEvent event) {
		if(lastProcessedEvent == event) return;
		lastProcessedEvent = event; 
		UIComponent c = event.getComponent();
		if(!(c instanceof UIDialogWindow)) return;
		UIDialogWindow component = (UIDialogWindow)c;
		
		/*
		 * If dialog is not needed, nothing else is to be done.
		 * 
		 */
		if(ActionPrefixHolder.PREFIX_NORMAL.equals(component.prefix)) {
			if(!event.isClose()) {
				rejectOpen();
			}
			return;
		}
		if(component.isNullPath()) {
			if(!event.isClose()) {
				rejectOpen();
				return;
			}
		}

		FacesContext context = FacesContext.getCurrentInstance();
		UIViewRoot viewroot = context.getViewRoot();
		ViewHandler vh = UIDialogAction.getViewHandler(context);
		UIViewRoot oldRoot = event.getSourceViewRoot();

		if(!event.isClose()) {
			/*
			 * Child dialog is about to open.
			 * The view id caculated by the navigation handler
			 * is to be saved and passed to child dialog window.
			 */
			String viewId = viewroot.getViewId();
			String targetActionURL = vh.getActionURL(context, viewId);
			targetActionURL += component.getParameterRequest();
	        DialogContext dcontext = DialogContextManager.getInstance(context).getContext(component.getClientId(context));
	        dcontext.setDialogPath(targetActionURL);
		} else {
			/*
			 * Child dialog has just been closed. 
			 * Nothing to be saved for future use.
			 */
		}

        /*
         * We need to prevent rendering new view in parent
         * window. Here we have two cases:
         * 1) Child dialog is about to open. In this case 
         * we need to restore in (this) parent window old view.         * 
         * 2) Child dialog has just been closed. In this case 
         * event keeps view id that should be shown in  
         * So view set by navigation handler is (this) parent 
         * window.
         */
		String oldViewId = event.getSourceViewId();
		UIViewRoot newRoot = null;
		boolean b1 = oldViewId == null || oldViewId.equals("null");
		boolean b2 = b1 || oldViewId.equals(oldRoot.getViewId());
		boolean b3 = (
				(!UIDialogAction.isServerMode(component) &&
					DialogWindowUtils.findAncestorForm(context, component) != null)
				|| component.isClose());
		boolean b = (b1 || (b2 && b3));
		try { 
			if(b) {
				newRoot = oldRoot;
			}
		} catch (Exception e) {
			//ignore
		}
		if(newRoot == null) {
			newRoot = vh.createView(context, oldViewId);
		} else {
			if(!b) try {
//				System.out.println("Restore state");
				Object st = oldRoot.saveState(context);
				newRoot.restoreState(context, st);
			} catch (Exception e) {
				e.printStackTrace();
			}
			context.getExternalContext().getRequestMap().put(AjaxContext.AJAX_CONTEXT_KEY, event.getAjaxContext());
		}

		context.setViewRoot(newRoot);
		
		Object nc = null;
		try {		
			if(b) {
				nc = component;
			} else {
				nc = newRoot.findComponent(component.getClientId(context));
			}
		} catch (Exception e) {
			//ignore
		}
		if(nc instanceof UIComponent) {
			UIComponent newComponent = (UIComponent)nc;
			AjaxEvent e = new AjaxEvent(newRoot);
			try {
//				newRoot.queueEvent(e);
				e = new AjaxEvent(newComponent);
				newComponent.queueEvent(e);
			} catch (Exception exc) {
				System.out.println("Cannot queue event: " + newComponent.getClass().getName());
			}
		}

	}
	
	private void rejectOpen() {
		FacesContext context = FacesContext.getCurrentInstance();
		DialogContext dcontext = DialogContextManager.getInstance(context).getActiveContext();
		if(dcontext == null) return;
		DialogContext parentContext = dcontext.getParentContext();
		dcontext.deactivate();
        if(parentContext != null) { 
			DialogContextManager.getInstance(context).setActiveRequest(parentContext.getDialogId());
		} else {
	    	DialogContextManager.getInstance(context).setActiveRequest(null);
		}
		
		
	}
	
}
