/**
 * @author Thomas Bellembois
 * @version
 * 
 * Creation date : 8 nov. 2005
 * Last modification :
 * 
 * spaceCreation
 *   -path=[pathToCreateTheFolder]
 *    | -name=[folderName]
 * ou |_-ldap=[ldapFilter] -ldapAttribute=[uniqueLdapAttributeToRetrieve]
 *  (-regexp=[regexp] -regexpSeparator=[regexpSeparator])
 *  (-templateFile=[pathToTemplateFile])
 **/
package org.esupportail.injac.webdavServer.esupWDServerManager.core.spaceManager;

import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.webdav.lib.Ace;
import org.apache.webdav.lib.Privilege;
import org.apache.webdav.lib.PropertyName;
import org.apache.webdav.lib.WebdavResource;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import com.novell.ldap.LDAPException;

import fr.univrennes1.cri.util.exceptions.ConfigException;
import fr.univrennes1.cri.util.exceptions.WrongPathException;
import fr.univrennes1.cri.util.ldapUtils.LDAPUtils;
import fr.univrennes1.cri.util.ldapUtils.ESUP_LDAPAttribute;
import fr.univrennes1.cri.util.ldapUtils.ESUP_LDAPEntry;

public class SpaceManager {
		
	// Constants
	//subjectUri="all" actionUri="all" negative="false"
	//name="owner" namespace="DAV:" value="test" type=""
	public static final String TAG_PROPERTIES = "properties";
	public static final String TAG_PROPERTY = "property";
	public static final String TAG_PERMISSIONS = "permissions";
	public static final String TAG_PERMISSION = "permission";
	
	public static final String PERMISSION_READ = "READ";
	public static final String PERMISSION_WRITE = "WRITE";
	public static final String PERMISSION_READ_ACL = "READ_ACL";
	public static final String PERMISSION_WRITE_ACL = "WRITE_ACL";
	public static final String PERMISSION_ALL = "ALL";
	
	public static final String PROPERTY_OWNER = "owner";
	
	public static final String PATTERNFILE_REPLACEMENTSTRING = "{0}";
	
	// WebDAV parameters
	private HttpURL httpUrl;
	private WebdavResource webDavResource;
	private String context;
	
	// Web service parameters
	private static Call call;
	
	// LDAP parameters
	private String ldapBaseDN;
	private String ldapURL;
	private String ldapPort;
	private String ldapScope;
	private String ldapPrincipal;
	private String ldapCredential;
	private String ldapMaxResults;
	
	// Other parameters
	private Hashtable existingPaths; // to store existing path
	
	private boolean connected;
	private static Log log;
	
	public SpaceManager() {
		log = LogFactory.getLog(getClass().getName());
		existingPaths = new Hashtable();
		connected = false;
	}// SpaceManager
	
	/**
	 * Checks if the WebDAV ressource exists
	 * @param webDavResource
	 * @param path syntax: /{context}/path - exemple: /slide/files/myRessource
	 * @return true if the path exists, else false
	 */
	private boolean pathExist(WebdavResource webDavResource, String path){
		boolean exist = false;
		
		if (existingPaths.get(path) != null && existingPaths.get(path) != "") {
			log.debug("pathExist:path="+path+" found in the cache");
			return true;
		}
		else {
			try {
				webDavResource.setPath(path);
				exist = webDavResource.exists();
			} catch (HttpException httpException) {
				log.debug("pathExist:path="+path+" > false");
				return false;
			} catch (IOException ioException) {
				log.debug("pathExist:"+ioException.toString());
			}
			log.debug("pathExist:path="+path+" > "+exist);
			if (exist) existingPaths.put(path, path);
			return exist;
		}// else if (existingPaths.get(path) != null && existingPaths.get(path) != "")
	}// isExist
	
	public boolean connect(String webdavServerUrl, String userName, String password) throws HttpException, IOException, ServiceException {
		return connect(webdavServerUrl, userName, password, null, null, null, null, null, null, null, null);
	}// connect
	
