/*
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.provider.access;
 
import java.io.IOException; 
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Vector; 

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.webdav.lib.Property;
import org.apache.webdav.lib.PropertyName;
import org.apache.webdav.lib.ResponseEntity;
import org.apache.webdav.lib.WebdavResource;
import org.apache.webdav.lib.methods.DepthSupport;
import org.apache.webdav.lib.methods.PropFindMethod;
import org.apache.webdav.lib.util.DOMUtils;
import org.esupportail.portal.channels.CStockage.provider.ChannelResource;
import org.esupportail.portal.channels.CStockage.provider.ResourceControl;
import org.esupportail.portal.channels.CStockage.config.Space;
import org.esupportail.portal.channels.CStockage.exception.AclAccessException;
import org.esupportail.portal.channels.CStockage.exception.AclReadException;
import org.esupportail.portal.channels.CStockage.exception.AclWriteException;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
import org.esupportail.portal.channels.CStockage.exception.BadConnexionParameters;
import org.esupportail.portal.channels.CStockage.exception.BadFormatException;
import org.esupportail.portal.channels.CStockage.exception.CopyException;
import org.esupportail.portal.channels.CStockage.exception.CreateDirectoryException;
import org.esupportail.portal.channels.CStockage.exception.DeleteException;
import org.esupportail.portal.channels.CStockage.exception.DownloadException;
import org.esupportail.portal.channels.CStockage.exception.EmptyFileOnUploadException;
import org.esupportail.portal.channels.CStockage.exception.MoveException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedDeleteException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedNewDirException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedRenameException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedUploadException;
import org.esupportail.portal.channels.CStockage.exception.NotExistsResourceException;
import org.esupportail.portal.channels.CStockage.exception.NotSupportedAclException;
import org.esupportail.portal.channels.CStockage.exception.OverQuotaException;
import org.esupportail.portal.channels.CStockage.exception.PasteDeletedResourceException;
import org.esupportail.portal.channels.CStockage.exception.PasteInChildDirectoryException;
import org.esupportail.portal.channels.CStockage.exception.PasteNotAuthorizedResourceException;
import org.esupportail.portal.channels.CStockage.exception.PasteWithSameNameException;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.exception.RenameException;
import org.esupportail.portal.channels.CStockage.exception.ServerException;
import org.esupportail.portal.channels.CStockage.exception.StillExistsException;
import org.esupportail.portal.channels.CStockage.exception.UploadException;
import org.esupportail.portal.channels.CStockage.exception.ChannelException;
import org.esupportail.portal.utils.webdav.acl.ACLManager;
import org.esupportail.portal.utils.webdav.acl.EsupPermission;
import org.esupportail.portal.utils.webdav.acl.EsupPermissions;
import org.esupportail.portal.utils.webdav.acl.exception.ReadAclException;
import org.esupportail.portal.utils.webdav.acl.exception.WriteAclException;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
 
/**
 * Id: WebdavAccessImpl.java,v 1.0 14 avr. 2004<br/>
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)<br/>
 * Classes: WebdavAccessImpl<br/>
 * Original Author: Yohan Colmant<br/>
 * Implements the ServerAccess methods to access a DAV server<br/>
 */
public class WebdavAccessImpl extends ServerAccess{
	

	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(WebdavAccessImpl.class);
	
	
	
	
	/**
	 * The dav access url
	 */
	private String url;
	
	/**
	 * The user login
	 */
	private String login;
	
	/**
	 * The password for the dav access
	 */
	private String password;
	
	/**
	 * The Http url used to access the webdav
	 */
	private HttpURL httpURL;	
	
	/** 
	 * The WebDAV ressource 
	 */
	private WebdavResource resource;
	
	
	/**
	 * The path used at the first connexion
	 */
	private String connexionPath;

	
	
	/**
	 * An object used to manage the ACL acces
	 */
	private ACLManager aclManager; 
	
	/**
  	 * The namespace for the ACL
  	 */
  	private String aclNamespace;
	
	/**
  	 * The user prefix for the ACL
  	 */
  	private String aclUserPrefix;
    
  	/**
  	 * The group prefix for the ACL
  	 */
  	private String aclGroupPrefix;
  	
  	/**
  	 * The ACL security group
  	 */
  	private String aclSecuriryGroup;
    
  	
  	
	
	/**
     * Default constructor
     */
	public WebdavAccessImpl() {
	}
	
	
	
	
	/**
     * This method initializes the parameters. You have to call this method before calling connect method.
     * @param space the space corresponding to the server access
     * @throws MalformedURLException
     * @throws PropertiesException
     */
	public void init(Space space) throws MalformedURLException, PropertiesException {
		//String s = "\n\ninit - label:"+space.getLabel();
		
		
		// first init
		//if (this.url == null) {		
			
			this.aclNamespace = space.getServer().getAclNamespace();
			this.aclUserPrefix = space.getServer().getAclUserPrefix();
			this.aclGroupPrefix = space.getServer().getAclGroupPrefix();
			this.aclSecuriryGroup = space.getServer().getAclSecurity();
			
			this.url = space.getCurrentFullUrlPath();	
			
		//}
			//s+="\n       url apres:"+url;
		// set login and password, and construct the HttpURL object
		this.login = space.getServer().getLogin();
		this.password = space.getServer().getPassword();
		if (log.isDebugEnabled()) {
			log.debug("init"+" :: url="+this.url);
			log.debug("init"+" :: login="+this.login);
			log.debug("init"+" :: password="+this.password);
			log.debug("init"+" :: aclNamespace="+this.aclNamespace);
			log.debug("init"+" :: aclUserPrefix="+this.aclUserPrefix);
			log.debug("init"+" :: aclGroupPrefix="+this.aclGroupPrefix);
			log.debug("init"+" :: aclSecuriryGroup="+this.aclSecuriryGroup);
		}
		//System.out.println(space.getLabel()+" >>>   login: "+login+"   password: "+password);
		try {
			//System.out.println(this.url);
			//System.out.println(this.login);
			//System.out.println(this.password);
			httpURL = new HttpURL(this.url);
			httpURL.setUserinfo(this.login, this.password);
			connexionPath = httpURL.getPath();
			//s+="\n       connexionPath:"+connexionPath;
			//System.out.println(connexionPath);
		}
		catch(URIException e) {
			log.error("init"+" :: "+e);
            throw new MalformedURLException();
		}
		//log.debug(s);
	}
	
  	
	
	

	/**
     * This method initializes the parameters. You have to call this method before calling connect method.
     * @param url webdav url
     * @param login connexion login
     * @param password connexioàn password
     * @throws MalformedURLException
     */
	private void init(String url, String login, String password) throws MalformedURLException {	
		
		this.url = url;	
		
		if (this.url.charAt(this.url.length()-1)!='/')
			this.url = this.url+"/";
				
		this.login = login;
		this.password = password;
		try {
			httpURL = new HttpURL(this.url);
			httpURL.setUserinfo(this.login, this.password);
		}
		catch(URIException e) {			
			log.error("init"+" :: "+e);
            throw new MalformedURLException();
		}
	}
	
	
	
	/**
	 * Return the hierarchy path oh the server. for example, if the server's url is http://URL:PORT/slide, the currentHierPath is "/slide"
	 * @return a String
	 * @throws MalformedURLException
	 */
	/*public String getServerCurrentHierPath() throws MalformedURLException {
		try {
			return httpURL.getCurrentHierPath();
		}
		catch(URIException e) {			
			log.error("getServerCurrentHierPath"+" :: "+e);
            throw new MalformedURLException();
		}
	}*/
	
	
	
