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

import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.esupportail.portal.channels.CStockage.channelAction.AbstractChannelAction;
import org.esupportail.portal.channels.CStockage.channelAction.BufferAction;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
import org.esupportail.portal.channels.CStockage.exception.BadConnexionParameters;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.exception.ServerException;
import org.esupportail.portal.channels.CStockage.exception.ChannelException;
import org.esupportail.portal.channels.CStockage.provider.access.ServerAccess;
import org.jasig.portal.security.IPerson;

/**
 * Id: Space.java,v 1.0 9 juil. 2004<br/>
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)<br/>
 * Classes: Space<br/>
 * Original Author: Yohan Colmant<br/>
 * This represents a file space on the server<br/>
 */
public class Space {


	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(Space.class);
	
	
	
	
	
	/**
	 * The space key
	 */
	private String key;
	
	/**
	 * The label of this space
	 */
	private String label;
	
	/**
	 * The server url
	 */
	private String url;
	
	
	
	/**
	 * The server type
	 */
	private String serverType;
		
	/**
	 * The channel action type
	 */
	private String actionType;
	
	
	
	/**
	 * The class name used to manage the actions
	 */
	private String channelActionClass;		

	/**
	 * The class name used to manage the actions
	 */
	private String serverAccessClass;


	
	
	/**
	 * The authentication mode. "cas" or "trusted"
	 */
	private String authenticationMode;
	
	/**
	 * CAS authentication
	 */
	public static final String AUTH_CAS = "cas";
	
	/**
	 * TRUSTED authentication
	 */
	public static final String AUTH_TRUSTED = "trusted";
	
	/**
	 * ASKED authentication
	 */
	public static final String AUTH_ASKED = "asked";
	
	/**
	 * The trusted login if trusted authentication. The portal login else
	 */
	private String login;
	
	/**
	 * The password if trusted authentication, or is asked authentication
	 */
	private String password;
	
	
	
	/**
	 * The currentPath used
	 */
	private Vector currentPath = new Vector();
	
	/**
	 * The attribute used to access the server
	 */
	private ServerAccess access;
	
	/**
	 * To manage the actions in funtion of the access class
	 */
	private AbstractChannelAction channelAction;
	
	
	
	

	/**
	 * The namespace used for the metadata
	 */
	private String metadataNamespace;
	
	
	
	
	/**
	 * The ACL namespace
	 */
	private String aclNamespace;
	
	/**
	 * The user prefix for the ACL
	 */
	private String aclUserPrefix;
	
	/**
	 * The group prefix for the ACL
	 */
	private String aclGroupPrefix;
	
	/**
	 * The uPortal group node for the ACL
	 */
	private String aclUportalGroup;
	
	
	
	
	
	/**
	 * The authorization list for this space
	 */
	private ArrayList authorizations = new ArrayList();
	
	
	
	/**
	 * The cifs domain
	 */
	private String cifsDomain;
	
	/**
	 * The Cifs resolve order
	 */
	private String cifsResolveOrder;
	
	/**
	 * The cifs disable plain text password
	 */
	private String cifsDisablePlainTextPassword;
	
	
	
	
	
	
	
	/**
	 * If this space is a personnal one
	 */
	private boolean personnalSpace = false;
	
	
	
	
	
	
	

	/**
	 * return the authorization list
	 * @return the authorization list
	 */
	public ArrayList getAuthorization() {			
		return authorizations;
	}

	/**
	 * add a new authorization to the list
	 * @param authorization the authorization to add
	 */
	public void setAuthorization(AuthorizationSpaceParameter authorization) {		
		// add this authorization
		authorizations.add(authorization);
	}
	
	
	
	
	/**
	 * @return Returns the metadataNamespace.
	 */
	public String getMetadataNamespace() {
		return metadataNamespace;
	}
	/**
	 * @param metadataNamespace The metadataNamespace to set.
	 */
	public void setMetadataNamespace(String metadataNamespace) {
		this.metadataNamespace = metadataNamespace;
	}
	
	
	
