/*
ESUP-portail is a french academic project developed under the GPL (General Public License) augmented according to the following :
A binary or source file developped by ESUP-portail can be used or compiled with products under Apache license.
The official english text of the GPL can be found here : http://www.gnu.org/licenses/gpl.html .
A non official french translation can be found here : http://www.linux-France.org/article/these/gpl.html .
The different kinds of licenses governing the products developed by the Apache foundation can be found here : http://www.apache.org/licenses .
It follows that you can as well as use download contents as well modify and redistribute them provided you respect the GPL terms.
Downloading and using such contents do not provide any guaranty.
Be sure that you have well understood the terms of the license before using the contents it covers.
The ESUP-portail distribution includes the following distributions :
    * UPortal : 
      software developed by JA-SIG (Java Architecture - Special Interest Group)
      You can find the license page here : http://mis105.udel.edu/ja-sig/uportal/license.html
    * CAS :
      SSO solution developed by Yale University
      You can find the project page here : http://www.yale.edu/tp/auth
    * Cocoon :
      XML framework distributed by the Apache foundation under Apache license;
      Please find the full text here : http://cocoon.apache.org/2.1/license.html
    * Mod_dav:
      A DAV module for Apache web server
      You can find the project page here : http://www.webdav.org/mod_dav
    * IMP :
      webmail from Horde application framework
      You can find the project page here : http://www.horde.org
    * …. To be completed
*/
 
package org.esupportail.portal.channels.CStockage;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.esupportail.portal.channels.CStockage.channelAction.AbstractDefaultRenderXml;
import org.esupportail.portal.channels.CStockage.channelAction.BufferAction;
import org.esupportail.portal.channels.CStockage.channelAction.Constants;
import org.esupportail.portal.channels.CStockage.channelAction.classic.sharing.SharedSpaceProperties;
import org.esupportail.portal.channels.CStockage.config.AuthorizationSpace;
import org.esupportail.portal.channels.CStockage.config.AuthorizationSpaceParameter;
import org.esupportail.portal.channels.CStockage.config.ChannelConfiguration;
import org.esupportail.portal.channels.CStockage.config.Space;
import org.esupportail.portal.channels.CStockage.exception.AnyVisibleSpaceException;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
import org.esupportail.portal.channels.CStockage.exception.BadConnexionParameters;
import org.esupportail.portal.channels.CStockage.exception.CancelException;
import org.esupportail.portal.channels.CStockage.exception.ChannelException;
import org.esupportail.portal.channels.CStockage.exception.ConnexionParametersRequired;
import org.esupportail.portal.channels.CStockage.exception.DataBaseException;
import org.esupportail.portal.channels.CStockage.exception.DownloadException;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.exception.ServerException;
import org.esupportail.portal.channels.CStockage.provider.ChannelResource;
import org.esupportail.portal.channels.CStockage.spacesPersonalization.PersonalizationTool;
import org.esupportail.portal.channels.CStockage.spacesPersonalization.target.UserForPersonalization;
import org.esupportail.portal.webservices.groups.PortalGroups;
import org.jasig.portal.ChannelCacheKey;
import org.jasig.portal.ChannelRuntimeData;
import org.jasig.portal.ChannelRuntimeProperties;
import org.jasig.portal.ChannelStaticData;
import org.jasig.portal.ICacheable;
import org.jasig.portal.IChannel;
import org.jasig.portal.IMimeResponse;
import org.jasig.portal.PortalEvent;
import org.jasig.portal.PortalException;
import org.jasig.portal.UPFileSpec;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.utils.XSLT;
import org.xml.sax.ContentHandler;

/**
 * Id: CStockage.java,v 1.0 7 avr. 2004<br/>
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)<br/>
 * Classes: CStockage<br/>
 * Original Author: Yohan Colmant<br/>
 * Channel used to manage personal files on a webdav server through the portal<br/>
 */



public class CStockage implements IChannel, IMimeResponse ,ICacheable  {


	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(CStockage.class);
	
	
	
	
	private ChannelStaticData staticData;
	private ChannelRuntimeData runtimeData;
	
	private String fileId;
	//private PortalControlStructures pcs;


  
	
	/**
	 * The spaces availables
	 */
	private ArrayList spaces;
	private ArrayList notObligedSpaces;
	
	/**
	 * The current used space
	 */
	private Space currentSpace;
	

	/**
	 * if we support the spaces personalization
	 */
	private boolean isSpacesPersonalization;
	
	
	
	
	/**
	 * Error at the beginning of the channel
	 */
	private ChannelException setStaticDataException;		
	
	
	/**
	 * The stylesheet used for the transformation
	 */
	private StringBuffer stylesheet;
	
	
	
	/**
	 * User login
	 */
	private String portalLogin;
	
	/**
	 * The user groups
	 */
	private Vector userGroups;
	
	
	/**
	 * The mode to use
	 */
	private String currentMode;
	
	
	/**
	 * Object used to keep the objects used between 2 actions, for example, the clipboard
	 */
	private BufferAction buffer;
	
	
	/**
	 * The current user IPerson object
	 */
	private IPerson person;
	
	/**
	 * If we want help
	 */
	//private boolean helpMode= false;
	
	
	
	/**
	 * Constructor
	 */
	public CStockage() {				
		
		// init the buffer
		this.buffer = new BufferAction();
	}	

	/** 
	 *  Process layout-level events coming from the portal.
	 *  Satisfies implementation of IChannel Interface.
	 *
	 *  @param <b>PortalEvent</b> ev a portal layout event
	 */
	public void receiveEvent(PortalEvent ev) {
		if (ev.getEventNumber() == PortalEvent.HELP_BUTTON_EVENT) {
			//helpMode = true;
		}
		else {
			//helpMode = false;
		}
	}

	  /** 
	   *  Receive channel runtime data from the portal.
	   *  Satisfies implementation of IChannel Interface.
	   *
	   *  @param <b>ChannelRuntimeData</b> rd handle to channel runtime data
	   */
	  public void setRuntimeData(ChannelRuntimeData rd) {
	  	this.runtimeData = rd;
	  }
	  
	  
	  /** 
	   *  Returns channel runtime properties.
	   *  Satisfies implementation of Channel Interface.
	   *
	   *  @return handle to runtime properties 
	   */ 
	  public ChannelRuntimeProperties getRuntimeProperties() { 
	  	return new ChannelRuntimeProperties();
	  }
	