	public boolean connect(String webdavServerUrl, String userName, String password,
			String ldapURL, String ldapPort, String ldapScope, String ldapBaseDN,
			String ldapPrincipal, String ldapCredential, String ldapMaxResults, String webServiceURL) throws HttpException, IOException, ServiceException {
		log.info("connect:webdavServerUrl="+webdavServerUrl+" userName="+userName);
		
		if (webdavServerUrl == null) {
			log.error("connect:webdavServerUrl can not be null");
			return false;
		}
		if (userName == null) userName = "";
		if (password == null) password = "";
		
		this.ldapBaseDN = ldapBaseDN;
		this.ldapCredential = ldapCredential;
		this.ldapMaxResults = ldapMaxResults;
		this.ldapPort = ldapPort;
		this.ldapPrincipal = ldapPrincipal;
		this.ldapScope = ldapScope;
		this.ldapURL = ldapURL;
		
		// connecting to the WebDAV server
		log.info("connect:connecting to the WebDAV server...");
		httpUrl = new HttpURL(webdavServerUrl+"/");
		httpUrl.setUserinfo(userName, password);
		context = httpUrl.getCurrentHierPath(); // /slide for example
		if (context.equalsIgnoreCase("/")) context = "";
		log.info("connect:context="+context);
		webDavResource = new WebdavResource(httpUrl);
		
		boolean webDavConnected = webDavResource.getStatusCode() != 0;
		if (webDavConnected) log.info("connect:connected to the WebDAV server");
		else log.error("connect:connection to the WebDAV server failed !");
		
		boolean webServiceConnected = false;
		
		// connecting to the Web service
		if (webServiceURL != null && !webServiceURL.equals("")) {
			log.info("connect:connecting to the Web service...");
			String endpoint = webServiceURL;
			
			Service service = new Service();
			call = (Call) service.createCall();
						
			call.setUsername(userName);
			call.setPassword(password);
			call.setMaintainSession(true);
			call.setTargetEndpointAddress( new java.net.URL(endpoint) );
			
			String tmpResult = (String)call.invoke(new QName("init"), new Object[] { "none" });
			webServiceConnected = Boolean.valueOf(tmpResult).booleanValue();
			if (webServiceConnected) log.info("connect:connected to the Web service");
			else log.error("connect:connection to the Web service failed !");
		}// if (webServiceURL != null && !webServiceURL.equals(""))
		else {
			webServiceConnected = true;
		}// else (webServiceURL != null && !webServiceURL.equals(""))
		
		connected = webDavConnected && webServiceConnected;
		
		log.info("connect:success=true");
		return connected;
	}// connect

	public boolean createSpace(String path, String spaceName, String xmlFilePath, String forceSetProperties) throws HttpException, ConfigurationException, WrongPathException, LDAPException, IOException, ConfigException {
		return createSpace(path, spaceName, null, null, null, null, xmlFilePath, forceSetProperties);
	}
	
	public boolean createSpace(String path, String spaceName, String regexp, String regexpSeparator, String xmlFilePath, String forceSetProperties) throws HttpException, ConfigurationException, WrongPathException, LDAPException, IOException, ConfigException {
		return createSpace(path, spaceName, null, null, regexp, regexpSeparator, xmlFilePath, forceSetProperties);
	}
	
	public boolean createSpace(String path, String LDAPFilter, String LDAPAttribute, String xmlFilePath, String forceSetProperties) throws HttpException, ConfigurationException, WrongPathException, LDAPException, IOException, ConfigException {
		return createSpace(path, null, LDAPFilter, LDAPAttribute, null, null, xmlFilePath, forceSetProperties);
	}
	
	public boolean createSpace(String path, String LDAPFilter, String LDAPAttribute, String regexp, String regexpSeparator, String xmlFilePath, String forceSetProperties) throws HttpException, ConfigurationException, WrongPathException, LDAPException, IOException, ConfigException {
		return createSpace(path, null, LDAPFilter, LDAPAttribute, regexp, regexpSeparator, xmlFilePath, forceSetProperties);
	}
	