	/**
	 * @return Returns the cifsDisablePlainTextPassword.
	 */
	public String getCifsDisablePlainTextPassword() {
		return cifsDisablePlainTextPassword;
	}
	/**
	 * @param cifsDisablePlainTextPassword The cifsDisablePlainTextPassword to set.
	 */
	public void setCifsDisablePlainTextPassword(
			String cifsDisablePlainTextPassword) {
		this.cifsDisablePlainTextPassword = cifsDisablePlainTextPassword;
	}
	/**
	 * @return Returns the cifsDomain.
	 */
	public String getCifsDomain() {
		return cifsDomain;
	}
	
	
	
	
	/**
	 * @param cifsDomain The cifsDomain to set.
	 */
	public void setCifsDomain(String cifsDomain) {
		this.cifsDomain = cifsDomain;
	}
	/**
	 * @return Returns the cifsResolveOrder.
	 */
	public String getCifsResolveOrder() {
		return cifsResolveOrder;
	}
	/**
	 * @param cifsResolveOrder The cifsResolveOrder to set.
	 */
	public void setCifsResolveOrder(String cifsResolveOrder) {
		this.cifsResolveOrder = cifsResolveOrder;
	}
	/**
	 * @return Returns the actionType.
	 */
	public String getActionType() {
		return actionType;
	}
	/**
	 * @param actionType The actionType to set.
	 */
	public void setActionType(String actionType) {
		this.actionType = actionType;
	}
	/**
	 * @return Returns the serverType.
	 */
	public String getServerType() {
		return serverType;
	}
	/**
	 * @param serverType The serverType to set.
	 */
	public void setServerType(String serverType) {
		this.serverType = serverType;
	}
	
	/**
	 * @return Returns the aclUportalGroup.
	 */
	public String getAclUportalGroup() {
		return aclUportalGroup;
	}
	/**
	 * @param aclUportalGroup The aclUportalGroup to set.
	 */
	public void setAclUportalGroup(String aclUportalGroup) {
		this.aclUportalGroup = aclUportalGroup;
	}
	/**
	 * @return Returns the aclGroupPrefix.
	 */
	public String getAclGroupPrefix() {
		return aclGroupPrefix;
	}
	/**
	 * @param aclGroupPrefix The aclGroupPrefix to set.
	 */
	public void setAclGroupPrefix(String aclGroupPrefix) {
		this.aclGroupPrefix = aclGroupPrefix;
	}
	/**
	 * @return Returns the aclNamespace.
	 */
	public String getAclNamespace() {
		return aclNamespace;
	}
	/**
	 * @param aclNamespace The aclNamespace to set.
	 */
	public void setAclNamespace(String aclNamespace) {
		this.aclNamespace = aclNamespace;
	}
	/**
	 * @return Returns the supportAcl.
	 */
	public boolean supportsAcl() {
		if (aclNamespace==null || aclUserPrefix == null || aclGroupPrefix == null)
			return false;				
		else return true;			
	}
	
	/**
	 * @return Returns the aclUserPrefix.
	 */
	public String getAclUserPrefix() {
		return aclUserPrefix;
	}
	/**
	 * @param aclUserPrefix The aclUserPrefix to set.
	 */
	public void setAclUserPrefix(String aclUserPrefix) {
		this.aclUserPrefix = aclUserPrefix;
	}
	/**
	 * @return Returns the personnalSpace.
	 */
	public boolean isPersonnalSpace() {
		return personnalSpace;
	}
	/**
	 * @param personnalSpace The personnalSpace to set.
	 */
	public void setPersonnalSpace(boolean personnalSpace) {
		this.personnalSpace = personnalSpace;
	}
	/**
	 * If the selected authentication is CAS
	 * @return trus is cas is selected
	 */
	public boolean isCasAuthentication() throws PropertiesException {
		if (authenticationMode==null) {
			log.error("isCasAuthentication :: there is no authentication mode set for space "+getKey());
			throw new PropertiesException();
		}
		return authenticationMode.equals(AUTH_CAS);
	}
	/**
	 * If the selected authentication is TRUSTED
	 * @return true if trusted is selected
	 */
	public boolean isTrustedAuthentication() throws PropertiesException {
		if (authenticationMode==null) {
			log.error("isTrustedAuthentication :: there is no authentication mode set for space "+getKey());
			throw new PropertiesException();
		}
		return authenticationMode.equals(AUTH_TRUSTED);
	}
	/**
	 * If the selected authentication is ASKED
	 * @return true if asked is selected
	 */
	public boolean isAskedAuthentication() throws PropertiesException {
		if (authenticationMode==null) {
			log.error("isAskedAuthentication :: there is no authentication mode set for space "+getKey());
			throw new PropertiesException();
		}
		return authenticationMode.equals(AUTH_ASKED);
	}
	/**
	 * @return Returns the login.
	 */
	public String getLogin() {
		return login;
	}
	/**
	 * @param login The login to set.
	 */
	public void setLogin(String login) {
		this.login = login;
	}
	/**
	 * @return Returns the password.
	 */
	public String getPassword() throws PropertiesException {
		if (isTrustedAuthentication() && password==null) {
			log.error("getPassword :: there is no password set for trusted authentication for space "+getKey());
			throw new PropertiesException();
		}
		return password;
	}
	/**
	 * @param password The trustedPassword to set.
	 */
	public void setPassword(String password) {
		this.password = password;
	}
	/**
	 * @return Returns the url.
	 */
	public String getUrl() throws PropertiesException {
		if (url==null) {
			log.error("getUrl :: there is no URL set for space "+getKey());
			throw new PropertiesException();
		}
		return url;
	}
	/**
	 * @param url The url to set.
	 */
	public void setUrl(String url) {
		this.url = url;
	}
	/**
	 * @param authenticationMode The authenticationMode to set.
	 */
	public void setAuthenticationMode(String authenticationMode) {
		this.authenticationMode = authenticationMode;
	}
	
	
	
