/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *     "Apache Jetspeed" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache" or
 *    "Apache Jetspeed", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
/*
 * PortletActionEvent.java
 *
 * Created on January 29, 2003, 4:20 PM
 */
package org.apache.jetspeed.modules.actions.portlets;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.Enumeration;
import java.util.HashMap;

import org.apache.jetspeed.portal.Portlet;
import org.apache.jetspeed.portal.portlets.GenericMVCPortlet;
import org.apache.jetspeed.util.PortletSessionState;
import org.apache.turbine.modules.ActionEvent;
import org.apache.turbine.services.velocity.TurbineVelocity;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.RunData;

import org.apache.velocity.context.Context;


/**
 * Provides form based action handling via the eventSubmit_do[action] pattern.
 * Works just like the mechanism described for the velocity portlet.  Extends
 * this convienent functionality to all GenericMVCPortlets
 * 
 * @author  tkuebler
 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
 * @version $Id: PortletActionEvent.java,v 1.3.2.1 2003/02/24 18:45:42 tkuebler Exp $
 * @stereotype moment-interval
 */
public abstract class PortletActionEvent
    extends ActionEvent
  {
  	
  	/**
  	 * Cache ActionEvent methods to avoid repeated replection
  	 * method lookups.
  	 */
  	private static final HashMap eventMethods = new HashMap();

    /**
     * You need to implement this in your classes that extend this
     * class.
     *
     * @param data A Turbine RunData object.
     * @exception Exception, a generic exception.
     */
    public abstract void doPerform(RunData data)
                            throws Exception;

    /**
     * This overrides the default Action.perform() to execute the
     * doEvent() method.  If that fails, then it will execute the
     * doPerform() method instead.
     *
     * @param data A Turbine RunData object.
     * @exception Exception, a generic exception.
     */
    protected void perform(RunData data)
                    throws Exception
      {

        try
          {
            executeEvents(data, TurbineVelocity.getContext(data));
          }
        catch (NoSuchMethodException e)
          {
            doPerform(data);
          }
      }

    /**
     * This method should be called to execute the event based system.
     *
     * @param data A Turbine RunData object.
     * @param context context information.
     * @exception Exception, a generic exception.
     */
    public void executeEvents(RunData data, Context context)
                       throws Exception
      {

        // Name of the button.
        String theButton = null;
        
        // Portlet whom this action is a target of
        Portlet portlet = (Portlet) context.get(GenericMVCPortlet.PORTLET);

        // ParameterParser.
        ParameterParser pp = data.getParameters();
        String button = pp.convert(BUTTON);

        // Loop through and find the button.
        for (Enumeration e = pp.keys(); e.hasMoreElements();)
          {

            String key = (String) e.nextElement();

            if (key.startsWith(button))
              {
                theButton = formatString(key);

                break;
              }
          }

        if (theButton == null )
          {
            throw new NoSuchMethodException("ActionEvent: The button was null");
          }

 

		if (!fireEvent(data, Context.class, context, theButton) && PortletSessionState.isMyRequest(data, portlet))
		{
			// Old JSP actions use Portlet instead of Context
			// as their event method's 2nd parameter
			if (!fireEvent(data, Portlet.class,
				portlet,
				theButton))
			{
				// Attempt to execut things the old way..
				super.executeEvents(data);
			}
		}            

      }
      
    /**
     * Convenience method for firing portlet events.
	 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
     */
	protected boolean fireEvent(RunData data, Class deltaClass, Object deltaValue, String theButton)		
	{
		try
		{
			// The arguments to the method to find.
			Class[] classes = new Class[2];
			classes[0] = RunData.class;
			classes[1] = deltaClass;
			
			// The arguments to pass to the method to execute.
			Object[] args = new Object[2];
			
			String methodKey = getClass().getName()+":"
			                   +theButton+":"+classes[0].getName()
			                   +":"+classes[1].getName();
			
			Method method = (Method)eventMethods.get(methodKey);
			if(method == null)
			{
				method = getClass().getMethod(theButton, classes);
				eventMethods.put(methodKey, method);
			}
			args[0] = data;
			args[1] = deltaValue;
			method.invoke(this, args);
			return true;
		}
		catch (Exception e)
		{
			return false;
		}
		
	}
      
     
  }