	/**
	 * Receive static channel data from the portal. Satisfies implementation of IChannel Interface.
	 * 
	 * @param sd <b>ChannelStaticData</b> static channel data
	 */
	public void setStaticData(ChannelStaticData sd) {
		
		this.staticData = sd;			
		 
		try {
			ChannelConfiguration config = ChannelConfiguration.getInstance();
			
			// init the value of directories for servant
			staticData.setParameter("serverView", config.getDirectoriesList());
			
			// the uportal person object
			person = sd.getPerson();			
			
			// the usernameAttribute
			String userNameAttribute = config.getUsernameAttribute();
			
			// Set the user login			
			portalLogin = (String)person.getAttribute(userNameAttribute);	
			
			// the user groups
			try {
				Vector groups = (Vector)new PortalGroups().getGroupsOfUser(portalLogin);
				userGroups = new Vector();
				for (int i=0; i<groups.size(); i++) {
					Vector group = (Vector)groups.elementAt(i);
					
					for (int j=0; j<group.size(); j++) {
						String key = (String)group.elementAt(j);
						
						if (!userGroups.contains(key)) {
							userGroups.addElement(key);
						}
					}
				}
				//System.out.println(userGroups);
			}
			catch(Exception e) {
				throw new ServerException();
			}
			
			// if we support the spaces personalization
			isSpacesPersonalization = ChannelConfiguration.getInstance().isSpacesPersonalization();
			
			// the spaces availables in the configuration file
			ArrayList[] defaultSpaces = config.getDefaultSpaces();
			spaces = defaultSpaces[0];
			notObligedSpaces = defaultSpaces[1];
			
			// add the obliged spaces from the database
			if (isSpacesPersonalization)
				addObligedSpacesToList(portalLogin, userGroups, spaces);
			
			// for each Space, we check if the path is in the {...} form. Is yes, we replace {...} by the real value									
			for (int i=0; i<spaces.size(); i++) {
				
				Space space = (Space)spaces.get(i);
				space.setStaticData(sd);
				boolean valid = initSpace(space, person, portalLogin, spaces, buffer, userGroups, this.staticData);
				
				if (!valid) {
					spaces.remove(i);
					i--;
				}
			}
			for (int i=0; i<notObligedSpaces.size(); i++) {
				
				Space space = (Space)notObligedSpaces.get(i);
				boolean valid = initSpace(space, person, portalLogin, spaces, buffer, userGroups, this.staticData);
				
				//System.out.println(space.getLabel());
				
				if (!valid) {
					//System.out.println("supprime");
					notObligedSpaces.remove(i);
					i--;
				}
				else {
					//System.out.println("supprime pas");
				}
			}

			
			
			// init the personal spaces into the current menu
			if (isSpacesPersonalization)
				initPersonalSpacesIntoMenu();
			
			
			
			
			// if we can not see any space
			if (spaces.isEmpty()) {
				if (log.isDebugEnabled()){
					log.debug("setStaticData"+" :: AnyVisibleSpaceException");
				}
				
				throw new AnyVisibleSpaceException();
			}
			
			else {
				// the current space
				this.currentSpace = (Space)spaces.get(0);									
			}

		}		
		catch(AnyVisibleSpaceException e) {			
			//this.currentSpace.setWebdavAccessObject(null);
			setStaticDataException = e;
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}			
		}
		catch(ServerException e) {			
			//this.currentSpace.setWebdavAccessObject(null);
			setStaticDataException = e;
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(ApplicationException e) {			
			//this.currentSpace.setWebdavAccessObject(null);			
			setStaticDataException = e;
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(PropertiesException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			setStaticDataException = e;
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(ChannelException e) {			
			//this.currentSpace.setWebdavAccessObject(null);
			setStaticDataException = e;
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		
	}
	
	
	
	/**
	 * Init the actions and server of a space
	 * @param space the space to init
	 * @param channelStaticData the channel static data
	 * @return true if the access is valid, false else
	 * @throws PropertiesException
	 * @throws IllegalAccessException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws ApplicationException
	 * @throws MalformedURLException
	 * @throws ChannelException
	 */
	private static boolean initSpace(Space space, IPerson person, String portalLogin, ArrayList spaces, BufferAction buffer, Vector userGroups, ChannelStaticData channelStaticData) throws PropertiesException, ApplicationException {
		//System.out.println("\nj'initSpace "+space.getLabel());

		// log
		if (log.isDebugEnabled()) {
			log.debug("initSpace"+" :: init = "+space.getLabel());
		}
		
		try {
			
			//System.out.println("\n\n"+space.getLabel());
			
			// if the server access is valid
			boolean validAccess = false;
			
			// check the authorization
			/*ArrayList authorizations = space.getAuthorization();
			if (authorizations!=null && !authorizations.isEmpty()) {
				
				for (int j=0; !validAccess && j<authorizations.size(); j++) {
					AuthorizationSpaceParameter auth = (AuthorizationSpaceParameter)authorizations.get(j);
					String name = auth.getAttribute();
					String value = auth.getValue();
					
					if (name!=null && !name.trim().equals("")) {
						
						// if it is a group
						if (name.equals(AuthorizationSpaceParameter.GROUP)) {
							if (userGroups.contains(value)) {
								validAccess = true;
								log.debug("initSpace"+" :: portal_group == "+value+" ??? yes");
							}
							else {
								log.debug("initSpace"+" :: portal_group == "+value+" ??? no, portal_group = "+userGroups);
							}
						}
						
						// if it is a parameter
						else {
							Object[] userValues = (Object[])person.getAttributeValues(name);						
							if (userValues!=null) {
							
								for (int k=0; !validAccess && k<userValues.length; k++) {
								
									String userValue = (String)userValues[k];
									if (userValue.toLowerCase().equals(value.toLowerCase())) {
										validAccess = true;
										log.debug("initSpace"+" :: "+name+" == "+value+" ??? yes");
									}
									else log.debug("initSpace"+" :: "+name+" == "+value+" ??? no, "+name+" = "+userValue);
								}							
							
							}
							else log.debug("initSpace"+" :: "+name+" == "+value+" ??? no, "+name+" is null ");
						}
					}
				}					
			}*/
			AuthorizationSpace authorization = space.getAuthorizations();
			if (authorization!=null) {
				String operator = authorization.getOperator();
				ArrayList authorizations = authorization.getAuthorizations();
				if (authorizations!=null && !authorizations.isEmpty()) {
					
					// if operator or
					if (operator.equals(AuthorizationSpace.OR)) {
						validAccess = false;
						
						for (int j=0; !validAccess && j<authorizations.size(); j++) {
							AuthorizationSpaceParameter auth = (AuthorizationSpaceParameter)authorizations.get(j);
							String name = auth.getAttribute();
							String value = auth.getValue();
							
							if (name!=null && !name.trim().equals("")) {
								
								// if it is a group
								if (name.equals(AuthorizationSpaceParameter.GROUP)) {
									if (userGroups.contains(value)) {
										validAccess = true;
										log.debug("initSpace"+" :: operator="+operator+" portal_group == "+value+" ??? yes");
									}
									else {
										log.debug("initSpace"+" :: operator="+operator+" portal_group == "+value+" ??? no, portal_group = "+userGroups);
									}
								}
								
								// if it is a parameter
								else {
									Object[] userValues = (Object[])person.getAttributeValues(name);						
									if (userValues!=null) {
									
										for (int k=0; !validAccess && k<userValues.length; k++) {
										
											String userValue = (String)userValues[k];
											if (userValue.toLowerCase().equals(value.toLowerCase())) {
												validAccess = true;
												log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? yes");
											}
											else {
												log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? no, "+name+" = "+userValue);
											}
										}							
									
									}
									else log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? no, "+name+" is null ");
								}
							}
						}	
					}
	
					// if operator and
					else {
						validAccess = true;
						
						for (int j=0; validAccess && j<authorizations.size(); j++) {
							AuthorizationSpaceParameter auth = (AuthorizationSpaceParameter)authorizations.get(j);
							String name = auth.getAttribute();
							String value = auth.getValue();
							
							if (name!=null && !name.trim().equals("")) {
								
								// if it is a group
								if (name.equals(AuthorizationSpaceParameter.GROUP)) {
									if (userGroups.contains(value)) {
										log.debug("initSpace"+" :: operator="+operator+" portal_group == "+value+" ??? yes");
									}
									else {
										validAccess = false;
										log.debug("initSpace"+" :: operator="+operator+" portal_group == "+value+" ??? no, portal_group = "+userGroups);
									}
								}
								
								// if it is a parameter
								else {
									Object[] userValues = (Object[])person.getAttributeValues(name);						
									if (userValues!=null) {
										
										// if this user has this value
										boolean containsValue = false;
										for (int k=0; !containsValue && k<userValues.length; k++) {
										
											String userValue = (String)userValues[k];
											if (userValue.toLowerCase().equals(value.toLowerCase())) {
												containsValue = true;
												log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? yes");
											}
											else {
												log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? no, "+name+" = "+userValue);
											}
										}
										
										if (!containsValue) {
											validAccess = false;
										}
									
									}
									else log.debug("initSpace"+" :: operator="+operator+" "+name+" == "+value+" ??? no, "+name+" is null ");
								}
							}
						}	
					}
				}
				else {
					validAccess = true;
				}
			}
			else {
				validAccess = true;
			}
			
			//System.out.println("validAccess 1 "+validAccess);

			// log
			if (log.isDebugEnabled()) {
				log.debug("initSpace"+" :: validAccess 1 "+validAccess);
			}
			
			// if authorized
			if (validAccess) {
				
				validAccess = false;
			
				// cas authentication mode
				if (false) {//space.getServer().isCasAuthentication()) {
					//TODO validAccess = space.setWebdavAccessObject(davAccessClass, uri, trustedLogin, password);
					validAccess = space.setServerAccessObject();
				}
			
				// trusted or asked authentication mode
				else if (space.getServer().isTrustedAuthentication() || space.getServer().isAskedAuthentication() || space.getServer().isCasAuthentication()) {
					
					// set the static data for cas authentication mode
					if (space.getServer().isCasAuthentication()) {
					}
					
					// if there is a trusted login
					String login = space.getServer().getLogin();
					String accessLogin = null;
					if (login==null || login.equals("")) {
						accessLogin = portalLogin;
						space.getServer().setLogin(accessLogin);
					}
					else accessLogin = login;
				
					// check the {...}
					space.checkPath(person);
					if (!space.getServer().isAskedAuthentication()) {
						space.clearRegexp();
					}
	
					// check the {...} in the checked attributes
					ArrayList checkedAttributes = ChannelConfiguration.getInstance().getCheckedAttributes();
					for (int j=0; j<checkedAttributes.size(); j++) {							
						space.checkAttribute((String)checkedAttributes.get(j), person);							
					}
					
					//System.out.println("avant setServerAccessObject");

					// log
					if (log.isDebugEnabled()) {
						log.debug("initSpace"+" :: before setServerAccessObject");
					}
					
					// we configure the object used by the space to acces the server
					validAccess = space.setServerAccessObject();

					// log
					if (log.isDebugEnabled()) {
						log.debug("initSpace"+" :: after setServerAccessObject");
					}
					//System.out.println("apres setServerAccessObject");
				}
				
			}		
			
			//System.out.println("validAccess 2 "+validAccess);

			// log
			if (log.isDebugEnabled()) {
				log.debug("initSpace"+" :: validAccess 2 "+validAccess);
			}
			
			// we check if this space if valid or not
			if (!validAccess) {
				if (log.isDebugEnabled()){
					log.debug("initSpace"+" :: "+portalLogin+" can not see "+space.getKey());
				}
				
				//System.out.println((!space.isPersonnalSpace())+" "+space.isFromConfigFile());
				if (!space.isPersonnalSpace() || (space.isPersonnalSpace() && space.isFromConfigFile())) 
					return false;
			}
			
			else {
				// set for the space, the channel action object used
				//System.out.println("avant setChannelActionObject");

				// log
				if (log.isDebugEnabled()) {
					log.debug("initSpace"+" :: before setChannelActionObject");
				}
				
				boolean wellDone = space.setChannelActionObject(person, spaces, buffer, portalLogin, userGroups);
				//System.out.println("apres setChannelActionObject");

				// log
				if (log.isDebugEnabled()) {
					log.debug("initSpace"+" :: after setChannelActionObject");
				}
				
				//System.out.println("wellDone "+wellDone);

				// log
				if (log.isDebugEnabled()) {
					log.debug("initSpace"+" :: wellDone "+wellDone);
				}
				
				if (!wellDone && (!space.isPersonnalSpace() || (space.isPersonnalSpace() && space.isFromConfigFile()))) {
					return false;
				}
			}
			
			return true;
		}
		catch(ClassNotFoundException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			PropertiesException ex = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("initSpace"+" :: "+e);
			}
			throw ex;
		}
		catch(IllegalAccessException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			PropertiesException ex = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("initSpace"+" :: "+e);
			}
			throw ex;
		}
		catch(InstantiationException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			PropertiesException ex = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("initSpace"+" :: "+e);
			}
			throw ex;
		}
		catch(MalformedURLException e) {			
			//this.currentSpace.setWebdavAccessObject(null);	
			PropertiesException ex = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("initSpace"+" :: "+e);
			}
			throw ex;
		}
	}
	
		
	
	/**
	 * Output channel content to the portal
	 * 
	 * @param out a sax document handler
	 */
	public void renderXML(ContentHandler out) throws PortalException {
		
		// Create a new XSLT styling engine		
		XSLT xslt = new XSLT(this);
		
		// if we click on help
		/*if (helpMode) {
			String xmlFilePath = "/docbook/CStockage/xml/utilisation.xml";
			
			String mediaOriginal = "media";
			String mediaFinal = "media/org/esupportail/portal/channels/CStockage/docbook";
			
			URL url = ChannelConfiguration.class.getResource(xmlFilePath);
			File xmlFile = new File(url.getFile());
			
		    // pass the result XML to the styling engine.
		    xslt.setXML(xmlFile);
		    
		    // specify the stylesheet selector
		    xslt.setXSL("/docbook/CStockage/xsl/docbookEsup.xsl");
		    xslt.setStylesheetParameter("media.original", mediaOriginal);
		    xslt.setStylesheetParameter("media.final", mediaFinal);
		    
		    // set the output Handler for the output.
		    xslt.setTarget(out);
		    
		    // do the deed
		    xslt.transform();
			
		    helpMode = false;
		    
			return ;
		}*/
		
		
		
		// if we change the space
		String[] spaceChanges = runtimeData.getParameterValues("space");
		if (spaceChanges != null){
			String oldSpaceKey = this.currentSpace.getKey();
			String newSpaceKey = null;
			boolean findChangement = false;
			for (int i = 0; i<spaceChanges.length && !findChangement;i++){
				newSpaceKey = spaceChanges[i];
				if (!newSpaceKey.equals(oldSpaceKey))
					findChangement = true;
			}
			
			// if found, we look for the good space into the ArrayList
			if (findChangement) {
				
				boolean findGoodSpace = false;
				Iterator iter = spaces.iterator();
				while (iter.hasNext() && !findGoodSpace) {
					Space s = (Space)iter.next();
					if (s.getKey().equals(newSpaceKey)) {
						findGoodSpace = true;
						this.currentSpace = s;
					}
						
				}
				
			}
		}
		

		
		
		//////////////////////////////////////////////////////
		// S P A C E S   P E R S O N A L I Z A T I O N
		// Manage the shared spaces 
		currentMode = null;
		StringBuffer xml = null;
		String[] mod=runtimeData.getParameterValues("modeDav");
		if (mod != null){
			for (int i = 0; i<mod.length;i++){
				if (!mod[i].equals("")) {
					currentMode = mod[i];
				}
			}
		}
		
		try {
			
			if (currentMode!=null && currentMode.equals(Constants.MANAGE_SHARED_SPACES)) {
				try {
					stylesheet = new StringBuffer("manageSharedSpaces");
					xml = renderXmlManageSharedSpaces(runtimeData);
				}
				catch(ChannelException e) {
					stylesheet = new StringBuffer("CStockage");
					
					if (e instanceof ConnexionParametersRequired) {
						throw (ConnexionParametersRequired)e;
					}
					if (e instanceof BadConnexionParameters) {
						throw (BadConnexionParameters)e;
					}
					
					if (this.currentSpace!=null) {
						xml = this.currentSpace.getChannelActionObject().renderXmlChannelException(e);
					}
					else {
						xml = AbstractDefaultRenderXml.getXmlError(e, -1);
					}
						
					// log
					if (log.isDebugEnabled()){
						log.debug("renderXML"+" :: "+e);
					}
				}
				
				xsltTransformation(xslt, xml, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
				return;
			}
			
			
			// if no space authorized
			else {
				if (this.currentSpace == null) {
					stylesheet = new StringBuffer("CStockage");
					if (setStaticDataException==null) {
						xml = AbstractDefaultRenderXml.getXmlError(new AnyVisibleSpaceException(), -1);
					}
					else {
						xml = AbstractDefaultRenderXml.getXmlError(setStaticDataException, -1);
					}
					xsltTransformation(xslt, xml, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
					return;
				}
				else {
					// generate the xml for in function of the current space type 
					try {
						this.currentSpace.getChannelActionObject().checkCalledAction(currentMode, staticData, runtimeData, out, xslt, setStaticDataException);
					}
					catch(NullPointerException ex) {
						//ex.printStackTrace();
						StackTraceElement[] stack = ex.getStackTrace();
						String s = "";
						for (int i=0; i<stack.length; i++) {
							s+=stack[i]+"\n";
						}
						log.error("renderXML"+" :: "+ex+" :: \n"+s);
						
						stylesheet = new StringBuffer("CStockage");
						
						ServerException e = new ServerException();
					
						xml = AbstractDefaultRenderXml.getXmlError(e, -1);
						try {
							xml.append(AbstractDefaultRenderXml.getXmlNavigation(spaces, this.currentSpace));
						}
						catch(PropertiesException pe) {
							if (log.isDebugEnabled()) {
								log.debug("renderXML"+" :: "+pe);
							}
						}
						
						// log
						if (log.isDebugEnabled()){
							log.debug("renderXML"+" :: "+e);
						}
						
						xsltTransformation(xslt, xml, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
						return;
					}
					
				}
			}
		}
		catch(BadConnexionParameters e) {
			stylesheet = new StringBuffer("CStockage");
			try {
				StringBuffer xmlTemp = this.currentSpace.getChannelActionObject().renderXmlBadConnexionParametersException(e);
				// log
				if (log.isDebugEnabled()){
					log.debug("checkCalledAction"+" :: "+e);
				}
				xsltTransformation(xslt, xmlTemp, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
				return;
			}
			catch(PropertiesException ex) {
				StringBuffer xmlTemp = this.currentSpace.getChannelActionObject().renderXmlChannelException(ex);
				xsltTransformation(xslt, xmlTemp, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
			}
		}
		catch(ConnexionParametersRequired e) {
			stylesheet = new StringBuffer("CStockage");
			try {
				StringBuffer xmlTemp = this.currentSpace.getChannelActionObject().renderXmlBadConnexionParametersException(e);
				// log
				if (log.isDebugEnabled()){
					log.debug("checkCalledAction"+" :: "+e);
				}
				xsltTransformation(xslt, xmlTemp, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
				return;
			}
			catch(PropertiesException ex) {
				StringBuffer xmlTemp = this.currentSpace.getChannelActionObject().renderXmlChannelException(ex);
				xsltTransformation(xslt, xmlTemp, out, runtimeData, stylesheet, buffer, isSpacesPersonalization);
			}
		}
	}
	
	
	
	
	
	/**
	 * Do the XSLT transformation in the channel
	 * @param xslt the XSLT object
	 * @param xmlTemp the XML generated
	 * @param out the ContentHandler object
	 * @param runtimeData the ChannelRuntimeData object
	 * @param stylesheet the stylesheet used
	 * @param buffer the buffer used in the channel
	 * @throws PortalException
	 */
	public static void xsltTransformation(XSLT xslt, StringBuffer xmlTemp, ContentHandler out, ChannelRuntimeData runtimeData, StringBuffer stylesheet, BufferAction buffer, boolean isSpacesPersonalization) throws PortalException {
		
		StringBuffer xml = new StringBuffer();
		xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");			
		xml.append("<ROOT spaces_personalization=\""+isSpacesPersonalization+"\">");
		xml.append(xmlTemp);
		
		// the baseActionUrl
		String baseActionUrl = runtimeData.getBaseActionURL();
		
		// set the stylesheet and the parameters
		
		//specify the stylesheet selector		
		xslt.setXSL("CStockage.ssl", stylesheet.toString(), runtimeData.getBrowserInfo());		
		
		//url to the channel
		xslt.setStylesheetParameter("baseActionURL",baseActionUrl);				
		
		//url to the download worker
		String downloadUrl = runtimeData.getBaseWorkerURL(UPFileSpec.FILE_DOWNLOAD_WORKER,true).replaceAll("%2F","/");
		xslt.setStylesheetParameter( "downloadURL", downloadUrl);	
		
		// the parameter to know if there is a resource in the clipboard
		if (buffer.getClipboard() != null)
			xslt.setStylesheetParameter("isClipboardEmpty","false");			      
		
		// the parameter used in the copy/move mode. tell if the mode is copy or move
		String clipboardParameter = buffer.getClipboardParameter();
		if (clipboardParameter != null) {
			xslt.setStylesheetParameter("clipboardParameter",clipboardParameter);			

		}

		// if we redirect in https
		try {
			xslt.setStylesheetParameter("redirection", ChannelConfiguration.getInstance().isHttpsRedirection()+"");
		}
		catch(PropertiesException e) {
			xslt.setStylesheetParameter("redirection", "false");
			
			// log
			if (log.isDebugEnabled()){
				log.debug("xsltTransformation"+" :: "+e);
			}
		}
		
		// the final balise
		xml.append("</ROOT>");

		//System.out.println(xml+"\n\n");
		// log
		/*if (log.isDebugEnabled()){
			log.debug("xsltTransformation"+" :: rendered XML "+xml);
		}*/
		
		//pass the result XML to the styling engine.
		String s = xml.toString();		
		xslt.setXML(s);		

		// set the output Handler for the output.
		xslt.setTarget(out);
	
		// do the deed
		xslt.transform();
	}
	

	/**
	 * Init the configuration spaces
	 * @throws DataBaseException
	 */
	/*private void initConfigurationSpaces() throws DataBaseException, ChannelException {

		
		
	}*/
	
	
	/**
	 * Init the personal spaces into the menu
	 * @throws DataBaseException
	 */
	private void initPersonalSpacesIntoMenu() throws DataBaseException, ChannelException {

		// init the personal spaces
		PersonalizationTool tool = new PersonalizationTool();
		TreeSet usedSpaces = getUsedSpaces(tool, this.portalLogin, this.userGroups, this.notObligedSpaces);
		this.currentSpace = setSpacesIntoMenu(this.spaces, this.currentSpace, tool, this.person, this.portalLogin, this.userGroups, usedSpaces, this.buffer, this.staticData);
			
	}

		
	
	
	
	
	
		
	
	/**************************
	 *  Obliged spaces from DB
	 **************************/
	

	/**
	 * Set the obliged spaces for this user
	 */
	public static void addObligedSpacesToList(String userPortalLogin, Vector userGroups, ArrayList initialSpaces) throws DataBaseException, PropertiesException, ServerException {

		PersonalizationTool tool = new PersonalizationTool();
		
		// get each obliged space for the current user
		Vector spaces = tool.getAvailableSpacesForUser(userPortalLogin, userPortalLogin, true);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
			initialSpaces.add(space);
		}
			

		// get each obliged space for the groups of the current user
		for (int g=userGroups.size()-1; g>=0; g--) {
			spaces = tool.getAvailableSpacesForGroup((String)userGroups.elementAt(g), userPortalLogin, true);
			for (int i=0; i<spaces.size(); i++) {
				Space space = (Space)spaces.elementAt(i);
				initialSpaces.add(space);
			}
		}
		

		// get each obliged space for all
		/*spaces = tool.getAvailableSpacesForAll(userPortalLogin, true);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
			initialSpaces.add(space);
		}*/
		
	}
	
		

		
	/**************************
	 *   Manage shared spaces
	 **************************/
			
			
			
	/**
	 * The avalaible spaces
	 */
	private TreeSet availableAndUsedSpaces;

	
	
	
	/**
	 * Set the used spaces and the avalaible spaces for this user
	 */
	private static TreeSet getAvailableAndUsedSpaces(PersonalizationTool tool, String userPortalLogin, Vector userGroups, ArrayList notObligedSpaces) throws DataBaseException, PropertiesException, ServerException {

		TreeSet sortedSpaces = new TreeSet();
		//TreeMap availableSpaces = new TreeMap();

		// we get each space from the preferences user
		Vector[] spacesFromPreferences = tool.getKeyOfSpacesFromPreferences(userPortalLogin);
		Vector idUsedUsers = spacesFromPreferences[0];
		Vector labelUsedUsers = spacesFromPreferences[1];
			
		// get each shared space for the current user
		Vector spaces = tool.getAvailableSpacesForUser(userPortalLogin, userPortalLogin, false);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
				
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			space.getCurrentViewer().setLabelTemp(space.getLabel());
			if (index== -1) {
				space.getCurrentViewer().setUsed(false);
				space.setLabel("");
			}
			else {
				space.getCurrentViewer().setUsed(true);
				String label = (String)labelUsedUsers.elementAt(index);
				if (label!=null && !label.trim().equals("")) {
					space.getCurrentViewer().setLabelTemp(label);
					space.setLabel(label);
				}
				else {
					space.setLabel("");
				}
			}
			
			if (!sortedSpaces.contains(space))
				sortedSpaces.add(space);
		}
			

		// get each shared space for the groups of the current user
		for (int g=userGroups.size()-1; g>=0; g--) {//TODO
			spaces = tool.getAvailableSpacesForGroup((String)userGroups.elementAt(g), userPortalLogin, false);
			for (int i=0; i<spaces.size(); i++) {
				Space space = (Space)spaces.elementAt(i);
				
				String id = space.getKey();
				int index = idUsedUsers.indexOf(id);
				space.getCurrentViewer().setLabelTemp(space.getLabel());
				if (index== -1) {
					space.getCurrentViewer().setUsed(false);
					space.setLabel("");
				}
				else {
					space.getCurrentViewer().setUsed(true);
					String label = (String)labelUsedUsers.elementAt(index);
					if (label!=null && !label.trim().equals("")) {
						space.getCurrentViewer().setLabelTemp(label);
						space.setLabel(label);
					}
					else {
						space.setLabel("");
					}
				}
				
				if (!sortedSpaces.contains(space))
					sortedSpaces.add(space);
				
			}
		}

		// get each shared space for the groups of the current user
		/*spaces = tool.getAvailableSpacesForAll(userPortalLogin, false);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
			
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			space.getCurrentViewer().setLabelTemp(space.getLabel());
			if (index== -1) {
				space.getCurrentViewer().setUsed(false);
				space.setLabel("");
			}
			else {
				space.getCurrentViewer().setUsed(true);
				String label = (String)labelUsedUsers.elementAt(index);
				if (label!=null && !label.trim().equals("")) {
					space.getCurrentViewer().setLabelTemp(label);
					space.setLabel(label);
				}
				else {
					space.setLabel("");
				}
			}
			
			if (!sortedSpaces.contains(space))
				sortedSpaces.add(space);	
		}*/
		
		// get local available spaces
		for (int i=0; i<notObligedSpaces.size(); i++) {
			Space space = (Space)notObligedSpaces.get(i);
			
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			space.getCurrentViewer().setLabelTemp(space.getLabel());
			if (index== -1) {
				space.getCurrentViewer().setUsed(false);
				space.setLabel("");
			}
			else {
				space.getCurrentViewer().setUsed(true);
				String label = (String)labelUsedUsers.elementAt(index);
				if (label!=null && !label.trim().equals("")) {
					space.getCurrentViewer().setLabelTemp(label);
					space.setLabel(label);
				}
				else {
					space.setLabel("");
				}
			}
			
			if (!sortedSpaces.contains(space))
				sortedSpaces.add(space);	
		}
		
		
		// check each space. if there are spaces more than one time, we keep the one wich is used
		TreeSet resultSpaces = sortedSpaces;
		resultSpaces = new TreeSet();
		Iterator iter = sortedSpaces.iterator();
		Space spaceToKeep = null;
		while (iter.hasNext()) {
			
			Space space = (Space)iter.next();
			String spacePath = space.getCurrentFullUrlPath();
			
			if (spaceToKeep==null) {
				spaceToKeep = space;
			}
			else {
				
				String keepPath = spaceToKeep.getCurrentFullUrlPath();
				
				// the current space is the same than the one we keep
				if (spacePath.equals(keepPath)) {
					
					// if this one is used
					if (space.getCurrentViewer().isUsed()) {
						spaceToKeep = space;
					}
					
				}
				
				// the current space is diferent
				else {
					resultSpaces.add(spaceToKeep);
					spaceToKeep = space;
				}

			}
			
			
		}
		
		// add the last
		if (spaceToKeep!=null)
			resultSpaces.add(spaceToKeep);
		
		
		return resultSpaces;
	}
	
	
	

	
	/**
	 * Set the used spaces and the avalaible spaces for this user
	 */
	private static TreeSet getUsedSpaces(PersonalizationTool tool, String userPortalLogin, Vector userGroups, ArrayList notObligedSpaces) throws DataBaseException, PropertiesException, ServerException {

		TreeSet usedSpaces = new TreeSet();
		
		// we get each space from the preferences user
		Vector[] spacesFromPreferences = tool.getKeyOfSpacesFromPreferences(userPortalLogin);
		Vector idUsedUsers = spacesFromPreferences[0];
		Vector labelUsedUsers = spacesFromPreferences[1];
			
		// get each shared space for the current user
		Vector spaces = tool.getAvailableSpacesForUser(userPortalLogin, userPortalLogin, false);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
				
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			if (index!= -1) {
				if (!usedSpaces.contains(space)) {
					usedSpaces.add(space);
					String label = (String)labelUsedUsers.elementAt(index);
					if (label!=null && !label.trim().equals("")) {
						space.setLabel(label);
					}
					else {
						space.setLabel(space.getLabel());
					}
				}
			}
			
		}
			

		// get each shared space for the groups of the current user
		for (int g=userGroups.size()-1; g>=0; g--) {//TODO
			spaces = tool.getAvailableSpacesForGroup((String)userGroups.elementAt(g), userPortalLogin, false);
			for (int i=0; i<spaces.size(); i++) {
				Space space = (Space)spaces.elementAt(i);
				
				String id = space.getKey();
				int index = idUsedUsers.indexOf(id);
				if (index!= -1) {
					if (!usedSpaces.contains(space)) {
						usedSpaces.add(space);
						String label = (String)labelUsedUsers.elementAt(index);
						if (label!=null && !label.trim().equals("")) {
							space.setLabel(label);
						}
						else {
							space.setLabel(space.getLabel());
						}
					}
				}
					
			}
		}

		// get each shared space for the groups of the current user
		/*spaces = tool.getAvailableSpacesForAll(userPortalLogin, false);
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);
			
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			if (index!= -1) {
				if (!usedSpaces.contains(space)) {
					usedSpaces.add(space);
					String label = (String)labelUsedUsers.elementAt(index);
					if (label!=null && !label.trim().equals("")) {
						space.setLabel(label);
					}
					else {
						space.setLabel(space.getLabel());
					}
				}
			}
		}*/
		
		// get local available spaces
		for (int i=0; i<notObligedSpaces.size(); i++) {
			Space space = (Space)notObligedSpaces.get(i);
			String id = space.getKey();
			int index = idUsedUsers.indexOf(id);
			if (index!= -1) {
				if (!usedSpaces.contains(space)) {
					usedSpaces.add(space);
					String label = (String)labelUsedUsers.elementAt(index);
					if (label!=null && !label.trim().equals("")) {
						space.setLabel(label);
					}
					else {
						space.setLabel(space.getLabel());
					}
				}
			}
		}
		
		return usedSpaces;
	}
	
	
		

	/**
	 * Set the personal spaces into the spaces menu
	 * @throws DataBaseException
	 */
	public static Space setSpacesIntoMenu(ArrayList spaces, Space currentSpace, PersonalizationTool tool, IPerson person, String userPortalLogin, Vector userGroups, TreeSet usedSpaces, BufferAction buffer, ChannelStaticData staticData) throws DataBaseException, PropertiesException, ApplicationException {			
		
		Space currSpace = currentSpace;
		
		// delete each space wich has been deleted from the database and from the spaces list
		for (int i=0; i<spaces.size(); i++) {
			Space s = (Space)spaces.get(i);
			//System.out.println("1:"+s.getLabel());
			
			boolean contains = false;
			Iterator iter = usedSpaces.iterator();
			while (iter.hasNext() && !contains) {
				Space temp = (Space)iter.next();
				if (temp.getKey().equals(s.getKey())) {
					contains = true;
				}
			}
			
			if (s.isPersonnalSpace() && !contains) {
				
				// delete from the database
				tool.delStorageUsersPreferencesForUser(s.getKey(), userPortalLogin);								
				
				// delete from the list
				spaces.remove(i);
				i--;
				
				// if the space deleted is the current space
				if (currentSpace!=null && s.getKey().equals(currentSpace.getKey())) {
					if (spaces.size()>0)
						currSpace = (Space)spaces.get(0);
					else currSpace = null;
				}
			}
		}
		
		// add each used space into the list and in the user preferences
		Iterator used = usedSpaces.iterator();
		while(used.hasNext()) {
			Space s = (Space)used.next();
			String spaceId = s.getKey();
			
			if (!spaces.contains(s)) {
				// add into the user preferences
				
				String label = null;
				String labelTemp = s.getCurrentViewer().getLabelTemp();
				if (labelTemp!=null) {
					label = labelTemp;
				}
				else {
					label = s.getLabel();
				}
				
				s.setLabel(label);
				
				tool.addStorageUsersPreferences(spaceId, userPortalLogin, label);
				
				// add into the used list
				spaces.add(s);			
			}
			
			// if still contains
			else {
				
				String labelOriginal = s.getLabel();
				String labelTemp = s.getCurrentViewer().getLabelTemp();
				
				if (!labelOriginal.equals(labelTemp) && labelTemp!=null) {
					tool.updateStorageUsersPreferencesLabel(spaceId, userPortalLogin, labelTemp);
					Space spaceToUpdate = (Space)spaces.get(spaces.indexOf(s));
					spaceToUpdate.setLabel(labelTemp);
				}
			}
			
		}
		
		// init each personal space connexion
		for (int i=0; i<spaces.size(); i++) {//TODO
			
			Space space = (Space)spaces.get(i);
			
			if (space.isPersonnalSpace() && space.getServerAccessObject()==null) {				
				//System.out.println("\n\n\n\n\n"+space.getLabel());
				
				initSpace(space, person, userPortalLogin, spaces, buffer, userGroups, staticData);
				
				/*
				// set the server access
				boolean serverOk = false;
				try {
					serverOk = space.setServerAccessObject();
				}
				catch(Exception e) {
					log.error("setSpacesIntoMenu"+" :: "+e);
					//serverOk = false;
				}
				//System.out.println("   server ok ? "+serverOk);
				// set for the space, the channel action object used
				
				boolean wellDone = false;
				//if (serverOk) {
				wellDone = space.setChannelActionObject(person, spaces, buffer, userPortalLogin, userGroups);
				//System.out.println("   action ok ? "+wellDone);
				//}				
				 
				 //if (!wellDone) {
				 //spaces.remove(i);
				 //i--;
				 //}
				*/
				
			}
			
		}
		if (currSpace == null && spaces.size()>0) {
			currSpace = (Space)spaces.get(0);
		}
		
		return currSpace;
	}
		
	
	
	
	
	/**
	 * Generate the XML when we want to manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 * @throws CancelException
	 */
	private StringBuffer renderXmlManageSharedSpacesGetXmlForRender(ChannelRuntimeData runtimeData) throws ServerException, PropertiesException  {
		
		StringBuffer xml = new StringBuffer();
		
		Vector spacesList = new Vector();
		Vector labelsList = new Vector();
		
		// generate the spaces and labels lists
		String url = null;
		Vector spaces = new Vector();
		Iterator iter = availableAndUsedSpaces.iterator();
		while (iter.hasNext()) {
			Space space = (Space)iter.next();
			
			String urlTemp = space.getServer().getUrl();
			if (url == null) {
				url = urlTemp;
			}
			
			if (urlTemp.equals(url)) {
				spaces.addElement(space);
			}
			else {
				spacesList.addElement(spaces);
				labelsList.addElement(url);
				
				spaces = new Vector();
				spaces.addElement(space);
				url = urlTemp;
			}
		}
		
		// the last list
		spacesList.addElement(spaces);
		labelsList.addElement(url);
		
		// render the xml for each one
		int size = spacesList.size();
		for (int i=0; i<size; i++) {
			spaces = (Vector)spacesList.elementAt(i);
			url = (String)labelsList.elementAt(i);
			
			if (url !=null) {
				/*if (size==1) {
					url = "";
				}*/
				
				// mapping of the url
				String label = url;
				Hashtable mapping = ChannelConfiguration.getInstance().getSharingMapping();
				if (mapping != null) {
					String mappingTemp = (String)mapping.get(url);
					if (mappingTemp!=null) {
						label = mappingTemp;
					}	
				}
				
				xml.append("<spaces label=\""+label+"\">");
				xml.append(renderXmlManageSharedSpacesGetXmlForRenderOnlySpaces(spaces));		
				xml.append("</spaces>");
			}
		}
		
		return xml;
	}
	
	
	
	
	/**
	 * Generate the XML when we want to manage the shared spaces
	 * @param spaces spaces list
	 * @return the XML for this mode
	 * @throws ServerException
	 * @throws PropertiesException
	 */
	/*private StringBuffer renderXmlManageSharedSpacesGetXmlForRenderOnlySpaces(Vector spaces) throws ServerException, PropertiesException  {
		
		StringBuffer xml = new StringBuffer();
		
		// for each space
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);			
			
			SharedSpaceProperties currentViewver = space.getCurrentViewer();
			String from = "";
			if(currentViewver!=null) {
				from = (new UserForPersonalization(currentViewver.getFromKey()).getDisplayName());
			}
			
			int nbChilds = spaces.size()-i-1;
			
			// get the display name
			String displayName = space.getPath();
			if (i>0) {
				Space previousSpace = (Space)spaces.elementAt(i-1);
				String previousDisplayName = previousSpace.getPath();
				if (displayName.startsWith(previousDisplayName) && !displayName.equals(previousDisplayName)) {
					displayName = displayName.substring(previousDisplayName.length());
				}
			}
			if (displayName.startsWith("/")) {
				displayName = displayName.substring(1);
			}
			if (displayName.endsWith("/")) {
				displayName = displayName.substring(0, displayName.length()-1);
			}
			
			// get the XML
			xml.append("<space childs=\""+nbChilds+"\" index=\""+i+"\" key=\""+space.getKey()+"\" displayName=\""+displayName+"\" from=\""+from+"\" used=\""+space.isUsed()+"\" label=\""+space.getLabel()+"\"/>");
		}				

		return xml;
	}*/
	private StringBuffer renderXmlManageSharedSpacesGetXmlForRenderOnlySpaces(Vector spaces) throws ServerException, PropertiesException  {
		
		StringBuffer xml = new StringBuffer();
		
		Object[] tree = renderXmlManageSharedSpacesGetXmlForRenderOnlySpacesGenerateTree(spaces);
		
		// for each space
		int treeDepth = getTreeDepth(tree);
		renderXmlManageSharedSpacesGetXmlForRenderOnlySpacesRecur(tree, xml, treeDepth, -1);		

		return xml;
	}
	
	
	
	private void renderXmlManageSharedSpacesGetXmlForRenderOnlySpacesRecur(Object[] tree, StringBuffer xml, int treeDepth, int depth) throws ServerException, PropertiesException  {
		
		// the space
		Space space = (Space)tree[0];
		if (space!=null) {
			SharedSpaceProperties currentViewver = space.getCurrentViewer();
			String from = "";
			if(currentViewver!=null) {
				from = (new UserForPersonalization(currentViewver.getFromKey()).getDisplayName());
			}
			
			int nbChilds = treeDepth-depth-1;
			
			// get the display name
			String displayName = space.getPath();
			Space parentSpace = (Space)tree[2];
			if (parentSpace!=null) {
				String previousDisplayName = parentSpace.getPath();
				if (displayName.startsWith(previousDisplayName) && !displayName.equals(previousDisplayName)) {
					displayName = displayName.substring(previousDisplayName.length());
				}
			}
			if (displayName.startsWith("/")) {
				displayName = displayName.substring(1);
			}
			if (displayName.endsWith("/")) {
				displayName = displayName.substring(0, displayName.length()-1);
			}
			
			// get the XML
			xml.append("<space childs=\""+nbChilds+"\" index=\""+depth+"\" key=\""+space.getKey()+"\" displayName=\""+displayName+"\" from=\""+from+"\" used=\""+space.getCurrentViewer().isUsed()+"\" label=\""+space.getCurrentViewer().getLabelTemp()+"\"/>");
		}
		
		
		
		// the children
		Vector children = (Vector)tree[1];
		for (int i=0; i<children.size(); i++) {
			
			Object[] node = (Object[])children.elementAt(i);			
			renderXmlManageSharedSpacesGetXmlForRenderOnlySpacesRecur(node, xml, treeDepth, depth+1);
			
		}				

	}
	
	
	
	/**
	 * Generate the XML when we want to manage the shared spaces
	 * @param spaces spaces list
	 * @return the XML for this mode
	 * @throws ServerException
	 * @throws PropertiesException
	 */
	private Object[] renderXmlManageSharedSpacesGetXmlForRenderOnlySpacesGenerateTree(Vector spaces) throws ServerException, PropertiesException  {
		
		Object[] root = new Object[3];
		root[0] = null;
		root[1] = new Vector();
		root[2] = null;
		
		// for each space
		for (int i=0; i<spaces.size(); i++) {
			Space space = (Space)spaces.elementAt(i);			
			String spacePath = space.getPath();
			
			Object[] nodeWhereAdd = renderXmlManageSharedSpacesGetNodeFromTree(spacePath, root);
			Vector vectorWhereAdd = (Vector)nodeWhereAdd[1];
			
			Object[] node = new Object[3];
			node[0] = space;
			node[1] = new Vector();
			node[2] = (Space)nodeWhereAdd[0];
			vectorWhereAdd.addElement(node);
		}				

		return root;
	}
	
	
	
	
	private Object[] renderXmlManageSharedSpacesGetNodeFromTree(String path, Object[] node) {
		
		// check if we have to search into children
		boolean searchInChildren = false;
		if (node[0]==null) {
			searchInChildren = true;
		}
		else {
			Space space = (Space)node[0];
			String spacePath = space.getPath();
			if (path.startsWith(spacePath)) {
				searchInChildren = true;
			}
			else {
				return null;
			}
		}
		
		// return the node
		if (!searchInChildren) {
			return node;
		}
		
		// we search into the children
		else {
			Object[] foundNode = null;
			Vector children = (Vector)node[1];
			for (int i=0; i<children.size() && foundNode==null; i++) {
				Object[] o = (Object[])children.elementAt(i);
				foundNode = renderXmlManageSharedSpacesGetNodeFromTree(path, o);
			}
			if (foundNode!=null) {
				return foundNode;
			}
			else {
				return node;
			}
		}
		
	}
	
	private int getTreeDepth(Object[] root) {
		return getTreeDepth(root, -1);
	}
	
	
	private int getTreeDepth(Object[] node, int depth) {
		
		Vector children = (Vector)node[1];
		
		int myDepth = depth+1;
		
		int max = myDepth;
		for (int i=0; i<children.size(); i++) {
			Object[] o = (Object[])children.elementAt(i);
			int childDepth = getTreeDepth(o, myDepth);
			if (childDepth>max) {
				max = childDepth;
			}
		}
		
		return max;
	}
	
	
	

	
	/**
	 * Generate the XML when we want to manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 * @throws CancelException
	 * @throws DataBaseException
	 */
	private StringBuffer renderXmlManageSharedSpaces(ChannelRuntimeData runtimeData) throws ChannelException, ConnexionParametersRequired, ApplicationException, PropertiesException, CancelException, DataBaseException, ServerException {
		
		// if it is the first call
		if (availableAndUsedSpaces == null) {
			availableAndUsedSpaces = getAvailableAndUsedSpaces(new PersonalizationTool(), portalLogin, userGroups, this.notObligedSpaces);
		}
		
		// check the labels
		renderXmlManageSharedSpacesCheckLabels(runtimeData);
		
		// if cancel
		String action = runtimeData.getParameter("actionForm");
		if (action!=null) {
			if (action.equals("cancel")) {
				renderXmlManageSharedSpacesCancel();
			}
			
			// if valid		
			if (action.equals("valid")) {
				StringBuffer xml = renderXmlManageSharedSpacesValid(runtimeData);
				return xml;
			}
		}
		
		// if add
		String add = runtimeData.getParameter("add");
		if (add != null && !add.trim().equals("")) {
			renderXmlManageSharedSpacesAdd(runtimeData);
		}
		
		// if delete
		String delete = runtimeData.getParameter("del");
		if (delete != null && !delete.trim().equals("")) {
			renderXmlManageSharedSpacesDelete(runtimeData);
		}
		
		// generate the xml
		return renderXmlManageSharedSpacesGetXmlForRender(runtimeData);
	}
	
	
	
	

	
	/**
	 * Generate the XML when we click on "valid" when we manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 * @throws DataBaseException
	 */
	private void renderXmlManageSharedSpacesCheckLabels(ChannelRuntimeData runtimeData) throws ChannelException, DataBaseException, PropertiesException, ApplicationException, ConnexionParametersRequired {
		
		Iterator iter = availableAndUsedSpaces.iterator();
		while(iter.hasNext()) {
			Space s = (Space)iter.next();
			String key = s.getKey();
			
			String userLabel = runtimeData.getParameter("label_"+key);
			if (userLabel!=null)
				s.getCurrentViewer().setLabelTemp(userLabel);
		}
		
	}
	
	
	
	
	
	
	/**
	 * Generate the XML when we click on "cancel" when we manage the shared spaces
	 * @throws CancelException
	 */
	private void renderXmlManageSharedSpacesCancel() throws CancelException, PropertiesException, ConnexionParametersRequired {
		availableAndUsedSpaces = null;

		// if it the asked authentication, and none password still set
		if (this.currentSpace.getServer().isAskedAuthentication() && (this.currentSpace.getServer().getPassword()==null || this.currentSpace.getServer().getPassword().trim().equals(""))) {
			throw new ConnexionParametersRequired();
		}
		
		throw new CancelException();
	}
	
	
	
	
	
	/**
	 * Generate the XML when we click on "valid" when we manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 * @throws DataBaseException
	 */
	private StringBuffer renderXmlManageSharedSpacesValid(ChannelRuntimeData runtimeData) throws ChannelException, DataBaseException, PropertiesException, ApplicationException, ConnexionParametersRequired {
		
		TreeSet spacesUsed = new TreeSet();
		
		// check each element
		Iterator iter = availableAndUsedSpaces.iterator();
		while (iter.hasNext()) {
			
			Space value = (Space)iter.next();
			
			if (value.getCurrentViewer().isUsed()) {
				spacesUsed.add(value);
			}
		}
		
		
		
		this.currentSpace = setSpacesIntoMenu(this.spaces, this.currentSpace, new PersonalizationTool(), this.person, this.portalLogin, this.userGroups, spacesUsed, this.buffer, this.staticData);
		
		availableAndUsedSpaces = null;
		
		stylesheet = new StringBuffer("CStockage");
		if (setStaticDataException instanceof AnyVisibleSpaceException) {
			setStaticDataException = null;
		}
		
		
		
		if (this.currentSpace!=null) {
			// if it the asked authentication, and none password still set
			if (this.currentSpace.getServer().isAskedAuthentication() && (this.currentSpace.getServer().getPassword()==null || this.currentSpace.getServer().getPassword().trim().equals(""))) {
				throw new ConnexionParametersRequired();
			}
			
			if (this.currentSpace.getChannelActionObject()==null) {
				this.currentSpace = (Space)this.spaces.get(0);
			}
			return this.currentSpace.getChannelActionObject().renderXmlWithInformation("2015");
		}
		else {
			return AbstractDefaultRenderXml.getXmlInformation("2015");
		}
	}
	
	
	
	
	
	/**
	 * Generate the XML when we click on "add" when we manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 */
	private StringBuffer renderXmlManageSharedSpacesAdd(ChannelRuntimeData runtimeData) throws ServerException, PropertiesException  {
		
		// we check the space we want to add
		String spaceId = runtimeData.getParameter("add");
		
		Space space = null;
		Iterator iter = availableAndUsedSpaces.iterator();
		while (iter.hasNext() && space==null) {
			Space temp = (Space)iter.next();
			if (temp.getKey().equals(spaceId)) {
				space = temp;
				space.getCurrentViewer().setUsed(true);
			}
		}

		return renderXmlManageSharedSpacesGetXmlForRender(runtimeData);
	}
	
	
	
	/**
	 * Generate the XML when we click on "delete" when we manage the shared spaces
	 * @param runtimeData the runtime data channel object
	 * @return the XML for this mode
	 */
	private StringBuffer renderXmlManageSharedSpacesDelete(ChannelRuntimeData runtimeData) throws ServerException, PropertiesException  {

		// we check the space we want to delete
		String spaceId = runtimeData.getParameter("del");
		
		Space space = null;
		Iterator iter = availableAndUsedSpaces.iterator();
		while (iter.hasNext() && space==null) {
			Space temp = (Space)iter.next();
			if (temp.getKey().equals(spaceId)) {
				space = temp;
				space.getCurrentViewer().setUsed(false);
			}
		}
		
		return renderXmlManageSharedSpacesGetXmlForRender(runtimeData);
	}
		
		

/***************************************************************************/
/*********************START OF DOWNLOAD FUNCTIONS***************************/
/***************************************************************************/

	/**
	 * The resource to download
	 */
	private ChannelResource downloadResource = null;
	
	
  	/**
	 * Return the content type of the seleted file
	 * @see org.jasig.portal.IMimeResponse#getContentType()
	 */
	public String getContentType() {				
		return downloadResource.getContentType();
	}


	
	/**
	 * Send HTTP header
	 * @see org.jasig.portal.IMimeResponse#getHeaders()
	 */
	public Map getHeaders() {
		Map map = new HashMap();
      
		fileId = runtimeData.getParameter("downloadFile");
		//System.out.println("fileId: "+fileId); 
		try {
			fileId = URLDecoder.decode(fileId,"UTF-8");
			//System.out.println("fileId: "+fileId);
		}
		catch (UnsupportedEncodingException e) {
			log.error("getHeaders"+" :: "+e);			
		}
    
		// we check if it is a directory
		String path = currentSpace.getCurrentPath();
		
		try {
			//System.out.println("path: "+path);
			downloadResource = this.currentSpace.getServerAccessObject().download(fileId,path);
				
			fileId = fileId.replaceAll(" ", "_");
			fileId = fileId.replaceAll("[àäâã]", "a");
			fileId = fileId.replaceAll("[éêèë]", "e");
			fileId = fileId.replaceAll("[îïì]", "i");
			fileId = fileId.replaceAll("[ôöòõ]", "o");
			fileId = fileId.replaceAll("[ûüù]", "u");
			fileId = fileId.replaceAll("ç", "c");
			fileId = fileId.replaceAll("ñ", "n");
			fileId = fileId.replaceAll("[ÀÄÂÃ]", "A");
			fileId = fileId.replaceAll("[ÉÈËÊ]", "E");
			fileId = fileId.replaceAll("[ÌÏÎ]", "I");
			fileId = fileId.replaceAll("[ÒÖÔÕ]", "O");
			fileId = fileId.replaceAll("[ÙÜÛ]", "U");
			fileId = fileId.replaceAll("Ç", "C");
			fileId = fileId.replaceAll("Ñ", "N");		
			
			// open in new window : inline  -- ||
			// download : attachment  -- -- -- ||
			//                                 \/
			map.put("Content-disposition", "attachment; filename="+fileId  );

			return map;
		}
		catch(DownloadException e) {
			log.error("getHeaders"+" :: "+e);
			map.put("Location", runtimeData.getBaseActionURL());
			return map;
		}
	}
	
	

	/**
	 * Send HTTP header
	 * @see org.jasig.portal.IMimeResponse#getHeaders()
	 */
	public Map getHeaders2() {
		Map map = new HashMap();
      
		fileId = runtimeData.getParameter("downloadFile");		
    
		// we check if it is a directory
		String path = currentSpace.getCurrentPath();
		
		try {
			//System.out.println("path: "+path);
			downloadResource = this.currentSpace.getServerAccessObject().download(fileId,path);				
			
			// open in new window : inline  -- ||
			// download : attachment  -- -- -- ||
			//                                 \/
			//map.put("Content-disposition", "attachment; filename=\""+fileId+"\";charset=\"utf-8\" ");
			map.put("Content-disposition", "attachment; filename=\""+fileId+"\"");
			//map.put("Content-disposition", "attachment");			
			//map.put("Content-Type", "text/html; charset=\"iso-8859-1\"");
			return map;
		}
		catch(DownloadException e) {
			log.error("getHeaders"+" :: "+e);
			map.put("Location", runtimeData.getBaseActionURL());
			return map;
		}
	}
	
	
	/**
	 *	Get the strem for the file to dowload
	 * @see org.jasig.portal.IMimeResponse#getInputStream()
	 */
	public InputStream getInputStream() throws IOException {	
		return downloadResource.getInputStream();
	}


	/**
	 * Function unused here
	 * @see org.jasig.portal.IMimeResponse#downloadData(java.io.OutputStream)
	 */
	public void downloadData(OutputStream arg0) throws IOException {
	}


	/**
	 * Function unused here
	 * @see org.jasig.portal.IMimeResponse#getName()
	 */
	public String getName() {
		System.out.println("passe par le getName");
		return "yahoo.txt";
	}


	/**
	 * Print the error generated by the download
	 * @see org.jasig.portal.IMimeResponse#reportDownloadError(java.lang.Exception)
	 */
	public void reportDownloadError(Exception arg0) {
		log.error("reportDownloadError"+" :: "+arg0);
	}

	

	/***************************************************************************/
	/*********************END OF DOWNLOAD FUNCTIONS*****************************/
	/***************************************************************************/



	/***************************************************************************/
	/**********************START OF CACHE FUNCTIONS*****************************/
	/***************************************************************************/

	/* (non-Javadoc)
	 * @see org.jasig.portal.ICacheable#generateKey()
	 */
	public ChannelCacheKey generateKey() {

	    ChannelCacheKey k = new ChannelCacheKey();
	    StringBuffer sbKey = new StringBuffer(1024);
	    sbKey.append(this.getClass().getName() + " : ");
	    sbKey.append("login : "+portalLogin+";");
	    sbKey.append("SubscribeId:"+this.staticData.getChannelSubscribeId());
	    k.setKeyScope(ChannelCacheKey.INSTANCE_KEY_SCOPE);

	    k.setKey(sbKey.toString());
	    k.setKeyValidity(new Long(System.currentTimeMillis()));
	    /*LogService.log(LogService.DEBUG,
	                              "CStockage::generateKey() (id : " +
	                              this.staticData.getChannelSubscribeId() +
	                              ") : generateKey :  -> Cle de cache:" + k.getKey());
	    */
		return k;
	}

	/* (non-Javadoc)
	 * @see org.jasig.portal.ICacheable#isCacheValid(java.lang.Object)
	 */
	public boolean isCacheValid(Object validity) {

	    boolean cacheValid = false;

	    /*if (helpMode) {
	    	//helpMode = false;
	    	return false;
	    }*/
	    
	  if(runtimeData.getParameters().size()==0)
	  		cacheValid=true;

	  /*if (cacheValid) {
        LogService.log(LogService.DEBUG,
                                  "CStockage::isCacheValid (" +
                                  this.staticData.getChannelSubscribeId() +
                                  ") : isCacheValid -> YES");
      }
      else {
        LogService.log(LogService.DEBUG,
                                  "CStockage::isCacheValid (" +
                                  this.staticData.getChannelSubscribeId() +
                                  ") : isCacheValid -> NO");
      }*/
	    return cacheValid;
	}
	/***************************************************************************/
	/************************END OF CACHE FUNCTIONS*****************************/
	/***************************************************************************/
}
