/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.tools.guiframework.event.handlers;

import com.iplanet.jato.RequestContext;
import com.iplanet.jato.ViewBeanManager;
import com.iplanet.jato.view.DisplayField;
import com.iplanet.jato.view.ContainerView;
import com.iplanet.jato.view.View;

import com.sun.enterprise.tools.guiframework.view.HandlerContext;
import com.sun.enterprise.tools.guiframework.view.DescriptorViewManager;

import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 *
 */
public class DisplayFieldHandlers {

    /**
     *	This method retrieves the value from a DisplayField.  It requires the
     *	id of the View and the name of the DisplayField be specified as
     *	Parameters.  The key for the View is "viewID", the key for the
     *	DisplayField is "fieldName".  You may optionally specify that you want
     *	an array of values.  To do this, pass in the parameters "multiple"
     *	equal to "true".  Note, if you are obtaining a View (not a ViewBean),
     *	then the View must be cached in order for this to work correctly (the
     *	container will not get set correctly).
     *
     *	@param	reqCtx		The RequestContext
     *	@param	handlerCtx	The HandlerContext
     */
    public void getDisplayFieldValue(RequestContext reqCtx, HandlerContext handlerCtx) {
	DisplayField field = (DisplayField)handlerCtx.getInputValue(DISPLAY_FIELD);
	if (field == null) {
	    // We can get the result of getDisplayField this way
	    getDisplayField(reqCtx, handlerCtx);
	    field = (DisplayField)handlerCtx.getOutputValue(VALUE);
	}

	// Check to see if we should attempt to get 1 or many values
	Boolean multi = (Boolean)handlerCtx.getInputValue(MULTI_VALUE);
	boolean getMulti = false;
	if (multi != null) {
	    getMulti = multi.booleanValue();
	}

	// If getMulti, then return Object[], else Object
	Object value = getMulti ? field.getValues() : field.getValue();
	handlerCtx.setOutputValue(VALUE, value);
    }


    /**
     *	This is a helper method for obtaining a View.
     */
    public void getDisplayField(RequestContext reqCtx, HandlerContext handlerCtx) {
    	// Get the View ID
    	Object viewID = handlerCtx.getInputValue(VIEW_ID);
	if (viewID == null) {
	    throw new IllegalArgumentException(
		"The parameter map did not contain "+VIEW_ID+"!");
	}

	// Try to obtain the ContainerView
	ViewBeanManager vm = reqCtx.getViewBeanManager();
	View view = null;
	String topName = (viewID instanceof List) ?
	    ((List)viewID).get(0).toString() : viewID.toString();
	try {
	    view = vm.getViewBean(topName);
	} catch (ClassCastException ex) {
	    view = ((DescriptorViewManager)vm).getView(null, topName);
	} catch (ClassNotFoundException ex) {
	    throw new RuntimeException(ex);
	}
	if (view == null) {
	    throw new RuntimeException(
		"Unable to obtain the view for mapping!");
	}

	// If we have more than 1 ID, walk the View...
	if (viewID instanceof List) {
	    Iterator iter = ((List)viewID).iterator();
	    iter.next();  // Already used the first one
	    while (iter.hasNext()) {
		if (!(view instanceof ContainerView)) {
		    throw new RuntimeException("View ("+
			view.getQualifiedName()+") is not a ContainerView!");
		}
		view = ((ContainerView)view).getChild(""+iter.next());
	    }
	}

	// Make sure we have a container
	if (!(view instanceof ContainerView)) {
	    throw new RuntimeException(
		"View ("+view.getQualifiedName()+") is not a ContainerView!");
	}

    	// Get the DisplayField Name
    	Object fieldName = handlerCtx.getInputValue(FIELD_NAME);
	if (fieldName == null) {
	    throw new IllegalArgumentException(
		"The parameter map did not contain "+FIELD_NAME+"!");
	}

	// Try to get the DisplayField
	DisplayField field =
	    ((ContainerView)view).getDisplayField(fieldName.toString());
	if (field == null) {
	    throw new RuntimeException(
		"Field ("+fieldName+") not found on View ("+viewID+")!");
	}

	// Return the View (as a ContainerView)
	handlerCtx.setOutputValue(VALUE, field);
    }


    /**
     *	This method sets a DisplayField value.  "params" must contain the View
     *	key and the DisplayField name.  The key for the View is "viewID", the
     *	key for the DisplayField is "fieldName".  You may optionally specify
     *	that you want an array of values.  To do this, pass in the parameters
     *	"multiple" equal to "true".  Note, if you are obtaining a View (not a
     *	ViewBean), then the View must be cached in order for this to work
     *	correctly (the container will not get set correctly).  If you attmempt
     *	to set an array of values, but do not pass in an array type, an
     *	Object[] will be created with the value as its only emelent.
     *
     *	@param	reqCtx		The RequestContext
     *	@param	handlerCtx	The HandlerContext
     */
    public void setDisplayFieldValue(RequestContext reqCtx, HandlerContext handlerCtx) {
	DisplayField field = (DisplayField)handlerCtx.getInputValue(DISPLAY_FIELD);
	if (field == null) {
	    // We can get the result of getDisplayField this way
	    getDisplayField(reqCtx, handlerCtx);
	    field = (DisplayField)handlerCtx.getOutputValue(VALUE);
	}

	// Check to see if we should attempt to set 1 or many values
	Boolean multi = (Boolean)handlerCtx.getInputValue(MULTI_VALUE);
	boolean getMulti = false;
	if (multi != null) {
	    getMulti = multi.booleanValue();
	}

	// If getMulti, then return Object[], else Object
	Object value = handlerCtx.getInputValue(VALUE);
	if (getMulti) {
	    // Make sure we have an array
	    if ((value != null) && !value.getClass().isArray()) {
		value = new Object[] {value};
	    }
	    field.setValues((Object [])value);
	} else {
	    field.setValue(value);
	}
    }


    public static final String	VALUE =		"value";
    public static final String	MULTI_VALUE =	"multiple";
    public static final String	VIEW_ID =	"viewID";
    public static final String	FIELD_NAME =	"fieldName";
    public static final String	DISPLAY_FIELD =	"displayField";
}
