/*
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.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.esupportail.portal.channels.CStockage.provider.ChannelResource;
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.EsupPermissions;
import org.jasig.portal.MultipartDataSource;


/**
 * Id: ServerAccess.java,v 1.0 14 avr. 2004<br/>
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)<br/>
 * Classes: ServerAccess<br/>
 * Original Author: Yohan Colmant<br/>
 * Interface for the dav access<br/>
 */
public abstract class ServerAccess {
	
 

	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(ServerAccess.class);
	
	
	
	
	/**
     * 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 abstract void init(Space space) throws MalformedURLException, PropertiesException;
	
	
	/**
	 * 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 abstract String getServerCurrentHierPath() throws MalformedURLException;
	
	/**
	 * Connect this object to the server	 
     * @throws ServerException
     * @throws BadConnexionParameters
	 */
	public abstract void connect() throws ServerException, BadConnexionParameters;
	
	/**
	 * Disconnection of the server
	 * @throws ServerException
	 */
	public abstract void disconnect() throws ServerException;
	
	/**
	 * 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 abstract ChannelResource[] ls(String fullPath) throws NotExistsResourceException, ApplicationException, NotAuthorizedException;
	
	/**
	 * 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 abstract ChannelResource[] ls(String path, String targetDirectory) throws NotExistsResourceException, ApplicationException, NotAuthorizedException;
	

	/**
	 * Upload a file to the path given in argument
	 * @param inputFile the input file
	 * @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 abstract boolean upload(MultipartDataSource inputFile, String path)throws ApplicationException, ServerException, NotExistsResourceException, StillExistsException, BadFormatException, UploadException, EmptyFileOnUploadException,OverQuotaException, NotAuthorizedDeleteException, NotAuthorizedUploadException, NotAuthorizedException;
	
	/**
	 * 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 abstract boolean delete(String file, String path) throws ApplicationException, DeleteException, NotAuthorizedDeleteException, NotExistsResourceException, NotAuthorizedException ;
	
	/**
	 * 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 abstract boolean rename(String oldName, String newName, String path) throws StillExistsException, BadFormatException, ApplicationException, RenameException, NotAuthorizedRenameException, NotExistsResourceException, NotAuthorizedException;

	/**
	 * 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 abstract boolean createDir (String name, String path) throws ApplicationException, CreateDirectoryException, StillExistsException, BadFormatException, NotAuthorizedNewDirException, NotExistsResourceException, NotAuthorizedException;

	/**
	 * 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 abstract boolean canPaste(Space fromSpace, String toSpaceKey, String clipboardPath, Vector clipboard, String curentDirPath) throws ApplicationException, PasteInChildDirectoryException, PasteWithSameNameException, PasteDeletedResourceException, NotAuthorizedException;
	
	
	
	

	/**
	 * Copy method
	 * @param resource resource to copy
	 * @param fromSpace the space from witch we want to move
	 * @param fromPath path where is the resource
	 * @param toSpaceKey the space key to witch we want to move
	 * @param toPath path to copy the resource
	 * @return boolean true if well done else false
	 * @throws ChannelException
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	public boolean copy(String resource, Space fromSpace, String fromPath, String toSpaceKey, String toPath) throws ChannelException, CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		// if there is not slash at toPath variable
		String toPathWithSlash = toPath;
		if (!toPath.endsWith("/"))
			toPathWithSlash += "/";
		
		// if from and to spaces are the same
		if (toSpaceKey.equals(fromSpace.getKey())) {
			return localCopy(resource, fromPath, toPathWithSlash);
		}
		
		// the spaces are not the same
		else {
			ServerAccess fromAccess = null;
			
			try {
				// connect to the from server
				fromAccess = fromSpace.getServerAccessObject();
				fromAccess.connect();
				
				// do the copy
				boolean result = distantCopy(resource, fromAccess, fromPath, toPathWithSlash);				

				// disconnect
				fromAccess.disconnect();
				
				// return
				if (result == true) {
					return true;
				}
				else {
					
					// log
					if (log.isDebugEnabled()){
						log.debug("copy"+" :: resource="+resource+" CopyException");
					}
					
					throw new CopyException();
				}
				
			}
			catch(ChannelException e) {
				if (fromAccess!=null)
					fromAccess.disconnect();
				throw e;
			}
		}
	}
	
	
	

	/**
	 * 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 abstract boolean localCopy(String resource, String fromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException;
	
	

	/**
	 * 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 abstract boolean distantCopy(String resource, ServerAccess fromAccess, String fromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException;
	
	
	
	

	/**
	 * Move method
	 * @param resource resource to move
	 * @param fromSpace the space from witch we want to move
	 * @param fromPath path where is the resource
	 * @param toSpaceKey the space key to witch we want to move
	 * @param toPath path to move the resource
	 * @return boolean true if well done else false
	 * @throws ChannelException
	 * @throws ApplicationException
	 * @throws MoveException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	public boolean move(String resource, Space fromSpace, String fromPath, String toSpaceKey, String toPath) throws ChannelException, MoveException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		// if there is not slash at toPath variable
		String toPathWithSlash = toPath;
		if (!toPath.endsWith("/"))
			toPathWithSlash += "/";
		
		// if from and to spaces are the same
		if (toSpaceKey.equals(fromSpace.getKey())) {		
			return localMove(resource, fromPath, toPathWithSlash);
		}
		
		// the spaces are not the same
		else {
			ServerAccess fromAccess = null;
			
			try {
				// connect to the from server
				fromAccess = fromSpace.getServerAccessObject();
				fromAccess.connect();
				
				// do the copy
				boolean result = distantCopy(resource, fromAccess, fromPath, toPathWithSlash);				

				// if ok, delete the source
				if (result) {
					if (!fromAccess.delete(resource, fromPath)) {
						throw new DeleteException();
					}
				}
				
				// disconnect
				fromAccess.disconnect();
				
				// return
				if (result == true) {
					return true;
				}
				else {

					// log
					if (log.isDebugEnabled()){
						log.debug("move"+" :: resource="+resource+" MoveException");
					}
					
					throw new MoveException();
				}
				
			}
			catch(ChannelException e) {
				if (fromAccess!=null)
					fromAccess.disconnect();
				throw e;
			}
		}
	}
	
	
	
	

	
	/**
	 * 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 abstract boolean localMove(String resource, String fromPath, String toPath) throws MoveException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException;
	
	
	
	
	
	/**
	 * 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 abstract ChannelResource download(String name,String path) throws DownloadException;
	
	/**
	 * Return the stream from a resource
	 * @param fullPath the full resource path
	 * @return the InputStream
	 * @throws IOException
	 */
	public abstract InputStream getMethodData(String fullPath) throws IOException;
	
	
	
	
	/************************
	 * resource control methods
	 ************************/
	
	
	
