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

// JDK stuff
import java.util.Vector;

// Jetspeed Struff
import org.apache.jetspeed.portal.portlets.VelocityPortlet;
import org.apache.jetspeed.modules.actions.portlets.VelocityPortletAction;
import org.apache.jetspeed.util.PortletConfigState;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.services.statemanager.SessionState;

import org.apache.jetspeed.services.cms.CmsService;
import org.apache.jetspeed.services.cms.manager.CmsManager;
import org.apache.jetspeed.services.cms.manager.CmsFactory;
import org.apache.jetspeed.services.cms.JetspeedCMSException;
import org.apache.jetspeed.om.cms.Catalog;


// Turbine stuff
import org.apache.turbine.util.Log;
import org.apache.turbine.util.RunData;
import org.apache.turbine.services.TurbineServices;


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


/**
 * Action used for CMS Admin (CRUD on content/catalog).
 *
 * <p>Don't call it from the URL, the Portlet and the Action are automatically
 * associated through the registry PortletName
 *
 * @author <a href="mailto:Christophe.lombart@skynet.be">Christophe Lombart</a>
 */
public class CmsAdminAction extends VelocityPortletAction
{


    private static final String CUSTOMIZE_TEMPLATE = "customize-template";
    
    private static final String FROM_URI = "fromuri";
    
    private static final String FROM_URI_DEFAULT_VALUE = "/catalog";
    
    private static final String TO_URI = "touri";
       
    private static final String NEW_CATALOG_EVENT = "NewCatalog";
    
    private static final String INSERT_CATALOG_EVENT = "InsertCatalog";
    
    private static final String NEW_CATALOG_TEMPLATE = "new-catalog-template";
        
    private static final String SUMMARY_CATALOG_TEMPLATE = "summary-catalog-template";
    
    private static final String CATALOG_PARAM = "catalog";
    
    private static final String CATALOG_PATH_PARAM = "catalogPath";
    
    private static final String SUB_CATALOG_PARAM = "subCatalog";
    
    private static final String CUSTOMIZE_EVENT_PARAM = "customizeEvent";
    
    private static final String MODE_PARAM = "mode";
    
    private static final String ADD_MODE_VALUE = "add";
    
    
    
    /**
     * Subclasses should override this method if they wish to
     * build specific content when maximized. Default behavior is
     * to do the same as normal content.
     */
    protected void buildMaximizedContext( VelocityPortlet portlet,
                                          Context context,
                                          RunData rundata )             
               throws JetspeedCMSException                                          
    {
        
        try 
        {
            buildNormalContext( portlet, context, rundata);
        }
        catch (JetspeedCMSException e)
        {
            throw e;
        }

    }

    /**
     * Subclasses should override this method if they wish to
     * provide their own customization behavior.
     * Default is to use Portal base customizer action
     */
    protected void buildConfigureContext( VelocityPortlet portlet,
                                          Context context,
                                          RunData rundata )
    {
        try {
        
            SessionState state = this.getSessionState(portlet, rundata);           
            
            String customizeEvent  = rundata.getParameters().getString(CUSTOMIZE_EVENT_PARAM);
            
            if (customizeEvent == null) 
            {
        	    setTemplate(rundata, getParameterUsingFallback(portlet, rundata, CUSTOMIZE_TEMPLATE, null));
            }
            else 
            {
                if (customizeEvent.equals(NEW_CATALOG_EVENT))
                {
        	        this.doNewCatalog(portlet,context,rundata);
                }
            
                if (customizeEvent.equals(INSERT_CATALOG_EVENT))
                {
        	        this.doInsertCatalog(portlet,context,rundata);
                }
            }
            // Store cataloPath and catalog into the context
            context.put(CATALOG_PATH_PARAM, state.getAttribute(CATALOG_PATH_PARAM));
            context.put(CATALOG_PARAM, state.getAttribute(CATALOG_PARAM));
        }
        catch (JetspeedCMSException e)
        {
            e.printStackTrace();	
        }


    }