	/**
	 * Connect this object to the server	 
     * @throws ServerException
     * @throws BadConnexionParameters
	 */
	public void connect() throws ServerException, BadConnexionParameters {		
		try {

			//System.out.println("\n\nconnect - connexionPath:"+connexionPath);
			
			//log.debug("\n\nconnect - connexionPath:"+connexionPath+"\n          login:"+login+"\n          password:"+password+"\n          label:"+label);
			
			
			httpURL.setPath(connexionPath);
			
			// connection
			if (true) {//this.resource == null) {
				this.resource = new WebdavResource(httpURL);
				this.resource.setDebug(0);
				if (log.isDebugEnabled())
					log.debug("connect :: statusCode 1:"+this.resource.getStatusCode());
				if (this.resource.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
					throw new BadConnexionParameters();
				}
				else if (this.resource.getStatusCode() == HttpStatus.SC_NOT_FOUND || this.resource.getStatusCode() == HttpStatus.SC_FORBIDDEN) {
					throw new ServerException();
				}
				
			}
			else {
				this.resource.setHttpURL(httpURL);
				if (log.isDebugEnabled())
					log.debug("connect :: statusCode 2:"+this.resource.getStatusCode());
				if (this.resource.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
					throw new BadConnexionParameters();
				}
				else if (this.resource.getStatusCode() == HttpStatus.SC_NOT_FOUND || this.resource.getStatusCode() == HttpStatus.SC_FORBIDDEN) {
					throw new ServerException();
				}
			}
			
			if (this.aclNamespace==null || this.aclUserPrefix==null || this.aclGroupPrefix==null || this.aclSecuriryGroup==null)
				aclManager = null;
			else aclManager = new ACLManager(this.resource, this.aclNamespace, this.aclUserPrefix, this.aclGroupPrefix, this.aclSecuriryGroup);
		}
		catch (HttpException ex) {
			//ex.printStackTrace();
			log.error("connect"+" :: "+ex);
			int reasonCode = ex.getReasonCode();
			if (reasonCode == HttpStatus.SC_UNAUTHORIZED) {
				throw new BadConnexionParameters();
			}
			/*System.out.println("getLocalizedMessage: "+ex.getLocalizedMessage());
			System.out.println("getMessage: "+ex.getMessage());
			System.out.println("getReason: "+ex.getReason());
			System.out.println("getReasonCode: "+ex.getReasonCode());
			System.out.println("getCause: "+ex.getCause());*/			
            throw new ServerException();
        }
		catch (IOException ex) {
			log.error("connect"+" :: "+ex);
            throw new ServerException();
        }		
    }
	
	 
	
	
	/**
	 * Disconnection of the server
	 * @throws ServerException
	 */
	public void disconnect() throws ServerException {
		
		try {			
			this.resource.close();			
		}
		catch (IOException ex) {  
			log.error("disconnect"+" :: "+ex);
            throw new ServerException();
        }
    }
	
	
	/**
	 * Return the stream from a resource
	 * @param fullPath the full resource path
	 * @return the InputStream
	 * @throws IOException
	 */
	public InputStream getMethodData(String fullPath) throws IOException {
		try {
			this.resource.setPath(fullPath);
			return this.resource.getMethodData(fullPath);		
		}
		catch (IOException ex) {  
			log.error("getMethodData"+" :: fullPath="+fullPath+" "+ex);
            throw ex;
        }		
	}
	
	
	
	
	/**
	 * List all ressources for a given path
	 * @param fullPath directory path on the dav server
	 * @return ChannelWebdavResource array
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */	
	// mis en commentaire et remplacé par une autre méthode. cette méthode ne marche pas quand on liste un dossier sur un mod_dav. Par exemple, sin on veut accéder à http://serveur/toto, "toto" apparait dans la liste des dossiers.
	/*public ChannelResource[] ls(String fullPath) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {
		
		if (this.resource == null)
			throw new ApplicationException();
		else {
			try {
				
				
				if (exists(fullPath)) {
					this.resource.setPath(fullPath);								
				}
				else {						
					throw new NotExistsResourceException();
				}				
				
				//TODO URIUtil.encodePath(path);
				WebdavResource[] liste = this.resource.listWebdavResources(fullPath);
				if (this.resource.getStatusCode()==404)
					throw new NotExistsResourceException();
								
				int length = liste.length;				
				
				// we transform the WebdavResource array into a ChannelWebdavResource array				
				ChannelResource[] channelList = new ChannelResource[length];
											
				for (int i=0; i<length; i++) {
					WebdavResource res = liste[i];									
					channelList[i] = new ChannelResource( res.getName(), res.getPath(), res.getGetContentLength(), res.getGetContentType(), res.getGetLastModified(), res.isCollection());
				}
							
				return channelList;
			}
			catch(HttpException e) {						
				log.error("ls"+" :: fullPath="+fullPath+" "+e);
				throw new NotAuthorizedException();
			}
			catch(IOException e) {
				log.error("ls"+" :: fullPath="+fullPath+" "+e);
				throw new ApplicationException();
			}			
		}       	
	}*/
	
	
	
	
	
	
	
	
	
		
	/**
	 * List all ressources for a given path
	 * @param path directory path on the dav server
	 * @param targetDirectory the directory name to list
	 * @return ChannelWebdavResource array
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */	
	public ChannelResource[] ls(String path, String targetDirectory, boolean requiredUportalRealUri) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {		
		return ls(path+targetDirectory, requiredUportalRealUri);
	}
	
	
	
	
	/**
	 * Get the ressource for a given path
	 * @param fullPath directory path on the dav server
	 * @return ChannelResource
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */	
	public ChannelResource getResource(String fullPath, boolean requiredUportalRealUri) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {
		if (log.isDebugEnabled()) {
			log.debug("> Begin getResource WebdavAccessImpl :: fullPath="+fullPath);
		}
		
		if (this.resource == null)
			throw new ApplicationException();
		else {
			try {
				
				// we are in a directory, if this path doesn't finish by a "/", we add it
				/*if(!fullPath.endsWith(("/"))){
					fullPath=fullPath+"/";
				}*/
				//System.out.println("fullpath= "+fullPath);
				if (exists(fullPath)) {
					this.resource.setPath(fullPath);								
				}
				else {	
					//System.out.println("l'erreur est la !!! ");					
					throw new NotExistsResourceException();
				}				
				
				
				String name = this.resource.getName();
                long contentLength = this.resource.getGetContentLength();
                String contentType = this.resource.getGetContentType();
                long lastModified = this.resource.getGetLastModified();
                boolean isCollection = this.resource.isCollection();
                String displayName = this.resource.getDisplayName();
                String uportalRealUri = null;
                if (requiredUportalRealUri) {
	                try {
	                	uportalRealUri = getProperty("ESUP:", fullPath, "uportalrealuri");
	                	if (uportalRealUri==null || uportalRealUri.trim().equals("")) {
	                		uportalRealUri = fullPath;
	                		//uportalRealUri = fullPath+"_titi";
	                	}
	                }
	                catch(Exception e) {
	                	log.error("getResource"+" :: fullPath="+fullPath+" "+e);
	                	uportalRealUri = fullPath;
	                }
                }
				//System.out.println("Dans le getResource: fullpath="+fullPath+"     uportalRealUri="+uportalRealUri);
				ChannelResource resource = new ChannelResource(name, displayName, fullPath, contentLength, contentType, lastModified, isCollection, uportalRealUri);
				
				
				if (this.resource.getStatusCode()==404)
					throw new NotExistsResourceException();
								
				
				
				if (log.isDebugEnabled()) {
					log.debug("> End getResource WebdavAccessImpl :: fullPath="+fullPath);
				}
				
				return resource;
			}
			catch(HttpException e) {						
				log.error("getResource"+" :: fullPath="+fullPath+" "+e);
				throw new NotAuthorizedException();
			}
			catch(IOException e) {
				log.error("getResource"+" :: fullPath="+fullPath+" "+e);
				throw new ApplicationException();
			}			
		}       	
	}
	
	
	