	/**
	 * 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 abstract boolean exists(String fullPath) throws ApplicationException, NotAuthorizedException;
	
	/**
	 * 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 abstract boolean exists(String resourceName, String path) throws ApplicationException, NotAuthorizedException;
	
	/**
	 * 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 abstract boolean canRead(String resourceName, String path) throws ApplicationException;
	
	/**
	 * 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 abstract boolean canRead(String path) throws ApplicationException;
	
	/**
	 * 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 abstract boolean isDirectory(String name, String path) throws ApplicationException, NotAuthorizedException, NotExistsResourceException;

	/**
	 * 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 abstract boolean isEmpty (String dir, String path) throws ApplicationException, NotExistsResourceException, NotAuthorizedException;	
	
	
	
	
	/*********************
	 * Properties methods
	 *********************/
	
	
	
	/**
	 * 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 abstract String getProperty(String namespace, String path, String propertyName) throws 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 abstract boolean setProperty(String namespace, String path, String propertyName, String propertyValue) throws 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 abstract EsupPermissions getPermissions(String path, String permissionType) throws AclReadException, AclAccessException, NotSupportedAclException;
	

	/**
	 * 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 abstract EsupPermissions getPermissions(String path) throws AclReadException, AclAccessException, NotSupportedAclException;
	
	
	/**
	 * 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]
	 * @return the EsupPermissions object modified by the action
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public abstract EsupPermissions grant(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException;
	
	/**
	 * 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]
	 * @return the EsupPermissions object modified by the action
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public abstract EsupPermissions deny(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException;
	
	/**
	 * 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]
	 * @return the EsupPermissions object modified by the action
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public abstract EsupPermissions revoke(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException;
	
	/**
	 * 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 abstract Vector hasInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException;
	
	/**
	 * 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 abstract boolean hasNotInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException;
	
}