	public boolean createSpace(String path, String spaceName, String LDAPFilter, String LDAPAttribute, String regexp, String regexpSeparator, String xmlFilePath, String _forceSetProperties) throws WrongPathException, LDAPException, HttpException, ConfigurationException, IOException, ConfigException {
		
		log.debug("createSpace:path="+path+" spaceName="+spaceName+" LDAPFilter="+LDAPFilter+" LDAPAttribute="+LDAPAttribute+" regexp="+regexp+" regexpSeparator="+regexpSeparator+" xmlFilePath="+xmlFilePath+" _forceSetProperties="+_forceSetProperties);
		
		if (!connected) {
			log.error("createSpace:Call the connect() method first !");
			return false;
		}// if (!connected)
		
		/////////////////////////////
		// Doing some initialisations
		//
		if (_forceSetProperties == null || _forceSetProperties.equalsIgnoreCase("")) _forceSetProperties = "false";
		
		boolean success = true;
		boolean forceSetProperties = Boolean.valueOf(_forceSetProperties).booleanValue();
		
		String endPath = null; // = spaceName or LDAP result entry - and can be modified by the regexp 
		String endPathSave = null; // we need to save it before it is modified by the regepx
		
		//////////////////////////
		// Retrieving LDAP entries
		//
		if (LDAPFilter != null && LDAPAttribute != null && !LDAPAttribute.equals("")) {
			endPath = LDAPFilter;
			
			LDAPUtils ldapUtils = new LDAPUtils();
			String[] attributesToRetrieve = {LDAPAttribute};
			log.info("createSpace:connecting to the LDAP...");
			if (ldapUtils.connect(ldapURL, ldapPort, ldapPrincipal, ldapCredential)) {
				log.info("createSpace:LDAP connexion success");
			}// if (ldapUtils.connect
			else {
				log.error("createSpace:LDAP connexion failed !");
			}// else (ldapUtils.connect
			log.info("createSpace:requesting the LDAP...");
			
			Enumeration LDAPResult = (ldapUtils.getEntries(LDAPFilter, ldapBaseDN, ldapMaxResults, attributesToRetrieve, ldapScope)).elements();
			
			if (LDAPResult == null || !LDAPResult.hasMoreElements()) { 
				log.error("createSpace:no LDAP entries matching the given filter !");
				throw new ConfigException("SpaceManager", "createSpace", "LDAP result null");
			}// if (LDAPResult == null)

			while (LDAPResult.hasMoreElements()) {
				ESUP_LDAPEntry ldapEntry = (ESUP_LDAPEntry) LDAPResult.nextElement();
				ESUP_LDAPAttribute ldapAttribute = ldapEntry.getAttributes().getLdapAttribute(LDAPAttribute);
				boolean isMulti = ldapAttribute.isMulti();
				if (isMulti) {
					log.error("createSpace:the given attribute has more than one value !");
					throw new ConfigException("SpaceManager", "createSpace", "LDAP attribute with several values");
				}// if (isMulti)
				endPath = ldapAttribute.getValue();
				endPathSave = endPath; // saving the LDAP result (needed later) given that endPath is going to be modified
				log.debug("createSpace:endPath="+endPath);
				if (endPath != null && !endPath.equals("")) {
					log.debug("createSpace:creating space "+endPath);
					success = success & createSpace(path, endPath, regexp, regexpSeparator, xmlFilePath, _forceSetProperties);
				}// if (endPath != null && !endPath.equals(""))
				else {
					log.error("createSpace:endPath=null !");
				}// // if (endPath != null && !endPath.equals(""))
				
			}// while (LDAPResult.hasMoreElements())
		}// if (LDAPFilter != null && LDAPAttribute != null && !LDAPAttribute.equals(""))
		else {
			endPath = spaceName;
			endPathSave = endPath; // saving the LDAP result (needed later) given that endPath is going to be modified
			
			////////////////////////////////////
			// Building the path with the regexp
			//
			if (regexp != null && !regexp.equals("")) {
				//building the sophisticated path
				log.debug("createSpace:building end path with regexp...");
				if (regexp!=null) {
					
					String[] regexps = null;
					if (regexpSeparator!=null) {
						regexps = regexp.split(regexpSeparator);
					}// if (regexpSeparator!=null)
					else {
						regexps = new String[1];
						regexps[0] = regexp;
					}// else (regexpSeparator!=null)
					
					StringBuffer buildPath = new StringBuffer();
					
					for (int i = 0; i < regexps.length; i++) {
						Pattern p = Pattern.compile(regexps[i], Pattern.CASE_INSENSITIVE);
						Matcher m = p.matcher(endPath);
						buildPath.append(m.replaceAll("$1")+"/");
					}// for (int i = 0; i < regexps.length; i++)
					
					endPath = buildPath.toString();
					// cleaning the endPath
					if (endPath.startsWith("/"))
						endPath = endPath.substring(1, endPath.length());		
					if (endPath.endsWith("/"))
						endPath = endPath.substring(0, endPath.length()-1);
					log.debug("createSpace:endPath="+endPath);
					regexp = null;
					regexpSeparator = null;
				}// if (regexp!=null)
			}// if (regexp != null && !regexp.equals(""))
			
			/////////////////////////////
			// Finally creating the space
			//
			//building the full path
			String fullSpacePath = context+path+"/"+endPath;
			log.debug("createSpace:fullSpacePath="+fullSpacePath);
			
			//checking if the path already exist
			if (pathExist(webDavResource,fullSpacePath)) {
				log.error("createSpace:fullSpacePath "+fullSpacePath+" already exists!");
				if (forceSetProperties && xmlFilePath != null && !xmlFilePath.equalsIgnoreCase("")) {
					success = success & setSpaceProperties(fullSpacePath.substring(context.length()), xmlFilePath, endPathSave);
				}// if (forceSetProperties)
			}// if
			else {
				//checking if each directory of the path exists and if not creating it
				log.debug("createSpace:checking each directory of the path");
				//..spliting the full path
				String[] splitPath = fullSpacePath.substring(1).split("/");
				String pathToCheck = "";
				for (int i = 0; i < splitPath.length; i++) {
					pathToCheck = pathToCheck+"/"+splitPath[i];
					log.debug("createSpace:pathToCheck="+pathToCheck);
					if (pathExist(webDavResource,pathToCheck) || pathToCheck.equalsIgnoreCase(context)){
						log.debug("createSpace:pathToCheck "+pathToCheck+" already exists or is the root");
					}// if (pathExist(webDavResource,pathToCheck)...
					else {
						log.debug("createSpace:pathToCheck "+pathToCheck+" does not exist");
						log.info("createSpace:creating "+pathToCheck);
						boolean mkcolSuccess = webDavResource.mkcolMethod(pathToCheck); //TODO traiter le retour de la fonction
						if (mkcolSuccess) {
							existingPaths.put(pathToCheck, pathToCheck); // done by the pathExist function but improve performance
							log.info("createSpace:space "+pathToCheck+" created successfully");
						}// if (mkcolSuccess)
						else {
							log.error("createSpace:space "+pathToCheck+" >>>creation failed !<<<");
						}// else (mkcolSuccess)
						success = success && mkcolSuccess;
						if (i==splitPath.length-1 && xmlFilePath != null && !xmlFilePath.equalsIgnoreCase("")) {
							success = success & setSpaceProperties(pathToCheck.substring(context.length()), xmlFilePath, endPathSave);
						}// if (i==splitPath.length-1)
					}// else (pathExist(webDavResource,pathToCheck)...
				}	
			}//else (pathExist(webDavResource,fullSpacePath))
			log.debug("createSpace:success="+success);
		}// if (! (LDAPFilter != null && LDAPAttribute != null && !LDAPAttribute.equals("")))

//DEPRECATED
//		//////////////////////////////////////////////////
//		// We still need to set properties and permissions
//		//
//		if (xmlFilePath != null && !xmlFilePath.equals("")) { //TODO
//			log.info("createSpace:setting properties and permissions...");
//			Enumeration createdSpacesPath = createdSpaces.keys();
//			while (createdSpacesPath.hasMoreElements()) {
//				String createdSpacePath = (String) createdSpacesPath.nextElement();
//				String createdSpaceOriginalName = (String) createdSpaces.get(createdSpacePath);
//				createdSpacePath = createdSpacePath.substring(context.length()); // we need to remove the context - required by the setSpaceProperties function
//				log.info("createSpace:processing "+createdSpaceOriginalName+" space");
//				success = success & setSpaceProperties(createdSpacePath, xmlFilePath, createdSpaceOriginalName);
//			}// while (createdSpacesPath.hasMoreElements())
//		}// if (xmlFilePath != null && !xmlFilePath.equals(""))
//		else {
//			log.info("createSpace:no template file given for this space(s)");
//		}// else (xmlFilePath != null && !xmlFilePath.equals(""))
		
		return success;
	}// createSpace
	
