/*
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.Iterator;
import java.util.Map;
import java.util.TreeMap;
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.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.CancelException;
import org.esupportail.portal.channels.CStockage.exception.ChannelException;
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.channels.CStockage.userManagement.PortalGroupsManagement;
import org.jasig.portal.ChannelCacheKey;
import org.jasig.portal.ChannelRuntimeData;
import org.jasig.portal.ChannelStaticData;
import org.jasig.portal.ICacheable;
import org.jasig.portal.IMimeResponse;
import org.jasig.portal.PortalException;
import org.jasig.portal.UPFileSpec;
import org.jasig.portal.channels.BaseChannel;
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 extends BaseChannel implements IMimeResponse,ICacheable  {


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


  
	
	/**
	 * The spaces availables
	 */
	private ArrayList spaces;
	
	/**
	 * 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;
	

	
	
	
	/**
	 * 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;
	

	
	
	
	/**
	 * Constructor
	 */
	public CStockage() {				
		
		// init the buffer
		this.buffer = new BufferAction();
	}	

	
	/**
	 * 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
			userGroups = PortalGroupsManagement.getUserGroupsKeys(portalLogin);
			
			// if we support the spaces personalization
			isSpacesPersonalization = ChannelConfiguration.getInstance().isSpacesPersonalization();
			

			
			
			// the spaces availables in the configuration file
			spaces = config.getDefaultSpaces();
			
			// 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);
				boolean valid = initSpace(space, person, portalLogin, spaces, buffer, userGroups);
				
				if (!valid) {
					spaces.remove(i);
					i--;
				}
				
				// the space
				/*Space space = (Space)spaces.get(i);

				// set the server access class
				String serverType = space.getServerType();
				String serverClass = null;
				
				// 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 attribute = auth.getAttribute();
						String value = auth.getValue();
						
						if (attribute==null || attribute.trim().equals("")) {
							Object[] userValues = (Object[])person.getAttributeValues(attribute);						
							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("setStaticData"+" :: "+attribute+" == "+value+" ??? yes");
									}
									else log.debug("setStaticData"+" :: "+attribute+" == "+value+" ??? no, "+attribute+" = "+userValue);
								}							
							
							}
							else log.debug("setStaticData"+" :: "+attribute+" == "+value+" ??? no, "+attribute+" is null ");
						}
					}					
				}
				else {
					validAccess = true;
				}
				
				// if authorized
				if (validAccess) {					
					
					validAccess = false;
				
					// cas authentication mode
					if (space.isCasAuthentication()) {
					
						//TODO validAccess = space.setWebdavAccessObject(davAccessClass, uri, trustedLogin, password);
					}
				
					// trusted or asked authentication mode
					else if (space.isTrustedAuthentication() || space.isAskedAuthentication()){
					
						// if there is a trusted login
						String login = space.getLogin();
						String accessLogin = null;
						if (login==null || login.equals("")) {
							accessLogin = portalLogin;
							space.setLogin(accessLogin);
						}
						else accessLogin = login;
					
						// check the {...}
						space.checkPath(person);				

						// check the {...} in the checked attributes
						ArrayList checkedAttributes = config.getCheckedAttributes();
						for (int j=0; j<checkedAttributes.size(); j++) {							
							space.checkAttribute((String)checkedAttributes.get(j), person);							
						}
						
						// we configure the object used by the space to acces the server
						validAccess = space.setServerAccessObject();					
					}
					
				}		
				
				// we check if this space if valid or not
				if (!validAccess) {
					if (log.isDebugEnabled()){
						log.debug("setStaticData"+" :: "+portalLogin+" can not see "+space.getKey());
					}
										
					spaces.remove(i);
					i--;
				}
				
				else {			
					// set for the space, the channel action object used
					boolean wellDone = space.setChannelActionObject(person, spaces, buffer, this.portalLogin, this.userGroups);
					
					if (!wellDone) {
						spaces.remove(i);
						i--;
					}
				}*/
			}				

			
			
			// 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);
			}
		}
		/*catch(ClassNotFoundException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			setStaticDataException = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(IllegalAccessException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			setStaticDataException = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(InstantiationException e) {			
			//this.currentSpace.setWebdavAccessObject(null);		
			setStaticDataException = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}
		catch(MalformedURLException e) {			
			//this.currentSpace.setWebdavAccessObject(null);	
			setStaticDataException = new PropertiesException();
			if (log.isDebugEnabled()){
				log.debug("setStaticData"+" :: "+e);
			}
		}*/		
	}
	
	
	
	/**
	 * Init the actions and server of a space
	 * @param space the space to init
	 * @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) throws PropertiesException, ApplicationException, ChannelException {
		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 attribute = auth.getAttribute();
					String value = auth.getValue();
					
					if (attribute!=null && !attribute.trim().equals("")) {
						Object[] userValues = (Object[])person.getAttributeValues(attribute);						
						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"+" :: "+attribute+" == "+value+" ??? yes");
								}
								else log.debug("initSpace"+" :: "+attribute+" == "+value+" ??? no, "+attribute+" = "+userValue);
							}							
						
						}
						else log.debug("initSpace"+" :: "+attribute+" == "+value+" ??? no, "+attribute+" is null ");
					}
				}					
			}
			else {
				validAccess = true;
			}
			
			// if authorized
			if (validAccess) {
				
				validAccess = false;
			
				// cas authentication mode
				if (space.isCasAuthentication()) {
				
					//TODO validAccess = space.setWebdavAccessObject(davAccessClass, uri, trustedLogin, password);
				}
			
				// trusted or asked authentication mode
				else if (space.isTrustedAuthentication() || space.isAskedAuthentication()) {
				
					// if there is a trusted login
					String login = space.getLogin();
					String accessLogin = null;
					if (login==null || login.equals("")) {
						accessLogin = portalLogin;
						space.setLogin(accessLogin);
					}
					else accessLogin = login;
				
					// check the {...}
					space.checkPath(person);				
	
					// 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");
					// we configure the object used by the space to acces the server
					validAccess = space.setServerAccessObject();
					//System.out.println("apres setServerAccessObject");
				}
				
			}		
			
			// we check if this space if valid or not
			if (!validAccess) {
				if (log.isDebugEnabled()){
					log.debug("initSpace"+" :: "+portalLogin+" can not see "+space.getKey());
				}
				
				if (!space.isPersonnalSpace()) 
					return false;
			}
			
			else {		
				// set for the space, the channel action object used
				//System.out.println("avant setChannelActionObject");
				boolean wellDone = space.setChannelActionObject(person, spaces, buffer, portalLogin, userGroups);
				//System.out.println("apres setChannelActionObject");
				
				if (!wellDone && !space.isPersonnalSpace()) {
					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 {		
		
		// 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;
					}
						
				}
				
			}
		}
		
		
		// Create a new XSLT styling engine		
		XSLT xslt = new XSLT(this);
		

		
		
		//////////////////////////////////////////////////////
		// 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 
		String 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];
				}
			}
		}
		
		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 (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) {
					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;
				}
			}
		}
	}
	
	
	
	
	
	/**
	 * 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");
		
		//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();
		TreeMap[] availableAndUsedSpaces = getAvailableAndUsedSpaces(tool, this.portalLogin, this.userGroups);
		this.currentSpace = setSpacesIntoMenu(this.spaces, this.currentSpace, tool, this.person, this.portalLogin, this.userGroups, availableAndUsedSpaces[0], this.buffer);
			
	}

		
	
	
	
	
	
		
	
	/**************************
	 *  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);
			}
		}
		
	}
	
		

		
	/**************************
	 *   Manage shared spaces
	 **************************/
			
			
	/**
	 * The spaces still in use
	 */
	private TreeMap usedSpaces;
			
	/**
	 * The avalaible spaces
	 */
	private TreeMap availableSpaces;

	
	
	/**
	 * Set the used spaces and the avalaible spaces for this user
	 */
	public static TreeMap[] getAvailableAndUsedSpaces(PersonalizationTool tool, String userPortalLogin, Vector userGroups) throws DataBaseException, PropertiesException, ServerException {

		TreeMap usedSpaces = new TreeMap();
		TreeMap availableSpaces = new TreeMap();

		// we get each space from the preferences user
		Vector idUsedUsers = tool.getKeyOfSpacesFromPreferences(userPortalLogin);
		//System.out.println(idUsedUsers);
			
		// 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();
			if (!idUsedUsers.contains(id)) {
				if (!availableSpaces.containsKey(id))
					availableSpaces.put(id, space);
			}
			else {
				if (!usedSpaces.containsKey(id))
					usedSpaces.put(id, space);
			}
		}
			

		// get each shared 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, false);
			for (int i=0; i<spaces.size(); i++) {
				Space space = (Space)spaces.elementAt(i);
				
				String id = space.getKey();
				if (!idUsedUsers.contains(id)) {
					if (!availableSpaces.containsKey(id))
						availableSpaces.put(id, space);
				}
				else {
					if (!usedSpaces.containsKey(id))
						usedSpaces.put(id, space);
				}
					
			}
		}
		
		TreeMap[] result = new TreeMap[2];
		result[0] = usedSpaces;
		result[1] = availableSpaces;
		return result;
	}
		

	/**
	 * 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, TreeMap usedSpaces, BufferAction buffer) throws DataBaseException, ChannelException {			
		
		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);
			
			if (s.isPersonnalSpace() && !usedSpaces.containsKey(s.getKey())) {
				
				// 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.values().iterator();
		while(used.hasNext()) {
			Space s = (Space)used.next();
			
			if (!spaces.contains(s)) {
				// add into the user preferences
				String spaceId = s.getKey();
				tool.addStorageUsersPreferences(spaceId, userPortalLogin);
				
				// add into the used list
				spaces.add(s);			
			}
			
		}
		
		// 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);
				
				/*
				// 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
	 * @throws DataBaseException
	 */
	private StringBuffer renderXmlManageSharedSpaces(ChannelRuntimeData runtimeData) throws ChannelException, PropertiesException, CancelException, DataBaseException, ServerException {
		
		// if it is the first call
		if (usedSpaces == null && availableSpaces == null) {
			TreeMap[] availableAndUsedSpaces = getAvailableAndUsedSpaces(new PersonalizationTool(), portalLogin, userGroups);
			usedSpaces = availableAndUsedSpaces[0];
			availableSpaces = availableAndUsedSpaces[1];
		}
		
		// if cancel
		String action = runtimeData.getParameter("action");
		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) {
			renderXmlManageSharedSpacesAdd(runtimeData);
		}
		
		// if delete
		String delete = runtimeData.getParameter("delete");
		if (delete != null) {
			renderXmlManageSharedSpacesDelete(runtimeData);
		}
		
		// generate the xml
		return renderXmlManageSharedSpacesGetXmlForRender(runtimeData);
	}
	
	
	
	
	
	/**
	 * 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();
		
		xml.append("<used>");
		xml.append(renderXmlManageSharedSpacesGetXmlForRenderOnlySpaces(usedSpaces));		
		xml.append("</used>");
		
		xml.append("<available>");		
		xml.append(renderXmlManageSharedSpacesGetXmlForRenderOnlySpaces(availableSpaces));
		xml.append("</available>");
		
		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(TreeMap spaces) throws ServerException, PropertiesException  {
		
		StringBuffer xmlReadOnly = new StringBuffer();
		StringBuffer xmlWrite = new StringBuffer();
		StringBuffer xmlManage = new StringBuffer();
		
		Iterator used = spaces.values().iterator();
		while (used.hasNext()) {			
			Space space = (Space)used.next();			
			String target = space.getCurrentViewer().getDisplayName();
			
			if (!space.getCurrentViewer().isWriting()) {
				xmlReadOnly.append("<space key=\""+space.getKey()+"\" writing=\""+space.getCurrentViewer().isWriting()+"\" from=\""+(new UserForPersonalization(space.getCurrentViewer().getFromKey()).getDisplayName())+"\" target=\""+target+"\">"+space.getLabel()+"</space>");
			}
			else {
				if (!space.isSharing()) {
					xmlWrite.append("<space key=\""+space.getKey()+"\" writing=\""+space.getCurrentViewer().isWriting()+"\" from=\""+(new UserForPersonalization(space.getCurrentViewer().getFromKey()).getDisplayName())+"\" target=\""+target+"\">"+space.getLabel()+"</space>");
				}
				else {
					xmlManage.append("<space key=\""+space.getKey()+"\" writing=\""+space.getCurrentViewer().isWriting()+"\" from=\""+(new UserForPersonalization(space.getCurrentViewer().getFromKey()).getDisplayName())+"\" target=\""+target+"\">"+space.getLabel()+"</space>");
				}
			}
		}				
		
		StringBuffer xml = new StringBuffer();
		xml.append("<read_only>");
		xml.append(xmlReadOnly);
		xml.append("</read_only>");
		xml.append("<read_and_write>");
		xml.append(xmlWrite);
		xml.append("</read_and_write>");
		xml.append("<read_and_write_and_manage>");
		xml.append(xmlManage);
		xml.append("</read_and_write_and_manage>");
		return xml;
	}
	
	
	
	/**
	 * Generate the XML when we click on "cancel" when we manage the shared spaces
	 * @throws CancelException
	 */
	private void renderXmlManageSharedSpacesCancel() throws CancelException {
		usedSpaces = null;
		availableSpaces = null;
		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 DataBaseException, ChannelException {
		this.currentSpace = setSpacesIntoMenu(this.spaces, this.currentSpace, new PersonalizationTool(), this.person, this.portalLogin, this.userGroups, usedSpaces, this.buffer);
		
		usedSpaces = null;
		availableSpaces = null;
		
		stylesheet = new StringBuffer("CStockage");
		if (setStaticDataException instanceof AnyVisibleSpaceException) {
			setStaticDataException = null;
		}
		
		if (this.currentSpace!=null) {
			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  {
		
		/*Iterator iter = usedSpaces.values().iterator();
		 while(iter.hasNext()) {
		 System.out.println(iter.next());
		 }*/
		
		
		// we check the selected spaces, remove them from "availableSpaces" and add to "usedSpaces"
		String[] available = runtimeData.getParameterValues("available");
		for (int i=0; available!=null && i<available.length; i++) {
			String spaceId = available[i];
			Space space = (Space)availableSpaces.remove(spaceId);
			usedSpaces.put(spaceId, space);
		}		
		
		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 selected spaces, remove them from "usedSpaces" and add to "availableSpaces"
		String[] used = runtimeData.getParameterValues("used");
		for (int i=0; used!=null && i<used.length; i++) {
			String spaceId = used[i];
			Space space = (Space)usedSpaces.remove(spaceId);
			availableSpaces.put(spaceId, space);
		}	
		
		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(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*****************************/
	/***************************************************************************/
}