    /**
     * Subclasses must override this method to provide default behavior
     * for the portlet action
     */
    protected void buildNormalContext( VelocityPortlet portlet,
                                       Context context,
                                       RunData rundata )
               throws JetspeedCMSException
    {
    	
    	try 
    	{
            
            SessionState state = this.getSessionState(portlet, rundata);
            
            String fromcatalogName = this.getParameterUsingFallback(portlet, rundata, FROM_URI, FROM_URI_DEFAULT_VALUE);
            String tocatalogName = rundata.getParameters().getString(TO_URI);
            
            
           
            if (tocatalogName == null)
            {
                // this case occur when the normal context is calling for the first time	
                if (state.getAttribute(CATALOG_PARAM) == null) 
                {	
        	        tocatalogName = fromcatalogName;
                }
                // this case occur when the end-used moves from the configure context to the normal context
        	    else
        	    {
                    context.put(CATALOG_PATH_PARAM, state.getAttribute(CATALOG_PATH_PARAM));
                    context.put(CATALOG_PARAM, state.getAttribute(CATALOG_PARAM));
                    return;        	
        	    }
        	                  	
            }
                      
            // get all catalogs objects used for the "catalog path"
            Vector catalogPath = this.getCmsManager().getCatalogs(fromcatalogName, tocatalogName);
            
            // get the catalog selected in the velocity template
            Catalog catalog = (Catalog) catalogPath.lastElement();
            // Retrieve catalog items
            this.getCmsManager().populateCatalog(catalog,true,true,1);
                                    
            // Store the cataloPath collection and the catalog into the portlet session for performance reason
            // (can be used by the customizer without a second retrieve in the cms repository           
            state.setAttribute(CATALOG_PATH_PARAM, catalogPath);
            state.setAttribute(CATALOG_PARAM, catalog);
            
            
            // Store cataloPath and catalog into the context
            context.put(CATALOG_PATH_PARAM, catalogPath);
            context.put(CATALOG_PARAM, catalog);
            
    	}
    	catch ( Exception e ) {
            throw new JetspeedCMSException("Impossible to build the normal context");    	    	
    	}
        
        
    }


    /**
     * Add a new catalog into the velocity context
     */
    protected void doNewCatalog( VelocityPortlet portlet,
                                          Context context,
                                          RunData rundata )
               throws JetspeedCMSException
    {
    	
         try 
         {    	
             Catalog catalog = (Catalog) CmsFactory.getCmsOmInstance("Catalog");
             setTemplate(rundata, getParameterUsingFallback(portlet, rundata, NEW_CATALOG_TEMPLATE, null));
             context.put(SUB_CATALOG_PARAM, catalog);
             context.put(MODE_PARAM, ADD_MODE_VALUE);
             
         }
         catch (Exception e)
         {
             throw new JetspeedCMSException("Impossible to create Catalog object");	
         }
                 	
    }

    /**
     *  Insert a new catalog into the CMS repository
     */
    protected void doInsertCatalog( VelocityPortlet portlet,
                                          Context context,
                                          RunData rundata )
               throws JetspeedCMSException
    {
    	
         try 
         {    	
             
             Catalog newCatalog = (Catalog) CmsFactory.getCmsOmInstance("Catalog"); 
             
             // Assign values to the catalog object
             rundata.getParameters().setProperties(newCatalog);
             
             Catalog parentCatalog = (Catalog) this.getSessionState(portlet, rundata)
                                          .getAttribute(CATALOG_PARAM);
             
             newCatalog.setParentUri(parentCatalog.getUri());
             
             newCatalog.setUri(newCatalog.getParentUri() +
                               "/" + newCatalog.getLogicalName());
             
             // Create catalog into the repository                  
             this.getCmsManager().createResource(newCatalog);
             
             // Refresh parent catalog
             this.getCmsManager().populateCatalog(parentCatalog); 
             
             setTemplate(rundata, getParameterUsingFallback(portlet, rundata, SUMMARY_CATALOG_TEMPLATE, null));
             
             context.put(CATALOG_PARAM, parentCatalog);
             context.put(MODE_PARAM, ADD_MODE_VALUE);

             
         }
         catch (Exception e)
         {
             throw new JetspeedCMSException("Impossible to create Catalog object");	
         }
                 	
    }
    

    protected String getParameterUsingFallback(VelocityPortlet portlet, RunData rundata,
                                             String attrName, String attrDefValue)
    {
        return PortletConfigState.getParameter(portlet, rundata, attrName, attrDefValue);
    }
    
    protected CmsManager getCmsManager()
               throws JetspeedCMSException
    {
        try 
        {
	        return ((CmsService) TurbineServices.getInstance()
			                                .getService(CmsService.SERVICE_NAME))
			                                .getCmsManager();
        }
        catch (Exception e)
        {
           throw new JetspeedCMSException("Impossible to get the CMS service");
        }
    }
    
    
    protected SessionState getSessionState(VelocityPortlet portlet,RunData rundata) {
    	
        return ((JetspeedRunData) rundata).getPortletSessionState(portlet.getID());
    }
    
    
}