	public boolean setSpaceProperties(String spacePath, String xmlFilePath, String replacementString) throws ConfigurationException, HttpException, IOException, ConfigException {
		
		log.debug("setSpaceProperties:spacePath="+spacePath+" xmlFilePath="+xmlFilePath+" replacementString="+replacementString);
		
		// doing some initialisations
		boolean propertiesSetSuccefully = false;
		if (xmlFilePath == null || xmlFilePath.equalsIgnoreCase("")) throw new ConfigException("SpaceManager", "setSpaceProperties", "xmlFilePath can not be null");
		
		String fullSpacePath = context+spacePath;
		
		XMLConfiguration xmlConfiguration = new XMLConfiguration(xmlFilePath);
		xmlConfiguration.load();
		
		/////////////////////////
		// Setting the properties
		//
		//log.debug(xmlConfiguration.getString("properties.property(0).[@name]"));
		// the following code is used instead of the xmlConfiguration.getMaxIndex(TAG_PROPERTY) function that does not work
		Document document = xmlConfiguration.getDocument();
		NodeList nodeList = document.getElementsByTagName(TAG_PROPERTY);
		int propertyNumber = nodeList.getLength();
		log.debug("setSpaceProperties:number of "+TAG_PROPERTY+" = "+propertyNumber);
		
		Hashtable propertiesTable = new Hashtable();
		String _propertyName;
		String _propertyNamespace;
		String _propertyValue;
		String _propertyType;
		for (int i = 0; i < propertyNumber; i++) {
			_propertyName = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@name]");
			_propertyNamespace = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@namespace]");
			_propertyValue = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@value]");
			_propertyType = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@type]");
			log.debug("setSpaceProperties:"+TAG_PROPERTY+" "+i+":"+_propertyName+" "+_propertyNamespace+" "+_propertyValue+" "+_propertyType);
			
			// Here we check if there is the PATTERNFILE_REPLACEMENTSTRING in one of the _property* variable
			boolean changePropertyName = (_propertyName != null && _propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			boolean changePropertyNamespace = (_propertyNamespace != null && _propertyNamespace.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			boolean changePropertyValue = (_propertyValue != null && _propertyValue.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			boolean changePropertyType = (_propertyType != null && _propertyType.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			
			String _newPropertyName = _propertyName;
			String _newPropertyNamespace = _propertyNamespace;
			String _newPropertyValue = _propertyValue ;
			String _newPropertyType = _propertyType;
			if (changePropertyName || changePropertyNamespace || changePropertyValue || changePropertyType) {
				
				log.debug("setSpaceProperties:"+PATTERNFILE_REPLACEMENTSTRING+" found - replacing by "+replacementString);
				if (changePropertyName ) _newPropertyName = StringUtils.replace(_propertyName, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				if (changePropertyNamespace ) _newPropertyNamespace = StringUtils.replace(_propertyNamespace, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				if (changePropertyValue ) _newPropertyValue = StringUtils.replace(_propertyValue, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				if (changePropertyType ) _newPropertyType = StringUtils.replace(_propertyType, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				log.debug("setSpaceProperties:"+TAG_PROPERTY+" "+i+":"+_newPropertyName+" "+_newPropertyNamespace+" "+_newPropertyValue+" "+_newPropertyType);
				
			}// if (_propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING)...
			
			// if the property is a live property the calling the setSpaceLiveMetadata function
			if (_newPropertyName.equalsIgnoreCase(PROPERTY_OWNER)) {
				log.info("setSpaceProperties:setting live properties for "+spacePath);
				log.debug("setSpaceProperties:adding LIVE property "+i+" to "+spacePath);
				setSpaceLiveMetadata(spacePath, _newPropertyName, _newPropertyValue); // spacePath and not fullSpacePath - required by the setSpaceLiveMetadata funtion
			} // if (_newPropertyName.equalsIgnoreCase(PROPERTY_OWNER))
			else {
				// TODO property type currently not used
				log.debug("setSpaceProperties:adding property "+i+" to "+spacePath);
				propertiesTable.put(new PropertyName(_newPropertyNamespace, _newPropertyName), _newPropertyValue);
			}// if (_newPropertyName.equalsIgnoreCase(PROPERTY_OWNER))
				
		}// for (int i = 0; i < propertyNumber; i++)
		if (propertiesTable.size() != 0) { // the properties table can be empty if all of the properties are live properties
			log.info("setSpaceProperties:setting properties for "+spacePath);
			propertiesSetSuccefully = setSpaceMetadata(fullSpacePath, propertiesTable);
		}// if (propertiesTable.size() != 0)
		
		//////////////////////////
		// Setting the permissions
		//		
		//document = xmlConfiguration.getDocument();
		nodeList = document.getElementsByTagName(TAG_PERMISSION);
		int permissionNumber = nodeList.getLength();
		log.debug("setSpaceProperties:number of "+TAG_PERMISSION+" = "+permissionNumber);
		
		Ace[] permissionsArray = new Ace[permissionNumber];
		String _permissionsSubjectUri;
		String _permissionsActionUri;
		String _permissionsNegative;
		for (int i = 0; i < permissionNumber; i++) {
			_permissionsSubjectUri = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@subjectUri]");
			_permissionsActionUri = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@actionUri]");
			_permissionsNegative = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@negative]");
			log.debug("setSpaceProperties:"+TAG_PERMISSION+" "+i+":"+_permissionsSubjectUri+" "+_permissionsActionUri+" "+_permissionsNegative);
			
			// Here we check if there is the PATTERNFILE_REPLACEMENTSTRING in one of the _property* variable
			boolean changePermissionsSubjectUri = (_permissionsSubjectUri != null && _permissionsSubjectUri.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			boolean changePermissionsActionUri = (_permissionsActionUri != null && _permissionsActionUri.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
			boolean changePermissionsNegative = (_permissionsNegative != null && _permissionsNegative.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
						
			String _newPermissionsSubjectUri = _permissionsSubjectUri;
			String _newPermissionsActionUri = _permissionsActionUri;
			String _newPermissionsNegative = _permissionsNegative ;
			
			if (changePermissionsSubjectUri || changePermissionsActionUri || changePermissionsNegative) {
				
				log.debug("setSpaceProperties:"+PATTERNFILE_REPLACEMENTSTRING+" found - replacing by "+replacementString);
				
				if (changePermissionsSubjectUri ) _newPermissionsSubjectUri = StringUtils.replace(_permissionsSubjectUri, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				if (changePermissionsActionUri ) _newPermissionsActionUri = StringUtils.replace(_permissionsActionUri, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				if (changePermissionsNegative ) _newPermissionsNegative = StringUtils.replace(_permissionsNegative, PATTERNFILE_REPLACEMENTSTRING, replacementString);
				log.debug("setSpaceProperties:"+TAG_PERMISSION+" "+i+":"+_newPermissionsSubjectUri+" "+_newPermissionsActionUri+" "+_newPermissionsNegative);
				
			}// if (_propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING)...
						
			// Building the new Ace
			Ace _ace = new Ace(_newPermissionsSubjectUri);
			_ace.setInheritable(true);
			_ace.setNegative(Boolean.valueOf(_newPermissionsNegative).booleanValue());
			// Building the Privilege
			if (_newPermissionsActionUri.equalsIgnoreCase(PERMISSION_READ)){
				log.debug("setSpaceProperties:permission="+PERMISSION_READ);
				_ace.addPrivilege(Privilege.READ);
			}
			else if (_newPermissionsActionUri.equalsIgnoreCase(PERMISSION_WRITE)){
				log.debug("setSpaceProperties:permission="+PERMISSION_WRITE);
				_ace.addPrivilege(Privilege.WRITE);
			}
			else if (_newPermissionsActionUri.equalsIgnoreCase(PERMISSION_READ_ACL)){
				log.debug("setSpaceProperties:permission="+PERMISSION_READ_ACL);
				_ace.addPrivilege(Privilege.READ_ACL);
			}
			else if (_newPermissionsActionUri.equalsIgnoreCase(PERMISSION_WRITE_ACL)){
				log.debug("setSpaceProperties:permission="+PERMISSION_WRITE_ACL);
				_ace.addPrivilege(Privilege.WRITE_ACL);
			}
			else if (_newPermissionsActionUri.equalsIgnoreCase(PERMISSION_ALL)){
				log.debug("setSpaceProperties:permission="+PERMISSION_ALL);
				_ace.addPrivilege(Privilege.ALL);
			}
			else {
				log.error("setSpaceProperties:Wrong Permission : "+_newPermissionsActionUri+" !");
				throw new ConfigException("SpaceManager", "setSpaceProperties", "Wrong Permission : "+_newPermissionsActionUri+" !");
			}
			permissionsArray[i] = _ace;
		}// for (int i = 0; i < propertyNumber; i++)
		if (permissionNumber > 0) {
			log.info("setSpaceProperties:setting permissions for "+spacePath);
			propertiesSetSuccefully = propertiesSetSuccefully & setSpaceACL(fullSpacePath, permissionsArray);
		}// if (permissionNumber > 0)
		
		return propertiesSetSuccefully;
		
	}// setSpaceProperties
	
	/////////////////////////////////////////////
	// Old code but could be usefull in the futur
	//
//	public boolean setSpaceProperties(String spacePath, String xmlFilePath, String[] replacementStrings) throws ConfigurationException, HttpException, IOException, ConfigException {
//		
//		log.debug("setSpaceProperties:spacePath="+spacePath+" xmlFilePath="+xmlFilePath);
//		
//		boolean propertiesSetSuccefully = false;
//		
//		String fullSpacePath = context+spacePath;
//		
//		XMLConfiguration xmlConfiguration = new XMLConfiguration(xmlFilePath);
//		xmlConfiguration.load();
//		
//		/////////////////////////
//		// Setting the properties
//		//
//		//log.debug(xmlConfiguration.getString("properties.property(0).[@name]"));
//		// the following code is used instead of the xmlConfiguration.getMaxIndex(TAG_PROPERTY) function that does not work
//		Document document = xmlConfiguration.getDocument();
//		NodeList nodeList = document.getElementsByTagName(TAG_PROPERTY);
//		int propertyNumber = nodeList.getLength();
//		log.debug("setSpaceProperties:number of "+TAG_PROPERTY+" = "+propertyNumber);
//		
//		Hashtable propertiesTable = new Hashtable();
//		String _propertyName;
//		String _propertyNamespace;
//		String _propertyValue;
//		String _propertyType;
//		for (int i = 0; i < propertyNumber; i++) {
//			_propertyName = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@name]");
//			_propertyNamespace = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@namespace]");
//			_propertyValue = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@value]");
//			_propertyType = xmlConfiguration.getString(TAG_PROPERTIES+"."+TAG_PROPERTY+"("+i+").[@type]");
//			log.debug("setSpaceProperties:TAG_PROPERTY "+i);
//			log.debug(_propertyName+" "+_propertyNamespace+" "+_propertyValue+" "+_propertyType);
//			
//			// Here we check if there is the PATTERNFILE_REPLACEMENTSTRING in one of the _property* variable
//			boolean changePropertyName = (_propertyName != null && _propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
//			boolean changePropertyNamespace = (_propertyNamespace != null && _propertyNamespace.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
//			boolean changePropertyValue = (_propertyValue != null && _propertyValue.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
//			boolean changePropertyType = (_propertyType != null && _propertyType.indexOf(PATTERNFILE_REPLACEMENTSTRING) != -1);
//			
//			if (changePropertyName || changePropertyNamespace || changePropertyValue || changePropertyType) {
//				
//				log.debug("setSpaceProperties:"+PATTERNFILE_REPLACEMENTSTRING+" found - replacing...");
//				String _newPropertyName = _propertyName;
//				String _newPropertyNamespace = _propertyNamespace;
//				String _newPropertyValue = _propertyValue ;
//				String _newPropertyType = _propertyType;
//				
//				for (int j = 0; j < replacementStrings.length; j++) {
//					if (changePropertyName ) _newPropertyName = StringUtils.replace(_propertyName, PATTERNFILE_REPLACEMENTSTRING, replacementStrings[j]);
//					if (changePropertyNamespace ) _newPropertyNamespace = StringUtils.replace(_propertyNamespace, PATTERNFILE_REPLACEMENTSTRING, replacementStrings[j]);
//					if (changePropertyValue ) _newPropertyValue = StringUtils.replace(_propertyValue, PATTERNFILE_REPLACEMENTSTRING, replacementStrings[j]);
//					if (changePropertyType ) _newPropertyType = StringUtils.replace(_propertyType, PATTERNFILE_REPLACEMENTSTRING, replacementStrings[j]);
//					
//					// TODO property type currently not used
//					log.debug("setSpaceProperties:adding property "+_newPropertyName+" "+_newPropertyNamespace+" "+_newPropertyValue);
//					propertiesTable.put(new PropertyName(_newPropertyNamespace, _newPropertyName), _newPropertyValue);
//				}// for (int j = 0; j < replacementStrings.length; j++)
//				
//			}// if (_propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING)...
//			else {
//				// TODO property type currently not used
//				log.debug("setSpaceProperties:adding property "+_propertyName+" "+_propertyNamespace+" "+_propertyValue);
//				propertiesTable.put(new PropertyName(_propertyNamespace, _propertyName), _propertyValue);
//			}// else (_propertyName.indexOf(PATTERNFILE_REPLACEMENTSTRING)...
//		
//		}// for (int i = 0; i < propertyNumber; i++)
//		log.debug("setSpaceProperties:setting properties for "+spacePath+"...");
//		propertiesSetSuccefully = setSpaceMetadata(fullSpacePath, propertiesTable);
//		
//		//////////////////////////
//		// Setting the permissions
//		//		
//		//document = xmlConfiguration.getDocument();
//		nodeList = document.getElementsByTagName(TAG_PERMISSION);
//		int permissionNumber = nodeList.getLength();
//		log.debug("setSpaceProperties:number of "+TAG_PERMISSION+" = "+permissionNumber);
//		
//		Ace[] permissionsArray = new Ace[permissionNumber];
//		String _permissionsSubjectUri;
//		String _permissionsActionUri;
//		String _permissionsNegative;
//		for (int i = 0; i < permissionNumber; i++) {
//			_permissionsSubjectUri = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@subjectUri]");
//			_permissionsActionUri = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@actionUri]");
//			_permissionsNegative = xmlConfiguration.getString(TAG_PERMISSIONS+"."+TAG_PERMISSION+"("+i+").[@negative]");
//			log.debug("setSpaceProperties:TAG_PROPERTY "+i);
//			log.debug(_permissionsSubjectUri+" "+_permissionsActionUri+" "+_permissionsNegative);
//			
//			// Building the new Ace
//			Ace _ace = new Ace(_permissionsSubjectUri);
//			_ace.setInheritable(true);
//			_ace.setNegative(Boolean.valueOf(_permissionsNegative).booleanValue());
//			// Building the Privilege
//			if (_permissionsActionUri.equalsIgnoreCase(PERMISSION_READ)){
//				log.debug("setSpaceProperties:permission="+PERMISSION_READ);
//				_ace.addPrivilege(Privilege.READ);
//			}
//			else if (_permissionsActionUri.equalsIgnoreCase(PERMISSION_WRITE)){
//				log.debug("setSpaceProperties:permission="+PERMISSION_WRITE);
//				_ace.addPrivilege(Privilege.WRITE);
//			}
//			else if (_permissionsActionUri.equalsIgnoreCase(PERMISSION_READ_ACL)){
//				log.debug("setSpaceProperties:permission="+PERMISSION_READ_ACL);
//				_ace.addPrivilege(Privilege.READ_ACL);
//			}
//			else if (_permissionsActionUri.equalsIgnoreCase(PERMISSION_WRITE_ACL)){
//				log.debug("setSpaceProperties:permission="+PERMISSION_WRITE_ACL);
//				_ace.addPrivilege(Privilege.WRITE_ACL);
//			}
//			else if (_permissionsActionUri.equalsIgnoreCase(PERMISSION_ALL)){
//				log.debug("setSpaceProperties:permission="+PERMISSION_ALL);
//				_ace.addPrivilege(Privilege.ALL);
//			}
//			else {
//				log.error("setSpaceProperties:Wrong Permission : "+_permissionsActionUri+" !");
//				throw new ConfigException("SpaceManager", "setSpaceProperties", "Wrong Permission : "+_permissionsActionUri+" !");
//			}
//			permissionsArray[i] = _ace;
//		}// for (int i = 0; i < propertyNumber; i++)
//		log.debug("setSpaceProperties:setting permissions for "+spacePath+"...");
//		propertiesSetSuccefully = propertiesSetSuccefully && setSpaceACL(fullSpacePath, permissionsArray);
//		
//		return propertiesSetSuccefully;
//		
//	}// setSpaceProperties
	
	public boolean setSpaceACL(String fullSpacePath, Ace[] ACEList) throws HttpException, IOException {
		
		log.debug("setSpaceACL:fullSpacePath="+fullSpacePath);
		
		boolean aclSetSuccessfully = false;
		aclSetSuccessfully = webDavResource.aclMethod(fullSpacePath, ACEList);
		if (aclSetSuccessfully) log.info("setSpaceACL:ACL set successfully for "+fullSpacePath);
		else log.error("setSpaceACL:ACL setting >>>failed for "+fullSpacePath+" !<<<");
		return aclSetSuccessfully;
	
	}// setSpaceACL
	
	public boolean setSpaceMetadata(String fullSpacePath, Hashtable metadata) throws HttpException, IOException {
		
		log.debug("setSpaceMetadata:fullSpacePath="+fullSpacePath);
		
		boolean metadataSetSuccessfully = false;
		metadataSetSuccessfully = webDavResource.proppatchMethod(fullSpacePath, metadata, true);
		if (metadataSetSuccessfully) log.info("setSpaceMetadata:Metadata set successfully for "+fullSpacePath);
		else log.error("setSpaceMetadata:Metadata setting >>>failed for "+fullSpacePath+" !<<<");
		return metadataSetSuccessfully;
		
	}// setSpaceMetadata
	
	public boolean setSpaceLiveMetadata(String fullSpacePath, String metadata, String value) throws RemoteException {
		log.debug("setProtectedSpaceMetadata:fullSpacePath="+fullSpacePath);
		
		boolean metadataSetSuccessfully = false;
		
		String _metadataSetSuccessfully = (String)call.invoke(new QName("setProperty"), new Object[] { fullSpacePath, metadata, value, "false" });
		metadataSetSuccessfully = Boolean.valueOf(_metadataSetSuccessfully).booleanValue();
		if (metadataSetSuccessfully) log.info("setSpaceLiveMetadata:Live metadata set successfully for "+fullSpacePath);
		else log.error("setSpaceLiveMetadata:Live metadata setting >>>failed for "+fullSpacePath+" !<<<");
		return metadataSetSuccessfully;
	}// setProtectedSpaceMetadata
	
	public boolean setSpaceProtectedMetadata(String fullSpacePath, String metadata, String value) throws RemoteException {
		log.debug("setProtectedSpaceMetadata:fullSpacePath="+fullSpacePath);
		
		boolean metadataSetSuccessfully = false;
		
		String _metadataSetSuccessfully = (String)call.invoke(new QName("setProperty"), new Object[] { fullSpacePath, metadata, value, "true" });
		metadataSetSuccessfully = Boolean.valueOf(_metadataSetSuccessfully).booleanValue();
		if (metadataSetSuccessfully) log.info("setSpaceLiveMetadata:Live metadata set successfully for "+fullSpacePath);
		else log.error("setSpaceLiveMetadata:Live metadata setting >>>failed for "+fullSpacePath+" !<<<");
		return metadataSetSuccessfully;
	}// setProtectedSpaceMetadata
}