/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2003 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/>.
 */

package org.apache.jetspeed.portal.controls;

// Turbine stuff
import org.apache.turbine.services.velocity.TurbineVelocity;
import org.apache.turbine.services.pull.TurbinePull;
import org.apache.turbine.util.RunData;

// Jetspeed stuff
import org.apache.jetspeed.portal.Portlet;
import org.apache.jetspeed.portal.PortletState;
import org.apache.jetspeed.services.TemplateLocator;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.persistence.PersistenceManager;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.util.template.JetspeedTool;
import org.apache.jetspeed.util.template.JetspeedLink;
import org.apache.jetspeed.util.template.JetspeedLinkFactory;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.om.security.JetspeedUser;

// Ecs stuff
import org.apache.ecs.ConcreteElement;
import org.apache.ecs.StringElement;

// Velocity Stuff
import org.apache.velocity.context.Context;

// Java stuff
import java.util.List;
import java.util.Vector;
import java.util.Iterator;

/**
 * A Velocity based portlet control which implements all PortletState action
 *
 * <p>To use this control you need to define in your registry the following
 * entry or similar:</p>
 * <pre>
 *   <portlet-control-entry name="TitlePortletControl">
 *     <classname>org.apache.jetspeed.portal.controls.VelocityPortletControl</classname>
 *     <parameter name="theme" value="default.vm"/>
 *     <meta-info>
 *       <title>TitleControl</title>
 *       <description>The standard Jetspeed boxed control</description>
 *       <image>url of image (icon)</description>
 *     </meta-info>
 *     <media-type ref="html"/>
 *   </portlet-control-entry>
 * </pre>
 *
 * 
 * @author <a href="mailto:re_carrasco@bco011.sonda.cl">Roberto Carrasco</a>
 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
 * @author <a href="mailto:morciuch@apache.org">Mark Orciuch</a> 
 *
 * @version $Id: VelocityPortletControl.java,v 1.25 2003/07/23 19:50:16 morciuch Exp $
 *
 */
public class VelocityPortletControl extends AbstractPortletControl
{

    /**
     * Static initialization of the logger for this class
     */    
    private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(VelocityPortletControl.class.getName());    
    
    /** Disable content caching */
    public boolean isCacheable()
    {
        return false;
    }
    
    /**
     * Handles the content generation for this control using Velocity
     */
    public ConcreteElement getContent( RunData rundata )
    {
        Portlet portlet = getPortlet();
        JetspeedRunData jdata = (JetspeedRunData)rundata;

        // Create a new Velocity context and load default 
        // application pull tools
        Context context = TurbineVelocity.getContext();
        
        context.put("data", rundata );
        context.put("actions", buildActionList( rundata, portlet ) );
        context.put("config", getConfig() );
        context.put("skin", portlet.getPortletConfig().getPortletSkin() );

        // Put the request and session based contexts
        TurbinePull.populateContext(context, rundata);
        
        if ( portlet.getName().equals(jdata.getCustomized())
             && (!portlet.providesCustomization()) )
        {            
            context.put("portlet",JetspeedTool.getCustomizer(portlet));
            context.put("portlet_instance",JetspeedTool.getCustomizer(portlet));
        }
        else
        {
            context.put("portlet", portlet );
            if (PersistenceManager.getInstance(portlet, jdata) == null)
            {
              context.put("portlet_instance", portlet );
            }
            else
            {
              context.put("portlet_instance", PersistenceManager.getInstance(portlet, jdata) );
            }
        }
            
        // allow subclasses to add elements to the context
        buildContext( rundata, context );
        
        String theme = getConfig().getInitParameter("theme","default.vm");

        String s = "";
        try 
        {
            String template = TemplateLocator.locateControlTemplate(rundata,theme);
            TurbineVelocity.handleRequest(context, template, rundata.getOut());
        }
        catch( Exception e )
        {
            logger.error( "Exception while creating content ", e );
            s = e.toString();
        }

        TurbineVelocity.requestFinished(context);

        return new StringElement( s );
    }
    
    /**
     * This method allows subclasses of the VelocityPortletControl
     * to populate the context of this control before rendering by
     * the template engine.
     *
     * @param rundata the RunData object for this request
     * @param context the Context used by the template
     */
    public void buildContext( RunData rundata, Context context )
    {
        // empty, used by subclasses to populate the context
    }
    