	/**
	 * Upload a file to the path given in argument
	 * @param fileName the input file name
	 * @param fileStream the input file stream
	 * @param path the path
	 * @return boolean true if no problem, else false
	 * @throws ApplicationException
	 * @throws ServerException
	 * @throws NotExistsResourceException
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws UploadException
	 * @throws EmptyFileOnUploadException
	 * @throws OverQuotaException
	 * @throws NotAuthorizedDeleteException
	 * @throws NotAuthorizedUploadException
	 * @throws NotAuthorizedException
	 */	
	public boolean upload(String fileName, InputStream fileStream, String path) throws ApplicationException, ServerException, NotExistsResourceException, StillExistsException, BadFormatException, UploadException, EmptyFileOnUploadException,OverQuotaException, NotAuthorizedDeleteException, NotAuthorizedUploadException, NotAuthorizedException, PropertiesException{ 

		try {			
			
			// the file to upload to the webdav			           					
            String cible = path+fileName;                                            
            //System.out.println("cible: "+cible);
            
            // check if the file still exists 
            boolean exist = false;
            //System.out.println("\n\nUPLOAD a1 "+exist);
            exist = exists(cible);
            //System.out.println("UPLOAD a2 "+exist);
            // we check if a directory has this name
            /*if(!exist && !cible.endsWith(("/"))){            	
            	exist = exist || exists(cible+"/");
            }*/
            //System.out.println("UPLOAD b "+exist);
            if ( exist ) {
            	//System.out.println("c 1");
        		// log
        		if (log.isDebugEnabled()){
        			log.debug("upload"+" :: "+fileName+" already exist");
        		}
        		
            	throw new StillExistsException();
            } 
            else {  
            	//System.out.println("c 2");
            	// check if the filename contains fobiden characters
            	boolean wellFormed = ResourceControl.isWellFormed(fileName);
            	if ( !wellFormed ) {
            		//System.out.println("d 1");
            		// log
            		if (log.isDebugEnabled()){
            			log.debug("upload"+" :: "+fileName+" not well formed");
            		}
            		
                	throw new BadFormatException();
            	}
            	// we can send
            	else { 
            		//System.out.println("d 2");
            		//System.out.println("1 "+cible+" "+fileStream);
            		boolean answer = this.resource.putMethod(cible, fileStream);
            		int httpCode = this.resource.getStatusCode();
            		//System.out.println("2 "+answer+" "+httpCode);
            		
            		// if a multistatus response
            		if (httpCode == 207 || httpCode == 403)
            			throw new NotAuthorizedUploadException();
            		
            		if (httpCode==507)throw new OverQuotaException();
            		
            		if ((httpCode>=400) && (httpCode<600) ) answer=false;
            		
            		if (answer) {
            			
            			// we check if the uploaded file is empty
            			if (fileIsEmptyOnServer(fileName, path)) {
            				
            				// we delete the file
            				delete(fileName, path);
            				
            				// we throw a new Exception
            				throw new EmptyFileOnUploadException();
            			}
            			else {                  				
            				return true;
            			}            			
            		}
            		else {
            			log.error("upload"+" :: fileName="+fileName+"  http code = "+ httpCode);
            			throw new UploadException();                			
            		}     
            	}
            }
        }
		catch (HttpException ex) {
			log.error("upload"+" :: "+ ex);
            throw new ServerException();
        }
		catch (IOException ex) {  
			log.error("upload"+" :: "+ ex);
            throw new ServerException();
        }
        catch (DeleteException ex) {

    		// log
    		if (log.isDebugEnabled()){
    			log.debug("upload"+" :: DeleteException");
    		}
    		
            throw new UploadException();
        } 
	}
	
	
	/**
	 * Check if a file is empty on the server
	 * @param fileName the name of the file to check
	 * @param path the path where is the file on the server
	 * @return true if the file is empty on the server, false else
	 * @throws ApplicationException
	 */
	private boolean fileIsEmptyOnServer(String fileName, String path) throws ApplicationException {
		
		try {
			String pathAndName = path+fileName;
			
			// check if this is a valid resource
			if (exists(pathAndName)) {
				this.resource.setPath(pathAndName);								
			}
			else {											
				throw new NotExistsResourceException();
			}
			
			if (this.resource.exists()) {
				int length = (int)resource.getGetContentLength();				
				if (length == 0)
					return true;
				else return false;
			}
			else return false;
		}
		catch (HttpException e) {			
			log.error("fileIsEmptyOnServer"+" fileName="+fileName+"  :: "+ e);
			throw new ApplicationException();
		}
		catch (IOException e) {			
			log.error("fileIsEmptyOnServer"+" fileName="+fileName+"  :: "+ e);
			throw new ApplicationException();
		}
		catch(ChannelException e) {
			// log
    		if (log.isDebugEnabled()){
    			log.debug("fileIsEmptyOnServer"+" fileName="+fileName+"  :: ApplicationException");
    		}
			throw new ApplicationException();
		}		
	}
	
	
	/**
	 * Delete the resource given in argument
	 * @param file file/directory to delete
	 * @param path path where is file/directory
	 * @return boolean true if well done else false
	 * @throws ApplicationException
	 * @throws DeleteException
	 * @throws NotAuthorizedDeleteException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean delete(String file, String path) throws ApplicationException, DeleteException, NotAuthorizedDeleteException, NotExistsResourceException, NotAuthorizedException {
		try {
            String cible = path+file;
			
            // check if is a directory
            boolean isDir = isDirectory(file, path);
            if (isDir)
            	cible = cible+"/";            
            
            boolean answer = this.resource.deleteMethod(cible);
    		int httpCode = this.resource.getStatusCode();
    	
    		// if a multistatus response
    		if (httpCode == 207 || httpCode == 403)
    			throw new NotAuthorizedDeleteException();
    	
    		if ((httpCode>=400) && (httpCode<600) ) answer=false;
    		if (answer) { 
                return true;
            } 
    		else {
    			log.error("delete"+" :: file="+file+"  http code = "+ httpCode);
    			throw new DeleteException();
            }
        }
		catch (HttpException ex) {
			log.error("delete"+" file="+file+"  :: "+ex);
        	throw new NotAuthorizedDeleteException();
        } 
		catch (IOException ex) {
			log.error("delete"+" file="+file+"  :: "+ex);
        	throw new ApplicationException();
        }                   
	}
	
	/**
	 * Rename the resource
	 * @param oldName file/directory to rename
	 * @param newName new name of the file/directory
	 * @param path path where is file/directory
	 * @return boolean true if well done else false
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws ApplicationException
	 * @throws RenameException
	 * @throws NotAuthorizedRenameException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean rename(String oldName, String newName, String path) throws StillExistsException, BadFormatException, ApplicationException, RenameException, NotAuthorizedRenameException, NotExistsResourceException, NotAuthorizedException, PropertiesException {
		try {
			//check if file exist on dav Server
			String fullPath = path+newName;			
            boolean exist = exists(fullPath);
            
            /*if(!fullPath.endsWith(("/")) && !exist) {
            	fullPath=fullPath+"/";
            	exist = exist || exists(fullPath);
            }*/
            