	/**
	 * @return Returns the serverAccessClass.
	 */
	public String getServerAccessClass() {
		return serverAccessClass;
	}
	/**
	 * @param serverAccessClass The serverAccessClass to set.
	 */
	public void setServerAccessClass(String serverAccessClass) {
		this.serverAccessClass = serverAccessClass;
	}
	
	

	/**
	 * @return Returns the accessClass.
	 */
	public String getChannelActionClass() {
		return channelActionClass;
	}
	/**
	 * @param channelActionClass The channelActionClass to set.
	 */
	public void setChannelActionClass(String channelActionClass) {
		this.channelActionClass = channelActionClass;
	}
	
	
	
	/**
	 * @return Returns the key.
	 */
	public String getKey() {
		return key;
	}
	
	/**
	 * @param key The key to set.
	 */
	public void setKey(String key) {
		this.key = key;
	}
	
	/**
	 * @return Returns the label.
	 */
	public String getLabel() {
		return label;
	}
	
	/**
	 * @param label The label to set.
	 */
	public void setLabel(String label) {
		this.label = label;
	}
	
	
	/**
	 * @param path The path to set.
	 */
	public void setPath(String path) {
		//this.path = path;
		
		currentPath = new Vector();		
		
		String initPath = new String(path);		
		if (initPath.startsWith("/"))
			initPath = initPath.substring(1, initPath.length());		
		if (initPath.endsWith("/"))
			initPath = initPath.substring(0, initPath.length()-1);
				
		// we add it to the currentPath
		currentPath.addElement(initPath);	
	}
		
	
	/**
	 * @return Returns the path.
	 */
	public String getPath() {	
		return getPath(currentPath);				
	}
	
	
	/**
	 * Return the path due to a current path vector
	 * @param currentPath
	 * @return the space current path
	 */
	private String getPath(Vector currentPath) {
		StringBuffer pathh = new StringBuffer("/"); 
		for (int i=0; i<currentPath.size(); i++) {
			String s = (String)currentPath.elementAt(i);
			if (!s.equals("")) {
				pathh.append(s);
				pathh.append("/");
			}			
		}
		
		return pathh.toString();	
	}
	
		
	/**
	 * We check if the is a {...} form in the path. If yes, we replace by the real value
	 * @param person the connected person
	 * @param trustedAttributeName if there is a trusted attribute, this is the name of this one
	 * @param trustedAttributeValue if there is a trusted attribute, this is the value of this one
	 */
	/*public void checkPath(IPerson person, String trustedAttributeName, String trustedAttributeValue) {
		
		// we fix the currentPath
		
		for (int i=0; i<currentPath.size(); i++) {
			String s = (String)currentPath.elementAt(i);
			
			int firstIndex = s.indexOf("{");
			int lastIndex = s.indexOf("}");
			
			if (firstIndex!=-1 && lastIndex!=-1) {
			
				String begin = s.substring(0, firstIndex);
				String med = s.substring(firstIndex+1, lastIndex);
				String end = s.substring(lastIndex+1, s.length());
				
				String realMedValue = "";
				// if we have a trusted attribute
				if (med.equals(trustedAttributeName))
					realMedValue = trustedAttributeValue;
				else realMedValue = (String)person.getAttribute(med);
				
				String newString = begin+realMedValue+end;								
				
				currentPath.setElementAt(newString, i);
			}			
		}		
	}*/
	
	
	
	
	/**
	 * We check if the is a {...} form in the path. If yes, we replace by the real value
	 * @param person the connected person
	 */
	public void checkPath(IPerson person) {
		
		// we fix the currentPath
		
		for (int i=0; i<currentPath.size(); i++) {
			String s = (String)currentPath.elementAt(i);
			
			int firstIndex = s.indexOf("{");
			int lastIndex = s.indexOf("}");
			
			if (firstIndex!=-1 && lastIndex!=-1) {
			
				String begin = s.substring(0, firstIndex);
				String med = s.substring(firstIndex+1, lastIndex);
				String end = s.substring(lastIndex+1, s.length());
				
				String realMedValue = (String)person.getAttribute(med);
				
				String newString = begin+realMedValue+end;								
				
				currentPath.setElementAt(newString, i);
			}			
		}		
	}
	
	
	
	
	