    /** Builds a list of possible window actions for this portlet
     *  instance. For best results, the portlet should also implement the
     *  PortletState interface.
     *
     * @param rundata the request RunData
     * @param the portlet instance managed by this control
     * @return a list of ordered PortletAction objects describing the
     * the actions available for this portlet
     */
    protected List buildActionList( RunData rundata, Portlet portlet )
    {
        List actions = new Vector();
        JetspeedLink jsLink = null;
        JetspeedRunData jdata = (JetspeedRunData)rundata;

        // disable actions option
        if (JetspeedSecurity.areActionsDisabledForAllUsers())
        {
            return actions;
        }
        JetspeedUser user = jdata.getJetspeedUser();
        if (JetspeedSecurity.areActionsDisabledForAnon() && false == user.hasLoggedIn())
        {
            return actions;
        }


        // list the available actiosn for this portlet
        if (portlet instanceof PortletState)
        {            
            // the portlet is state aware
            PortletState state = (PortletState)portlet;
            boolean customized = (jdata.getMode()==jdata.CUSTOMIZE);
            boolean maximized = customized||(jdata.getMode()==jdata.MAXIMIZE);
            boolean infoAdded = false;
                    
            if ( state.allowCustomize( rundata ) )
            {
                if (! customized )
                {
                    actions.add( new PortletAction("customize", "Customize") );
                }
            }
            else
            {
                if ( state.allowInfo( rundata ) )
                {
                    actions.add( new PortletAction("info", "Information") );
                    infoAdded = true;
                }
            }

            if ( (!customized) &&  state.allowPrintFriendly( rundata ) )
            {
                actions.add( new PortletAction("print", "Print Friendly Format") );
            }

            if ( (!customized) &&  state.allowInfo( rundata ) && (!infoAdded) )
            {
                actions.add( new PortletAction("info", "Information") );
            }
                       
            if ( (!customized) && (!maximized) && state.allowClose( rundata ) )
            {
                actions.add( new PortletAction("close", "Close") );
            }
            
            if ( state.isMinimized( rundata ) || maximized )
            {
                actions.add( new PortletAction("restore", "Restore") );
            }
            else
            {
                if ( state.allowMinimize( rundata ) )
                {
                    actions.add( new PortletAction("minimize", "Minimize") );
                }

                if ( state.allowMaximize( rundata ) )
                {
                    actions.add( new PortletAction("maximize", "Maximize") );
                }
            }
        }
        else
        {
            // the portlet only knows about edit and maximize
            if ( portlet.getAllowEdit( rundata ) )
            {
                actions.add( new PortletAction("info", "Information") );
            }
        
            if ( portlet.getAllowMaximize( rundata ) )
            {
                actions.add( new PortletAction("maximize", "Maximize") );
            }
        }
        
        // Now that we know which actions should be displayed,
        // build the links and put it in the context
        Iterator i = actions.iterator();
                
        while( i.hasNext() )
        {
            PortletAction action = (PortletAction)i.next();

            try
            {
                jsLink = JetspeedLinkFactory.getInstance(rundata);
            }
            catch( Exception e)
            {
               logger.error( "Exception in buildActionList", e );
            }
//            action.setLink( jsLink.setPortletById(portlet.getID())
//                                 .addQueryData("action", getAction( action.getName()))
//                                 .toString());
            action.setLink( jsLink.setAction( getAction( action.getName()), portlet).toString());
            JetspeedLinkFactory.putInstance(jsLink);
            jsLink=null;
        }
        
        return actions;
    }
    
    /** Transforms an Action name in Turbine valid action name, by
     *  adding a controls package prefix and capitalizing the first
     *  letter of the name.
     */
    protected static String getAction( String name )
    {
        StringBuffer buffer = new StringBuffer( "controls." );
        
        buffer.append( name.substring(0,1).toUpperCase() );
        buffer.append( name.substring(1, name.length() ) );
        
        return buffer.toString();
    }
    
    /** This utility class is used to give information about the actions 
     *  available in a control theme template
     */
    public class PortletAction
    {
        String name = null;
        String link = null;
        String alt = null;
    
        /**
         * Constructor
         * 
         * @param name   Name of the action
         * @param alt    Alternative text description (localized)
         */
        protected PortletAction( String name, String alt )
        {
            this.name = name;
            this.alt = alt;
        }
        
        public String getName()
        {
            return this.name;
        }
        
        public String getLink()
        {
            return this.link;
        }
        
        public void setLink(String link)
        {
            this.link = link;
        }

        public String getAlt()
        {
            return this.alt;
        }

    }
}

