/* ====================================================================
 * 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/>.
 */

package org.apache.jetspeed.modules.actions.controls;

// Turbine stuff
import org.apache.turbine.modules.Action;
import org.apache.turbine.util.RunData;

// Jetspeed stuff
import org.apache.jetspeed.portal.Portlet;
import org.apache.jetspeed.portal.PortletSet;
import org.apache.jetspeed.portal.PortletControl;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.om.profile.Profile;
import org.apache.jetspeed.om.profile.ProfileLocator;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.Profiler;
import org.apache.jetspeed.services.statemanager.SessionState;
import org.apache.jetspeed.util.template.JetspeedLink;
import org.apache.jetspeed.util.template.JetspeedLinkFactory;
import org.apache.jetspeed.services.security.PortalResource;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.om.security.JetspeedUser;

import java.util.Enumeration;
import java.util.Stack;

/**
 * Handle Customization requests for the current portal page
 *
 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
 * @author <a href="mailto:paulsp@apache.org">Paul Spencer</a>
 * @author <a href="mailto:ggolden@apache.org">Glenn R. Golden</a>
 */
public class Customize extends Action
{
    
    /**
     * Static initialization of the logger for this class
     */
    private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(Customize.class.getName());
    
    /**
     * @param rundata The RunData object for the current request
     */
    public void doPerform( RunData rundata ) throws Exception
    {
        JetspeedRunData jdata = (JetspeedRunData)rundata;

        if (jdata.getUser() == null)
        {
            return;
        }
        if(jdata.getProfile() == null)
        {
            return;
        }

        // read some parameters
        String editMediaType = jdata.getParameters().getString ("mtype");
        String resetStack = jdata.getParameters().getString ("reset");
        String peid = jdata.getParameters().getString("js_peid");

        // get the customization state for this page
        SessionState customizationState = jdata.getPageSessionState();

        // this will be the profile we are editing
        Profile profile = null;

        // the "reset" parameter's presence signals the start of customization
        if (    (resetStack != null)
            &&  ((resetStack.equalsIgnoreCase("on")) || (resetStack.equalsIgnoreCase("1"))))
        {
            // clear out any prior customization state
            jdata.cleanupFromCustomization();
        }

        // if we have not yet setup for customization, do so now
        if (jdata.getCustomizedProfile() == null)
        {
            ProfileLocator locator = (ProfileLocator)jdata.getProfile().clone();

            if (editMediaType != null)
            {
                locator.setMediaType(editMediaType);
            }

            // get a profile to edit
            profile = (Profile) Profiler.getProfile(locator).clone();
            jdata.setCustomizedProfile(profile);
        }

        // we are continuing an on-going customization
        else
        {
            // get the profile we are working on
            profile = jdata.getCustomizedProfile();
        }

        // Get js_peid parmameter.
        // If it does not exist, we will customize the root of the profile
        if ( peid == null )
        {
            // use the id of the root set of the profile
            peid = profile.getRootSet().getID();
            jdata.setJs_peid(peid);
        }

        // find the portlet within the profile with this peid %%% isn't there a better way to do this? -ggolden
        Portlet found = null;
        Stack sets = new Stack();
        sets.push(profile.getRootSet());

        while ((found==null) && (sets.size() > 0))
        {
            PortletSet set = (PortletSet)sets.pop();

            if (set.getID().equals(peid))
            {
                found = set;
            }
            else
            {
                Enumeration en = set.getPortlets();
                while((found==null) && en.hasMoreElements())
                {
                    Portlet p = (Portlet)en.nextElement();

                    // unstack the controls to find the real PortletSets
                    Portlet real = p;
                    while (real instanceof PortletControl)
                    {
                        real = ((PortletControl)p).getPortlet();
                    }

                    if (real instanceof PortletSet)
                    {
                        if (real.getID().equals(peid))
                        {
                            found=real;
                        }
                        else
                        {
                            // we'll explore this set afterwards
                            sets.push(real);
                        }
                    }
                    else if (p.getID().equals(peid))
                    {
                        found = p;
                    }
                }
            }
        }

        if (found!=null)
        {
            PortalResource portalResource = new PortalResource(found);
            try
            {
                JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);
                portalResource.setOwner(jsLink.getUserName());
                JetspeedLinkFactory.putInstance(jsLink);
            }
            catch (Exception e)
            {
                logger.warn(e.toString());
                portalResource.setOwner(null);
            }

            if(!JetspeedSecurity.checkPermission((JetspeedUser) jdata.getUser(), 
                                                 portalResource, 
                                                 JetspeedSecurity.PERMISSION_CUSTOMIZE))
            {
                logger.warn("User " + jdata.getUser().getUserName() + " has no customize permission for portlet with id " + peid);
                jdata.setMessage("Sorry, you have no customize permission for this portlet");
                return;
            }
            jdata.setCustomized(found);
            jdata.setScreenTemplate("Customize");
        }

    }

    /**
    * Save the current customization
    * Used by any other customizer to get this done right!
    *
    * @deprecated. The customizers should handle the save themselves
    */
    public static void save(RunData data)
    {
        try
        {
            Profile profile = ((JetspeedRunData) data).getCustomizedProfile();
            profile.store();
        }
        catch (Exception e)
        {
            logger.error("Error while saving profile", e);
        }

    }   // save

    /**
    * Exit the customizer.
    * @deprecated. Exec the controls.EndCustomize action instead
    */
    public static void exit(RunData data)
    {
        JetspeedLink jsLink = null;
        ((JetspeedRunData) data).cleanupFromCustomization();

        // bring logged on user to homepage via HTTP redirect
        try
        {
            jsLink = JetspeedLinkFactory.getInstance(data);
            String mtype = data.getParameters().getString("mtype");
            if (mtype != null)
            {
                jsLink.setMediaType(mtype);
                jsLink.addQueryData("mtype", mtype);
            }

        }
        catch (Exception e)
        {
            logger.error("exit error", e);
        }
        data.setRedirectURI(jsLink.toString());
        JetspeedLinkFactory.putInstance(jsLink);
        jsLink = null;

    }   // exit
}