	/**
	 * Add a path element to the current directory
	 * @param pathElement
	 */
	public void addPathElement(String pathElement) {
		this.currentPath.add(pathElement);
	}
	
	/**
	 * Remove an element from the current path
	 * @param index
	 */
	public void removePathElement(int index) {
		this.currentPath.remove(index);
	}
	
	/**
	 * Return the path size
	 * @return the size
	 */
	public int getPathSize() {
		return currentPath.size();
	}
		
	/**
	 * Return the current element path at the good index
	 * @param index the selected index
	 * @return a string
	 */
	public String getPathElementAt(int index) {
		if (index == 0)
			return this.label;
		else return (String)this.currentPath.elementAt(index);
	}
		
	
	/**
	 * Check if we are authorized to read this space
	 * @param access the object used to access the server
	 * @return true if authorized else false
	 */
	public boolean canRead(ServerAccess access) {
		try {
			if (access.canRead(this.getPath()))
				return true;
			else return false;
		}
		catch(ChannelException e) {
			return false;
		}
	}		
	
	
	/**
	 * Set the server access object for this space
	 * @return true if we can access this space, else false
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws MalformedURLException
	 * @throws ApplicationException
	 * @throws PropertiesException
	 */
	public boolean setServerAccessObject() throws PropertiesException, ClassNotFoundException, InstantiationException, IllegalAccessException, MalformedURLException, ApplicationException{
		
		if (serverAccessClass==null) {
			log.error("setServerAccessObject :: wrong server type for space "+getKey());
			return false;
		}
		
		// construct the object
		Class c = Class.forName(serverAccessClass);
		access = (ServerAccess)c.newInstance();
				
		access.init(this);

		// add the current server hierarchy path
		String serverCurrentHierPath = access.getServerCurrentHierPath();		
		setPath(serverCurrentHierPath);
		
		
		// if the authentication is "asked", we don't try to connect
		if (isAskedAuthentication())
			return true;
		
		// try to connect
		try {
			access.connect();			
		}
		catch(ServerException e) {			

			// log
			if (log.isDebugEnabled()){
				log.debug("setServerAccessObject"+" :: "+e);
			}
			
			return false;
		}
		catch(BadConnexionParameters e) {

			// log
			if (log.isDebugEnabled()){
				log.debug("setServerAccessObject"+" :: "+e);
			}
			
			return false;
		}
		
		// if it is valid
		boolean valid = access.canRead(getPath());
		
		// disconnect
		try {
			access.disconnect();			
		}
		catch(ServerException e) {

			// log
			if (log.isDebugEnabled()){
				log.debug("setServerAccessObject"+" :: "+e);
			}
			
		}
		
		return valid;
	}
	
	
	
	/**
	 * Return the object used to access the server
	 * @return the object used to access the server
	 */
	public ServerAccess getServerAccessObject() {
		return this.access;
	}
	
	
	/**
	 * Set the server access object
	 * @param access
	 */
	public void setServerAccessObject(ServerAccess access) {
		this.access = access;
	}
	
	
	/**
	 * Set the object used to manage the actions of the channel
	 * @param spaces the spaces used
	 * @param config the config class
	 * @param buffer the buffer used to get for example the clipboard
	 * @param userPortalLogin The user login in the portal
	 * @param userGroups The groups of the user in the portal
	 * @return true if well done
	 */
	public boolean setChannelActionObject(ArrayList spaces, ChannelConfiguration config, BufferAction buffer, String userPortalLogin, Vector userGroups) throws ChannelException {
		
		try {
			
			if (this.channelActionClass==null)
				this.channelActionClass = "org.esupportail.portal.channels.CStockage.channelAction.webdav.ChannelAction";				
			
			Class classe = Class.forName(this.channelActionClass);
			Object obj = classe.newInstance();
			
			this.channelAction = (AbstractChannelAction)obj;
			this.channelAction.init(this, spaces, config, buffer, userPortalLogin, userGroups);
			
		}
		catch(ClassNotFoundException e) {
			log.error("setChannelActionObject"+" :: "+e);			
			return false;
		}
		catch(IllegalAccessException e) {
			log.error("setChannelActionObject"+" :: "+e);	
			return false;
		}
		catch(InstantiationException e) {
			log.error("setChannelActionObject"+" :: "+e);	
			return false;
		}
		return true;
	}
	
	
	
	/**
	 * Get the channel action object
	 * @return the channel action object
	 */
	public AbstractChannelAction getChannelActionObject() {
		return this.channelAction;
	}
	
	
	
	
	/**
	 * Return a String representation of this space
	 */
	public String toString() {
		return 
		"key: "+key+"\n"+
		"label: "+label+"\n"+
		"path: "+getPath()+"\n";
	}
	
	
}