            if ( exist ) {

        		// log
        		if (log.isDebugEnabled()){
        			log.debug("rename"+" :: file="+newName+" already exist");
        		}
        		
            	throw new StillExistsException();            	
            }
            else {          
            	// check if the filename contains fobiden characters
            	boolean wellFormed = ResourceControl.isWellFormed(newName);
            	if ( !wellFormed ) { 

            		// log
            		if (log.isDebugEnabled()){
            			log.debug("rename"+" :: file="+newName+" not well formed");
            		}
            		
                	throw new BadFormatException();
            	}
            	// we can rename
            	else {            		
            		String cible = path+oldName;
			
            		// check if is a directory
            		boolean isDir = isDirectory(oldName, path);
            		if (isDir)
            			cible = cible+"/"; 
            		
            		if (exists(cible)) {
    					this.resource.setPath(cible);								
    				}
    				else {											
    					throw new NotExistsResourceException();
    				}
            		
            		// we rename            
            		cible = path+newName;
            		if (isDir)
            			cible = cible+"/";
            		
            		boolean answer = this.resource.moveMethod(cible);
             		int httpCode = this.resource.getStatusCode();
             		
             		// if a multistatus response
            		if (httpCode == 207 || httpCode == 403)
            			throw new NotAuthorizedRenameException();
             		
             		if ((httpCode>=400) && (httpCode<600) ) answer=false;
             		if (answer) { 
            			return true;
             		}
            		else{
            			log.error("rename"+" :: file="+newName+" http code = "+ httpCode);
            			throw new RenameException();
            		}
            	}            
            }
		}
        catch (HttpException ex) {
        	log.error("rename"+" :: file="+newName+" "+ex);
        	throw new NotAuthorizedRenameException();
        }
        catch (IOException ex) {
        	log.error("rename"+" :: file="+newName+" "+ex);
        	throw new RenameException();
        }               
	}
	
	
	/**
	 * Create the directory given in argument
	 * @param name file/directory to delete
	 * @param path path where is file/directory
	 * @return boolean true if well done else false
	 * @throws ApplicationException
	 * @throws CreateDirectoryException
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws NotAuthorizedNewDirException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean createDir (String name, String path) throws ApplicationException, CreateDirectoryException, StillExistsException, BadFormatException, NotAuthorizedNewDirException, NotExistsResourceException, NotAuthorizedException, PropertiesException{
		try {
			//look if a file with the same name exist
			String fullPath = path+name;			
            boolean exist = exists(fullPath);
            
            /*if(!fullPath.endsWith(("/")) && !exist) {
            	fullPath=fullPath+"/";
            	exist = exist || exists(fullPath);
            }*/
            
            if ( exist ) {

        		// log
        		if (log.isDebugEnabled()){
        			log.debug("createDir"+" :: name="+name+"  already exist");
        		}
            	throw new StillExistsException();           	
            }
            else {          
            	// check if the file is well-formed
            	boolean wellFormed = ResourceControl.isWellFormed(name);
            	if ( !wellFormed ) {

            		// log
            		if (log.isDebugEnabled()){
            			log.debug("createDir"+" :: name="+name+"  not well formed");
            		}
            		
                	throw new BadFormatException();
            	}
            	// we can create the directory
            	else {            		
            		if (exists(path)) {
    					this.resource.setPath(path);								
    				}
    				else {											
    					throw new NotExistsResourceException();
    				}

               		boolean answer = this.resource.mkcolMethod(path+name+"/");
               		int httpCode = this.resource.getStatusCode();
               		
               		// if a multistatus response
            		if (httpCode == 207 || httpCode == 403)
            			throw new NotAuthorizedNewDirException();
               		
            		if ((httpCode>=400) && (httpCode<600) ) answer=false;
            		if (answer)
            			return true;
            		else {
            			log.error("createDir"+" :: name="+name+" http code = "+ httpCode);
                    	throw new CreateDirectoryException();
            		}
            	}
            }
		}
        catch (HttpException ex) {
        	log.error("createDir"+" :: name="+name+" "+ex);
        	throw new NotAuthorizedNewDirException();
        }
        catch (IOException ex) {
        	log.error("createDir"+" :: name="+name+" "+ex);
        	throw new CreateDirectoryException();
        }          
	}
	
	
	/**
	 * Check if we can paste here
	 * @param fromSpace the space from whitch we want to paste
	 * @param toSpaceKey the space key where we want to paste
	 * @param clipboardPath the path where is the clipboad
	 * @param clipboard the containt of the clipboard
	 * @param curentDirPath the path of the curent dir
	 * @return true if ok excpetion else
	 * @throws ApplicationException
	 * @throws PasteInChildDirectoryException
	 * @throws PasteWithSameNameException
	 * @throws PasteDeletedResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean canPaste(Space fromSpace, String toSpaceKey, String clipboardPath, Vector clipboardNamesFrom, Vector clipboardNamesTo, String curentDirPath) throws ApplicationException, PasteInChildDirectoryException, PasteWithSameNameException, PasteDeletedResourceException, NotAuthorizedException {
		
		// we check if there is a resource with the same name in the curent dir
		for (int i=0; i<clipboardNamesTo.size(); i++) {
			String resourceName = (String)clipboardNamesTo.elementAt(i);
			
			String fullPath = curentDirPath+resourceName;			
            boolean exist = exists(fullPath);
            
            if(!fullPath.endsWith(("/")) && !exist) {
            	fullPath=fullPath+"/";
            	exist = exist || exists(fullPath);
            }
			
			if (exist)
				throw new PasteWithSameNameException();			
		}
		
		// we check if we try to paste a resource in its child
		if (toSpaceKey.equals(fromSpace.getKey())) {
			for (int i=0; i<clipboardNamesTo.size(); i++) {
				String resourceName = (String)clipboardNamesTo.elementAt(i);
				if (curentDirPath.startsWith(clipboardPath+resourceName+"/")) {				
					throw new PasteInChildDirectoryException();
				}					
			}
		}
		
		// we check if one of the selected resource has been deleted
		ServerAccess fromAccess = fromSpace.getServerAccessObject();
		//System.out.println("existe encore dans "+fromSpace.getLabel()+" ?");
		for (int i=0; i<clipboardNamesFrom.size(); i++) {
			String resourceName = (String)clipboardNamesFrom.elementAt(i);			
			//System.out.println("resourceName= "+resourceName);
			String fullPath = clipboardPath+resourceName;
			//System.out.println("fullPath= "+fullPath);
			boolean exist = fromAccess.exists(fullPath);
			//System.out.println("existe "+fullPath+" --> "+exist);
            if(!fullPath.endsWith(("/")) && !exist) {
            	fullPath=fullPath+"/";
            	exist = exist || fromAccess.exists(fullPath);
            	//System.out.println("existe "+fullPath+" --> "+exist);
            }			
			
			if (!exist)
				throw new PasteDeletedResourceException();					
		}
		
		return true;
	}
	
	
	

	
	/************************
	 *      Copy methods
	 ************************/
	
	
	
	
	
	

	/**
	 * Local copy method
	 * @param resource resource to copy
	 * @param fromPath path where is the resource
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	protected boolean localCopy(String resourceName, String fromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		try {						
			
			// check if resource is a directory   
			String realResource = resourceName;
			boolean isDir = isDirectory(resourceName, fromPath);
			if (isDir)
				realResource = realResource+"/"; 			
			
			// absolute path of the resource
			String absoluteFromPath = fromPath+realResource;
			
			// absolute path to copy the resource
			String absoluteToPath = toPath+realResource;							
			
			// fix the path			
			if (exists(absoluteFromPath)) {
				this.resource.setPath(absoluteFromPath);
			}
			else {											
				throw new NotExistsResourceException();
			}            
           
			boolean answer = this.resource.copyMethod(absoluteToPath);	
			int httpCode = this.resource.getStatusCode();
			
			// if a multistatus response
			if (httpCode == 207 || httpCode == 500)
				throw new PasteNotAuthorizedResourceException();
			
			// if we try to put a document in a not authorized directory
			if (httpCode == 403)
				throw new NotAuthorizedUploadException();
			
			if (httpCode==507)throw new OverQuotaException();
			
			if ((httpCode>=400) && (httpCode<600) ) answer=false;
			
			if (answer)
				return true;
			else {
				log.error("localCopy"+" :: resourceName="+resourceName+" http code = "+ httpCode);
				throw new CopyException();
			}
		}
		catch (HttpException ex) {
			log.error("localCopy"+" :: resourceName="+resourceName+" "+ex);
			throw new PasteNotAuthorizedResourceException();
		}
		catch (IOException ex) {
			log.error("localCopy"+" :: resourceName="+resourceName+" "+ex);
			throw new CopyException();
		}  	
	}
	
	
	
	/**
	 * The distant copy method
	 * @param resource resource to copy
	 * @param fromAccess the space access from witch we want to copy
	 * @param fromPath path where is the resource
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	protected boolean distantCopy(String resourceNameFrom, String resourceNameTo, ServerAccess fromAccess, String fromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		// check if resource is a directory   
		boolean isDirectory = fromAccess.isDirectory(resourceNameFrom, fromPath);	
		
		//System.out.println(resource+" dans "+fromPath+" est directory ? "+isDirectory);
		
		// if file
		if (!isDirectory) {
			String absoluteFromPath = fromPath+resourceNameFrom;
			return distantCopyFile(resourceNameTo, fromAccess, absoluteFromPath, toPath);
		}
		
		// if directory
		else {
			String absoluteFromPath = fromPath+resourceNameFrom;
			String name = resourceNameTo;
			if (!name.endsWith("/")) {
				name = name+"/";
			}
			if (!absoluteFromPath.endsWith("/")) {
				absoluteFromPath = absoluteFromPath+"/";
			}
			return distantCopyDirectory(name, fromAccess, absoluteFromPath, toPath);
		}		

	}
	
	
	

	/**
	 * The distant copy method
	 * @param resource resource to copy
	 * @param fromAccess the space access from witch we want to copy 
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	private boolean distantCopy(ChannelResource resource, ServerAccess fromAccess, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		// check if resource is a directory   
		boolean isDirectory = resource.isCollection(); 	
		
		// resource name
		String name = resource.getName();
				
		// resource full path
		String path = resource.getPath();
		if (!path.endsWith("/"))
			path += "/";
		String absoluteFromPath = resource.getPath();
		
		// if directory
		if (!isDirectory) {
			return distantCopyFile(name, fromAccess, absoluteFromPath, toPath);
		}
		
		// if file
		else {
			if (!name.endsWith("/")) {
				name = name+"/";
			}
			if (!absoluteFromPath.endsWith("/")) {
				absoluteFromPath = absoluteFromPath+"/";
			}
			return distantCopyDirectory(name, fromAccess, absoluteFromPath, toPath);
		}		

	}
	
	
	

	
	/**
	 * The distant copy method of a file
	 * @param fileName file to copy
	 * @param fromAccess the space access from witch we want to copy
	 * @param absoluteFromPath path where is the resource
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	private boolean distantCopyFile(String resourceNameTo, ServerAccess fromAccess, String absoluteFromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		try {
		
			// absolute path to copy the resource
			String absoluteToPath = toPath+resourceNameTo;							
			
			// get the resource from the server			
			InputStream streamFromFile = fromAccess.getMethodData(absoluteFromPath);
			
			// log
			if (log.isDebugEnabled()) {
				log.debug("distantCopyFile"+" :: absoluteFromPath="+absoluteFromPath);
			}
			
			// if not exists
			if (streamFromFile==null) {
				throw new NotExistsResourceException();
			}
			
			// if the resource exists
			else {
				
				// put the stream to the new server
				boolean answer = this.resource.putMethod(absoluteToPath, streamFromFile);
				streamFromFile.close();			
				
				int httpCode = this.resource.getStatusCode();
				
				// if a multistatus response
				if (httpCode == 207 || httpCode == 500)
					throw new PasteNotAuthorizedResourceException();
				
				// if we try to put a document in a not authorized directory
				if (httpCode == 403)
					throw new NotAuthorizedUploadException();
				
				// over quota
				if (httpCode==507)throw new OverQuotaException();
				
				// if error
				if ((httpCode>=400) && (httpCode<600) ) answer=false;
			
				// if ok, return true
				if (answer)
					return true;
				
				// if not ok, exception
				else {
					log.error("distantCopyFile"+" :: resourceNameTo="+resourceNameTo+" absoluteFromPath="+absoluteFromPath+" http code = "+ httpCode);
					throw new CopyException();
				}
		
			}
		}
		catch (HttpException ex) {
			log.error("distantCopyFile"+" resourceNameTo="+resourceNameTo+" :: "+ex);
			throw new PasteNotAuthorizedResourceException();
		}
		catch (IOException ex) {
			log.error("distantCopyFile"+" resourceNameTo="+resourceNameTo+" :: "+ex);
			throw new CopyException();
		} 
	}
	
	
	

	
	/**
	 * The distant copy method of a directory
	 * @param directoryName file to directory
	 * @param fromAccess the space access from witch we want to copy
	 * @param absoluteFromPath path where is the resource
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	private boolean distantCopyDirectory(String resourceNameTo, ServerAccess fromAccess, String absoluteFromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		try {
		
			// absolute path to copy the resource
			String absoluteToPath = toPath+resourceNameTo;							
			
			// if exists from path
			boolean exists = fromAccess.exists(absoluteFromPath);
			//System.out.println("existe "+absoluteFromPath+" ? "+exists);
			if (exists) {				

				// create this directory onto the new server
				boolean answer = this.resource.mkcolMethod(absoluteToPath);
				
				// if ok
				int httpCode = this.resource.getStatusCode();
				
				// if a multistatus response
				if (httpCode == 207 || httpCode == 500)
					throw new PasteNotAuthorizedResourceException();
				
				// if we try to put a document in a not authorized directory
				if (httpCode == 403)
					throw new NotAuthorizedUploadException();
				
				// over quota
				if (httpCode==507)
					throw new OverQuotaException();
				
				// if error
				if ((httpCode>=400) && (httpCode<600) ) 
					answer=false;
			
				// if not ok
				if (!answer) {
					log.error("distantCopyDirectory"+" :: resourceNameTo="+resourceNameTo+" http code = "+ httpCode);
					throw new CopyException();
				}
				
				// list the resources into this directory				
				ChannelResource[] resources = fromAccess.ls(absoluteFromPath, false);
				
				// for each resource, we copy
				for (int i=0; i<resources.length; i++) {
					distantCopy(resources[i], fromAccess, absoluteToPath);
				}				

				// if ok, return true
				if (answer)
					return true;
				
				// if not ok, exception
				else {
					log.error("distantCopyDirectory"+" :: resourceNameTo="+resourceNameTo+" http code = "+ httpCode);
					throw new CopyException();
				}
				
			}
			else {											
				throw new NotExistsResourceException();
			}    
			
		}
		catch (HttpException ex) {
			log.error("distantCopyDirectory"+" :: resourceNameTo="+resourceNameTo+" "+ex);
			throw new PasteNotAuthorizedResourceException();
		}
		catch (IOException ex) {
			log.error("distantCopyDirectory"+" :: resourceNameTo="+resourceNameTo+" "+ex);
			throw new CopyException();
		} 
	}
	
	
	
	


	
	/************************
	 *      Move methods
	 ************************/
	
	
	
	
	

	
	

	
	
	/**
	 * Local move method
	 * @param resource resource to move
	 * @param fromPath path where is the resource
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws MoveException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	protected boolean localMove(String resource, String fromPath, String toPath) throws MoveException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		try {						
			
			// check if resource is a directory   
			String realResource = resource;
			boolean isDir = isDirectory(resource, fromPath);
			if (isDir)
				realResource = realResource+"/"; 			
			
			// absolute path of the resource
			String absoluteFromPath = fromPath+realResource;
			
			// absolute path to move the resource
			String absoluteToPath = toPath+realResource;							
			
			// fix the path
			if (exists(absoluteFromPath)) {
				this.resource.setPath(absoluteFromPath);								
			}
			else {											
				throw new NotExistsResourceException();
			}            
           
			boolean answer = this.resource.moveMethod(absoluteToPath);
			int httpCode = this.resource.getStatusCode();
			
			// if a multistatus response
			if (httpCode == 207 || httpCode == 500)
				throw new PasteNotAuthorizedResourceException();
			
			// if we try to put a document in a not authorized directory
			if (httpCode == 403)
				throw new NotAuthorizedUploadException();
			
			
			if (httpCode==507)throw new OverQuotaException();
			
			if ((httpCode>=400) && (httpCode<600) ) answer=false;
			
			if (answer)
				return true;
			else {
				log.error("localMove"+" :: resource="+resource+" http code = "+ httpCode);
				throw new MoveException();
			}
		}
		catch (HttpException ex) {
			log.error("localMove"+" :: resource="+resource+" "+ex);
			throw new PasteNotAuthorizedResourceException();
		}
		catch (IOException ex) {
			log.error("localMove"+" :: resource="+resource+" "+ex);
			throw new MoveException();
		}  	
	}
	
	
	
	
	
	
	
	
	
	
	
	
	/**
	 * Return the resource associated to the file to download
	 * @param name the file name
	 * @param path the path where to find the file
	 * @return the ChannelWebdavResource
	 * @throws DownloadException
	 */
	public ChannelResource download(String name,String path) throws DownloadException {
		
		try {
			this.init(this.url,this.login,this.password);
		} 
		catch (MalformedURLException ex) {
			log.error("download"+" :: name="+name+" "+ex);
		}
		
		try {				        					
			WebdavResource fileToDownloadResource = new WebdavResource(httpURL);
			fileToDownloadResource.setPath(path+name);
			
			return new ChannelResource( fileToDownloadResource.getName(), fileToDownloadResource.getDisplayName(), fileToDownloadResource.getPath(), fileToDownloadResource.getGetContentLength(), fileToDownloadResource.getGetContentType(), fileToDownloadResource.getGetLastModified(), fileToDownloadResource.isCollection(), fileToDownloadResource.getMethodData(), null);						
		}
		catch(HttpException ex){			
			log.error("download"+" :: name="+name+" "+ex);
	     	throw new DownloadException();
		}
		catch(IOException ex){			
			log.error("download"+" :: name="+name+" "+ex);
	     	throw new DownloadException();
		}
		
		
	}
	
	
	
	
	
	/************************
	 * Webdav control methods
	 ************************/
	
	
	
	/**
	 * Check is the resource exists
	 * @param resourceName name of the file/directory to verify
	 * @param path path to find the file/directory
	 * @return true if file/directory exists else false
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */
	
	public boolean exists(String resourceName, String path) throws ApplicationException, NotAuthorizedException {				
			String pathAndName = path+resourceName;			
			return exists(pathAndName);
	}
	
	
	
	/**
	 * Check is the resource exists
	 * @param fullPath path to find the file/directory
	 * @return true if file/directory exists else false
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */
	public boolean exists(String fullPath) throws ApplicationException, NotAuthorizedException {
		
		if (fullPath.endsWith("/")) {
			return exist(fullPath);
		}
		
		else {
			
			boolean exist = exist(fullPath);
			if (!exist) {
				return exist(fullPath+"/");
			}
			else return exist;
		}
		
	}
	
	
	/**
	 * Check is the resource exists
	 * @param fullPath path to find the file/directory
	 * @return true if file/directory exists else false
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */
	private boolean exist(String fullPath) throws ApplicationException, NotAuthorizedException {
		
		WebdavResource tempResource = null;
		
		try {
			
			//System.out.println("exist fullPath: "+fullPath);
			HttpURL httpURL = new HttpURL(this.url);
			httpURL.setUserinfo(this.login, this.password);
			
			//System.out.println("exists - login="+this.login+" password="+this.password+" url="+this.url+" path="+fullPath);
			
			tempResource = new WebdavResource(httpURL);
			
			//tempResource = this.resource;
			
			//System.out.println("1");
			
			tempResource.setPath(fullPath);
			
			//System.out.println("2");
			
			if (tempResource.exists()) {
				//System.out.println("3");
				try {
					if (tempResource!=null)
						tempResource.close();
				}
				catch(IOException ex) {				
				}
				return true;
			}
			else {
				//System.out.println("4");
				try {
					if (tempResource!=null)
						tempResource.close();
				}
				catch(IOException ex) {				
				}
				return false;
			}			
		}
		catch (HttpException e) {
			//e.printStackTrace();
			//System.out.println("5");
			try {
				if (tempResource!=null)
					tempResource.close();
			}
			catch(IOException ex) {
				
			}
			if (log.isDebugEnabled()){
				log.debug("exists"+" :: doesn't exist fullPath="+fullPath+" "+e);
			}
			return false;
		}
		catch (IOException e) {
			//System.out.println("6");
			try {
				if (tempResource!=null)
					tempResource.close();
			}
			catch(IOException ex) {				
			}
			if (log.isDebugEnabled()){
				log.debug("exists"+" :: doesn't exist fullPath="+fullPath+" "+e);
			}
			throw new ApplicationException();
		}
				
	}
	
	
	
	
	
	
	
	/**
	 * Check if we are authorized to read this resource
	 * @param resourceName name of the file/directory to verify
	 * @param path path to find the file/directory
	 * @return true if authorized else false
	 * @throws ApplicationException
	 */
	public boolean canRead(String resourceName, String path) throws ApplicationException {
		
		try {
			
			String fullPath = path+resourceName;
			boolean exists = exists(fullPath);
			 /*if(!fullPath.endsWith(("/")) && !exists){
                fullPath=fullPath+"/";
                exists = exists || exists(fullPath);
            }*/
						
			if (exists)
				return true;
			else return false;
		}
		catch (NotAuthorizedException e) {	
			// log
			if (log.isDebugEnabled()){
				log.debug("canRead"+" resourceName="+resourceName+" :: NotAuthorizedException");
			}
			return false;
		}
		
	}
	
	
	/**
	 * Check if we are authorized to read this resource
	 * @param path path to find the file/directory
	 * @return true if authorized else false
	 * @throws ApplicationException
	 */
	public boolean canRead(String path) throws ApplicationException {
		
		try {
			String fullPath = path;			
			boolean exists = exists(fullPath);
			 /*if(!fullPath.endsWith(("/")) && !exists){
                fullPath=fullPath+"/";
                exists = exists || exists(fullPath);
            }*/
			 
			if (exists)
				return true;
			else return false;
		}
		catch (NotAuthorizedException e) {	
			// log
			if (log.isDebugEnabled()){
				log.debug("canRead"+" path="+path+" :: NotAuthorizedException");
			}
			return false;
		}
		
	}
	
	/**
	 * Check if the resource named name is a directory in the path given
	 * @param name the name of the resource
	 * @param path the path
	 * @return true if directory, false else
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 * @throws NotExistsResourceException
	 */
	public boolean isDirectory(String name, String path) throws ApplicationException, NotAuthorizedException, NotExistsResourceException {
		
		try {
			// the full path used without "/"
			String fullPath = path+name;			
			
			//System.out.println("existe "+fullPath+" ?");
			
			//if (exists(fullPath)) {
				//this.resource.setPath(fullPath);								
			//}
			//else {	
				//if(!fullPath.endsWith(("/"))){
					//fullPath=fullPath+"/";
				//}
				
				if (exists(fullPath)) {
					this.resource.setPath(fullPath);								
				}
				else {				
					throw new NotExistsResourceException();		
				}
			//}
			
			
			
			if (this.resource.isCollection()) {
				return true;
			}
			else {
				return false;				
			}				
		}				
		catch (HttpException e) {			
			log.error("isDirectory"+" path="+path+" :: "+e);
			throw new NotAuthorizedException();
		}
		catch (IOException e) {			
			log.error("isDirectory"+" path="+path+" :: "+e);
			throw new ApplicationException();
		}			
	}
	

	
	
	/**
	 * Check if the directory named dir is empty or not. We suppose that dir has been checked as a directory before
	 * @param dir the name of the directory
	 * @param path the path
	 * @return true if empty, false else
	 * @throws ApplicationException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean isEmpty (String dir, String path) throws ApplicationException, NotExistsResourceException, NotAuthorizedException {		
				
		try {			
			String pathToList;
			
			// we construct the path
			if (!dir.endsWith("/"))
				pathToList = path+dir+"/";
			else pathToList = path+dir;
			
			// we count the number of resources
			if (ls(pathToList, false).length > 0){
				return false;
			}
			else {
				return true;
			}//end if							
		}
		catch (ApplicationException e) {
			// log
			if (log.isDebugEnabled()){
				log.debug("isEmpty :: dir="+dir+" ApplicationException");
			}			
			throw new ApplicationException();
		}		
	}	
	
	
	
	
	
	
	/*********************
	 * Properties methods
	 *********************/
	
	private static String useBytesName = "quota-used-bytes";
	private static String availableBytesName = "quota-available-bytes";
	
	/**
	 * Get the quota for a specified path
	 * @param path the path of the resource
	 * @return an array of long. 1rst is the available bytes. 2nd is the total bytes
	 */
	public long[] getQuota(String path) {
		
		try {
		
			String useBytesValue = getProperty(null, path, useBytesName);
			//System.out.println("quotas: "+useBytesValue+" ++ "+availableBytesValue);
			if (useBytesValue!=null && !useBytesValue.trim().equals("")) {
				
				String availableBytesValue = getProperty(null, path, availableBytesName);
				if (availableBytesValue!=null && !availableBytesValue.trim().equals("")) {
					
					long useBytes = Long.parseLong(useBytesValue);
					long availableBytes = Long.parseLong(availableBytesValue);
					
					long[] quota = new long[2];
					quota[0] = availableBytes;
					quota[1] = useBytes+availableBytes;
					
					if (log.isDebugEnabled())
						log.debug("getQuota :: path="+path+" available="+quota[0]+" total="+quota[1]);
					
					return quota;
				}
			}
			
			return null;
		}
		catch(ServerException e) {
			log.debug("getQuota :: path="+path+" "+e);
			return null;
		}
	}
	
	

	/**
	 * Get a resource's property specified by the path
	 * @param namespace the namespace used for this metadata
	 * @param path the resource path
	 * @param propertyName the property name
	 * @return a vector containing the properties
	 * @throws ServerException
	 */
	/*private Vector getProperties(String namespace, String path, String propertyName) throws ServerException {
		Vector properties = new Vector(1);
	   
		PropertyName property = new PropertyName(namespace, propertyName);
		properties.addElement(propertyName);
		
	    return getProperties(path, properties);
	}*/

	
	
	
	/**
	 * Get a resource's property specified by the path
	 * @param namespace the namespace used for this metadata
	 * @param path the resource path
	 * @param properties a vector containing the properties name
	 * @return a vector containing the properties
	 * @throws ServerException
	 */ 
	/*private Vector getProperties(String path, Vector properties) throws ServerException {
		try {
			
			String fullPath = path;
			if (path.endsWith("/"))
				fullPath = path.substring(0, path.length()-1);
			
			Enumeration props = this.resource.propfindMethod(path, properties);
			
			Vector res = new Vector();			 
			 
			while (props.hasMoreElements()) {
				String encodedPropertyValue = (String)props.nextElement();
				String decodedPropertyValue = URLDecoder.decode(encodedPropertyValue, "utf-8");
				res.add(decodedPropertyValue);
			}	    
			
			return res;
		}
		catch(IOException e) {
			//e.printStackTrace();
			log.error("getProperties"+" path="+path+" :: "+e);
			throw new ServerException();
		}
	}*/
	

	
	
	/**
	 * Get a resource's property specified by the path
	 * @param namespace the namespace used for this metadata
	 * @param path the resource path
	 * @param propertyName the property name
	 * @return the property as a String object
	 * @throws ServerException
	 */
	/*public String getProperty(String namespace, String path, String propertyName) throws ServerException {
		Vector properties = getProperties(namespace, path, propertyName);
		System.out.println("Je cherche "+propertyName+" avec namespace "+namespace);
		if (properties==null || properties.size()==0)
			return null;
		System.out.println("\tje trouve "+(String)properties.elementAt(0));
		return (String)properties.elementAt(0);
	}*/
	public String getProperty(String namespace, String path, String propertyName) throws ServerException {
		
		//System.out.println("cherche sur "+namespace+" "+path+" "+propertyName);
		
		String defaultNamespace = "DAV:";
		String usedNamespace = namespace;
		if (usedNamespace==null) {
			usedNamespace = defaultNamespace;
		}
		
		try {
			String realPath = path;
			if (path.endsWith("/")) {
				realPath = realPath.substring(0, realPath.length()-1);
			}
			if (!realPath.startsWith("/")) {
				realPath = "/"+realPath;
			}
			realPath = URIUtil.encodePathQuery(realPath);		
			realPath = realPath.replaceAll("!","%21");			
			realPath = realPath.replaceAll("#","%23");
			realPath = realPath.replaceAll("\\$","%24");					
			realPath = realPath.replaceAll("&","%26");
			realPath = realPath.replaceAll("'","%27");
			realPath = realPath.replaceAll("\\(","%28");
			realPath = realPath.replaceAll("\\)","%29");		
			realPath = realPath.replaceAll("@","%40");		
			realPath = realPath.replaceAll("`","%60");			
			
			//System.out.println("realPath: "+realPath);
		
			Vector propertiesName = new Vector(1); 
			propertiesName.addElement(new PropertyName(usedNamespace, propertyName));		
		
			PropFindMethod method = new PropFindMethod(realPath, DepthSupport.DEPTH_INFINITY, propertiesName.elements());
			resource.retrieveSessionInstance().executeMethod(method);
			Enumeration result = method.getResponseProperties(realPath);
		
			
			String res = null;
			if (result.hasMoreElements()) {
				Property p = (Property)result.nextElement();				
				res = URLDecoder.decode(p.getPropertyAsString(), "utf-8");						
			}
		
			//System.out.println(propertyName+"="+res);	
			
			return res;
		}
		catch(IOException e) {
			//e.printStackTrace();
			log.error("getProperty"+" path="+path+" :: "+e);
			throw new ServerException();
		}
	}
	
	
	
	
	/**
	 * Set the property of resource
	 * @param namespace the namespace used for this metadata
	 * @param path the resource path
	 * @param propertyName the name of the property to set
	 * @param propertyValue the value of the property to set
	 * @return true if well done
	 * @throws ServerException
	 */	
	public boolean setProperty(String namespace, String path, String propertyName, String propertyValue) throws ServerException {
		try {			
			String encodedPropertyValue = URLEncoder.encode(propertyValue, "utf-8");
			
			return this.resource.proppatchMethod(path, new PropertyName(namespace, propertyName), encodedPropertyValue, true);
		}
		catch(HttpException e) {
			log.error("setProperty"+" path="+path+" propertyName="+propertyName+" :: "+e);
			throw new ServerException();
		}
		catch(IOException e) {
			log.error("setProperty"+" path="+path+" propertyName="+propertyName+" :: "+e);
			throw new ServerException();
		}
	}

	
	

	
	


	/*********************
	 *    Acl methods
	 *********************/
	
	
	
	

	/**
	 * Get a resource permissions as an EsupPermissions object
	 * @param path the resource path
	 * @param permissionType the type of permission (read, write, ....)
	 * @return an EsupPermissions object representing the permissions
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws NotSupportedAclException
	 */
	/*public EsupPermissions getPermissions(String path, String permissionType) throws AclReadException, AclAccessException, NotSupportedAclException {
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			return aclManager.getPermissions(path, permissionType);
		}
		catch(IOException e) {
			log.error("getPermissions"+" path="+path+" :: "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("getPermissions"+" path="+path+" :: "+e);
			throw new AclReadException();
		}
	}*/
	
	
	/**
	 * Get a resource permissions as an EsupPermissions object
	 * @param path the resource path
	 * @return an EsupPermissions object representing the permissions
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws NotSupportedAclException
	 */
	public EsupPermissions getPermissions(String path) throws AclReadException, AclAccessException, NotSupportedAclException {
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			return aclManager.getPermissions(path);
		}
		catch(IOException e) {
			log.error("getPermissions"+" path="+path+" :: "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("getPermissions"+" path="+path+" :: "+e);
			throw new AclReadException();
		}
	}
	
	/**
	 * Add a grant permission on a resource for a user role specified
	 * @param path the resource path
	 * @param principal the concerned user role
	 * @param permissionType the permission type: [read|read-acl|read-current-user-privilege-set|write|write-acl|write-properties|write-content]
	 * @param fixNow if we want to fix ACL now or if we want to fix with the fixPermissions() method
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public void grant(String path, String principal, String permissionType, boolean fixNow) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		
		//System.out.println("grant "+path+" "+principal+" "+permissionType);
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			aclManager.grant(path, principal, permissionType, fixNow);
		}
		catch(IOException e) {
			//e.printStackTrace();
			log.error("grant"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			//e.printStackTrace();
			log.error("grant"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
		catch(WriteAclException e) {
			//e.printStackTrace();
			log.error("grant"+" :: path="+path+" "+e);
			throw new AclWriteException();
		}
	}
	
	/**
	 * Add a deny permission on a resource for a user role specified
	 * @param path the resource path
	 * @param principal the concerned user role
	 * @param permissionType the permission type: [read|read-acl|read-current-user-privilege-set|write|write-acl|write-properties|write-content]
	 * @param fixNow if we want to fix ACL now or if we want to fix with the fixPermissions() method
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public void deny(String path, String principal, String permissionType, boolean fixNow) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		
		//System.out.println("deny "+path+" "+principal+" "+permissionType);
		
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			aclManager.deny(path, principal, permissionType, fixNow);
		}
		catch(IOException e) {
			log.error("deny"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("deny"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
		catch(WriteAclException e) {
			log.error("deny"+" :: path="+path+" "+e);
			throw new AclWriteException();
		}
	}
	
	/**
	 * Revoke permission on a resource for a user role specified
	 * @param path the resource path
	 * @param principal the concerned user role
	 * @param permissionType the permission type: [read|read-acl|read-current-user-privilege-set|write|write-acl|write-properties|write-content]
	 * @param fixNow if we want to fix ACL now or if we want to fix with the fixPermissions() method
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public void revoke(String path, String principal, String permissionType, boolean fixNow) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		
		//System.out.println("revoke "+path+" "+principal+" "+permissionType);
		
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			aclManager.revoke(path, principal, permissionType, fixNow);
		}
		catch(IOException e) {
			log.error("revoke"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("revoke"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
		catch(WriteAclException e) {
			log.error("revoke"+" :: path="+path+" "+e);
			throw new AclWriteException();
		}
	}
	
	
	/**
	 * Revoke all the permissions on a resource
	 * @param path the resource path
	 * @param fixNow if we want to fix ACL now or if we want to fix with the fixPermissions() method
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public void revokeAllPermissons(String path, boolean fixNow) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {

		if (aclManager == null) {
			NotSupportedAclException e = new NotSupportedAclException();
			log.error("revokeAllPermissons"+" :: path="+path+" "+e);
			throw e;
		}
		
		try {
			aclManager.revokeAllPermissons(path, fixNow);
		}
		catch(IOException e) {
			log.error("revokeAllPermissons"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("revokeAllPermissons"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
		catch(WriteAclException e) {
			log.error("revokeAllPermissons"+" :: path="+path+" "+e);
			throw new AclWriteException();
		}
		catch(Exception e) {
			//e.printStackTrace();
		}
	}
	
	
	
	/**
	 * Fix the resource permissions
	 * @param path the path for the acl we fix
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public void fixPermissions(String path) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {

		if (aclManager == null) {
			NotSupportedAclException e = new NotSupportedAclException();
			log.error("fixPermissions"+" :: path="+path+" "+e);
			throw e;
		}
		
		try {
			aclManager.fixPermissions(path);
		}
		catch(IOException e) {
			log.error("fixPermissions"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("fixPermissions"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
		catch(WriteAclException e) {
			log.error("fixPermissions"+" :: path="+path+" "+e);
			throw new AclWriteException();
		}
		catch(Exception e) {
			//e.printStackTrace();
		}
	}
	
	
	/**
	 * If we set acl asynchronously, we can init the working acl by this method.
	 * @param path the path for the acl we fix
	 * @throws NotSupportedAclException
	 */
	public void initTemporaryWorkingPermissions(String path) throws NotSupportedAclException {
		if (aclManager == null) {
			NotSupportedAclException e = new NotSupportedAclException();
			log.error("fixPermissions"+" :: path="+path+" "+e);
			throw e;
		}
		
		aclManager.initTemporaryWorkingPermissions(path, null);
	}
	
	
	/**
	 * Check if the specified resource has the inherited permission given in parameter
	 * @param path the resource path
	 * @param principal the concerned user role
	 * @param permissionType the permission type: [read|read-acl|read-current-user-privilege-set|write|write-acl|write-properties|write-content]
	 * @param negative false for grant, true for deny
	 * @return null if not inherited permission, else return the inherited permissions
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws NotSupportedAclException
	 */
	/*public Vector hasInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException {
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			return aclManager.hasInheritedPermission(path, principal, permissionType, negative);
		}
		catch(IOException e) {
			log.error("hasInheritedPermission"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("hasInheritedPermission"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
	}*/
	
	/**
	 * Check if the specified resource has the not inherited permission given in parameter
	 * @param path the resource path
	 * @param principal the concerned user role
	 * @param permissionType the permission type: [read|read-acl|read-current-user-privilege-set|write|write-acl|write-properties|write-content]
	 * @param negative false for grant, true for deny
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws NotSupportedAclException
	 */
	/*public boolean hasNotInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException {
		if (aclManager == null)
			throw new NotSupportedAclException();
		
		try {
			return aclManager.hasNotInheritedPermission(path, principal, permissionType, negative);
		}
		catch(IOException e) {
			log.error("hasNotInheritedPermission"+" :: path="+path+" "+e);
			throw new AclAccessException();
		}
		catch(ReadAclException e) {
			log.error("hasNotInheritedPermission"+" :: path="+path+" "+e);
			throw new AclReadException();
		}
	}*/
	
	
	
	/**
	 * Check The privileges for the current user
	 * @param path the path of the space
	 * @return an array containing the values of reading, writing and sharing
	 */
	public boolean[] checkPrivileges(String path) {
		
		boolean[] results = new boolean[3];
		
		try {
			
			String realPath = path;
			if (path.endsWith("/")) {
				realPath = realPath.substring(0, realPath.length()-1);
			}	
			realPath = URIUtil.encodePathQuery(realPath);		
			realPath = realPath.replaceAll("!","%21");			
			realPath = realPath.replaceAll("#","%23");
			realPath = realPath.replaceAll("\\$","%24");					
			realPath = realPath.replaceAll("&","%26");
			realPath = realPath.replaceAll("'","%27");
			realPath = realPath.replaceAll("\\(","%28");
			realPath = realPath.replaceAll("\\)","%29");		
			realPath = realPath.replaceAll("@","%40");		
			realPath = realPath.replaceAll("`","%60");	
			
			Vector properties = new Vector();
			properties.addElement("current-user-privilege-set");

			PropFindMethod method = new PropFindMethod(realPath, DepthSupport.DEPTH_0, properties.elements());
			resource.retrieveSessionInstance().executeMethod(method);
			Enumeration iter = method.getResponseProperties(realPath);
			//System.out.println("les elements:");
			if (iter.hasMoreElements()) {
				Property p = (Property)iter.nextElement();
				//System.out.println("property: "+p);
				Element element = p.getElement();
				
				NodeList readPrivilege = DOMUtils.getElementsByTagNameNS(element, EsupPermission.READ, ACLManager.DEFAULT_SLIDE_NAMESPACE);
				boolean read = readPrivilege.getLength() == 1;
	        
		        NodeList writePrivilege = DOMUtils.getElementsByTagNameNS(element, EsupPermission.WRITE, ACLManager.DEFAULT_SLIDE_NAMESPACE);
		        boolean write = writePrivilege.getLength() == 1;
		
		        NodeList writeAclPrivilege = DOMUtils.getElementsByTagNameNS(element, EsupPermission.WRITE_ACL, ACLManager.DEFAULT_SLIDE_NAMESPACE);
		        boolean writeAcl = writeAclPrivilege.getLength() == 1;
	
		        results[0] = read;
		        results[1] = write;
		        results[2] = writeAcl;
		        
		        return results;
			}
			
			return getDefaultPrivileges();
		}
		catch(IOException e) {
			log.error("checkPrivileges"+" :: path="+path+" "+e);
			return getDefaultPrivileges();
		}
	}
	
	
	/**
	 * Get the default privileges: read=true, write=true, write-acl=false
	 * @return an array containing the values of reading, writing and sharing
	 */
	private boolean[] getDefaultPrivileges() {
		boolean[] results = new boolean[3];
		results[0] = true;
        results[1] = true;
        results[2] = false;
        log.debug("getDefaultPrivileges");
        return results;
	}
	
	
	
	


	/********************************************************************************************************
	********************************************************************************************************
	 *    Modification methode de listing a cause d'un probleme sur le listage de repertoires sur un mod_dav 
	 ********************************************************************************************************
	********************************************************************************************************/
	

    /**
     * Unescape octets for some characters that a server might (but should not)
     * have escaped. These are: "-", "_", ".", "!", "~", "*", "'", "(", ")"
     * Look at section 2.3 of RFC 2396.
     * @param input
     * @return decoded marks
     */
    private static String decodeMarks(String input) {
        char[] sequence = input.toCharArray();
        StringBuffer decoded = new StringBuffer(sequence.length);
        for (int i = 0; i < sequence.length; i++) {
            if (sequence[i] == '%' && i < sequence.length - 2) {
                switch (sequence[i + 1]) {
                case '2':
                    switch (sequence[i + 2]) {
                    case 'd':
                    case 'D':
                        decoded.append('-');
                        i += 2;
                        continue;
                    case 'e':
                    case 'E':
                        decoded.append('.');
                        i += 2;
                        continue;
                    case '1':
                        decoded.append('!');
                        i += 2;
                        continue;
                    case 'a':
                    case 'A':
                        decoded.append('*');
                        i += 2;
                        continue;
                    case '7':
                        decoded.append('\'');
                        i += 2;
                        continue;
                    case '8':
                        decoded.append('(');
                        i += 2;
                        continue;
                    case '9':
                        decoded.append(')');
                        i += 2;
                        continue;
                    }
                    break;
                case '5':
                    switch (sequence[i + 2]) {
                    case 'f':
                    case 'F':
                        decoded.append('_');
                        i += 2;
                        continue;
                    }
                    break;
                case '7':
                    switch (sequence[i + 2]) {
                    case 'e':
                    case 'E':
                        decoded.append('~');
                        i += 2;
                        continue;
                    }
                    break;
                }
            }
            decoded.append(sequence[i]);
        }
        return decoded.toString();
    }
	
    
    
	
    /**
     * Get the name of this WebdavResource.
     * If the decoding of the name fails, this method will not throw an
     * exception but return the escaped name instead.
     *
     * @return the name of this WebdavResource.
     * @see org.apache.commons.httpclient.HttpURL#getName()
     */
    private static String getName(String url) {
        String escapedName = URIUtil.getName(
            url.endsWith("/") ? url.substring(0, url.length() - 1): url);
        try {
            return URIUtil.decode(escapedName);
        } catch (URIException e) {
            return escapedName;
        }
    }
    
    
    

    /**
     * Date formats using for Date parsing.
     */
    private static final SimpleDateFormat formats[] = {
        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
            new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
            new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
            new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US),
            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US)
    };

    /**
     * Parse the <code>java.util.Date</code> string for HTTP-date.
     *
     * @return The parsed date.
     */
    private static Date parseDate(String dateValue) {
      
        Date date = null;
        for (int i = 0; (date == null) && (i < formats.length); i++) {
            try {
                synchronized (formats[i]) {
                    date = formats[i].parse(dateValue);
                }
            } catch (ParseException e) {
            }
        }

        return date;
    }
    
    
    
    
    
    
    
    /**
     * Get a path child resources
     * @param webdavResource the webdavresource used
     * @param path the resource path to list
     * @return a vector of ChannelResource
     * @throws HttpException
     * @throws IOException
     */
    private static Vector getChilds(WebdavResource webdavResource, String path) throws HttpException, IOException {
    	
		Vector childResources = new Vector();
		HttpURL httpURL = webdavResource.getHttpURL();
		

		// properties 
		Vector props = new Vector();
		props.addElement(WebdavResource.CREATIONDATE);
		props.addElement(WebdavResource.DISPLAYNAME);
		props.addElement(WebdavResource.GETCONTENTLANGUAGE);
		props.addElement(WebdavResource.GETCONTENTLENGTH);
		props.addElement(WebdavResource.GETCONTENTTYPE);
		props.addElement(WebdavResource.GETETAG);
		props.addElement(WebdavResource.GETLASTMODIFIED);
		props.addElement(WebdavResource.LOCKDISCOVERY);
		props.addElement(WebdavResource.RESOURCETYPE);
		props.addElement(WebdavResource.SOURCE);
		props.addElement(WebdavResource.SUPPORTEDLOCK);
		
		PropFindMethod method = new PropFindMethod(URIUtil.encodePath(path), DepthSupport.DEPTH_1, props.elements());
		int status = webdavResource.retrieveSessionInstance().executeMethod(method);
		if (status != HttpStatus.SC_MULTI_STATUS
	              && status != HttpStatus.SC_OK) {
	              HttpException ex = new HttpException();
	              ex.setReasonCode(status);
	              throw ex;
	    }
		Enumeration responses = method.getResponses();
        
    	
        // Make the resources in the collection empty.
        while (responses.hasMoreElements()) {
    
            ResponseEntity response = (ResponseEntity) responses.nextElement();
    
            //System.out.println("  reponse "+response);
            
            boolean itself = false;
            String href = response.getHref();
            if (!href.startsWith("/"))
                href = URIUtil.getPath(href);
            href = decodeMarks(href);

            // Decode urls to common (unescaped) format for comparison 
            // as HttpClient.url.setPath() doesn't escape $ and : chars.
            //
            String httpURLPath = httpURL.getPath();
            String escapedHref = URIUtil.decode(href);
            
            // Normalize them to both have trailing slashes if they differ by one in length.
            int lenDiff = escapedHref.length() - httpURLPath.length();
            int compareLen = 0;
            
            if ( lenDiff == -1 && !escapedHref.endsWith("/")) {
                compareLen = escapedHref.length();
                lenDiff = 0;
            }
            else
            if ( lenDiff == 1 && !httpURLPath.endsWith("/")) {
                compareLen = httpURLPath.length();
                lenDiff = 0;
            }

            // if they are the same length then compare them.
            if (lenDiff == 0) {
                if ((compareLen == 0 && httpURLPath.equals(escapedHref))
                    || httpURLPath.regionMatches(0, escapedHref, 0, compareLen))
                {
                    // escaped href and http path are the same                    
                    itself = true;
                }
            }
    
            //System.out.println("    itself: "+itself);
            if (!itself) {
                        
            	String name = getName(href);
               
            	
                // Process the resource's properties                            
                long contentLength = 0;
                String contentType = null;
                long lastModified = 0;
                boolean isCollection = false;
                String displayName = name;
                
                Enumeration properties = response.getProperties();

                while (properties.hasMoreElements()) {
            	
                	Property property = (Property) properties.nextElement();                	
                	String propertyName = property.getLocalName();
                	String value = property.getPropertyAsString();
                
                	// contentLength property
                	if (propertyName.equals(WebdavResource.GETCONTENTLENGTH)) {
                		if (value!=null && !value.trim().equals(""))
                			contentLength = Long.parseLong(value);
                	}
                
                	// contentType property
                	else if (propertyName.equals(WebdavResource.GETCONTENTTYPE)) {
                		contentType = value;
                	}
                
                	// displayName property
                	else if (propertyName.equals(WebdavResource.DISPLAYNAME)) {
                		displayName = value;
                	}
                                
                	// lastModified property
                	else if (propertyName.equals(WebdavResource.GETLASTMODIFIED)) {
                		Date date = parseDate(value);
                		if (date != null)
                			lastModified = date.getTime();
                	}                

                	// isCollection property
                	else if (propertyName.equals(WebdavResource.RESOURCETYPE)) {
                		if (value.equals("COLLECTION"))
                			isCollection = true;
                		else isCollection = false;
                	}                
                }
    
                
                String resourcePath = path+name;
                if (isCollection && !path.endsWith("/"))
                	path += "/";            
            
                
                
                /*System.out.println("    ajoute displayName="+displayName);
                System.out.println("           path="+resourcePath);
                System.out.println("           contentLength="+contentLength);
                System.out.println("           contentType="+contentType);
                System.out.println("           lastModified="+lastModified);
                System.out.println("           isCollection="+isCollection);
                System.out.println("           getMethodData="+workingResource.getMethodData());
                */
                
               
                
                ChannelResource resource = new ChannelResource(name, displayName, resourcePath, contentLength, contentType, lastModified, isCollection, null);                
            	childResources.addElement(resource);           
            }
        }
        return childResources;
}
    
    
    
	
	

	/**
	 * List all ressources for a given path
	 * @param fullPath directory path on the dav server
	 * @return ChannelWebdavResource array
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */	
	public ChannelResource[] ls(String fullPath, boolean requiredUportalRealUri) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {
		if (log.isDebugEnabled()) {
			log.debug("> Begin ls WebdavAccessImpl :: fullPath="+fullPath);
		}
		
		if (this.resource == null)
			throw new ApplicationException();
		else {
			try {
				// we are in a directory, if this path doesn't finish by a "/", we add it
				/*if(!fullPath.endsWith(("/"))){
					fullPath=fullPath+"/";
				}*/
				//System.out.println("fullpath= "+fullPath);
				if (exists(fullPath)) {					
					this.resource.setPath(fullPath);								
				}
				else {	
					//System.out.println("l'erreur est la !!! ");					
					throw new NotExistsResourceException();
				}				
				
				Vector liste = getChilds(this.resource, fullPath);
				if (this.resource.getStatusCode()==404)
					throw new NotExistsResourceException();
				
				int length = liste.size();				
				
				// we transform the ChannelResource Vector into a ChannelResource array				
				ChannelResource[] channelList = new ChannelResource[length];
					
				for (int i=0; i<length; i++) {
					ChannelResource res = (ChannelResource)liste.elementAt(i);
					
					if (requiredUportalRealUri) {
						 String uportalRealUri = null;
						 try {
							 uportalRealUri = getProperty("ESUP:", res.getPath(), "uportalrealuri");
							 if (uportalRealUri==null || uportalRealUri.trim().equals("")) {
		                		uportalRealUri = res.getPath();
		                		//uportalRealUri = res.getPath()+"_titi/";
		                	}
							 
		                }
		                catch(Exception e) {
		                	log.error("ls"+" :: fullPath="+fullPath+" "+e);
		                	uportalRealUri = fullPath;
		                }
		                //System.out.println("Dans le ls: fullpath="+res.getPath()+"     uportalRealUri="+uportalRealUri);
						res.setUportalRealUri(uportalRealUri);
					}
					
					channelList[i] = res;
				}
				
				if (log.isDebugEnabled()) {
					log.debug("> End ls WebdavAccessImpl :: fullPath="+fullPath);
				}
				return channelList;
			}
			catch(HttpException e) {						
				log.error("ls"+" :: fullPath="+fullPath+" "+e);
				throw new NotAuthorizedException();
			}
			catch(IOException e) {
				log.error("ls"+" :: fullPath="+fullPath+" "+e);
				throw new ApplicationException();
			}			
		}       	
	}
}
