/*
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.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.provider.access.ServerAccess;
import org.jasig.portal.security.IPerson;



/**
 * Id: Server.java,v 1.0 14 avril 2005<br/>
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)<br/>
 * Classes: Server<br/>
 * Original Author: Yohan Colmant<br/>
 * This represents a server in the configuration file<br/>
 */
public class Server {


	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(Server.class);
	



	/**
	 * CAS authentication
	 */
	private static final String AUTH_CAS = "cas";
	
	/**
	 * TRUSTED authentication
	 */
	private static final String AUTH_TRUSTED = "trusted";
	
	/**
	 * ASKED authentication
	 */
	private static final String AUTH_ASKED = "asked";
	
	
	/**
	 * The spaces list into this server
	 */
	private ArrayList spaces = new ArrayList();
	
	/**
	 * The name of the server
	 */
	private String name;
	
	/**
	 * The server id
	 */
	private String id;
	
	/**
	 * The server url
	 */
	private String url;
	
	/**
	 * The server type
	 */
	private String serverType;

	/**
	 * The authentication mode. "cas" or "trusted"
	 */
	private String authenticationMode;
	
	/**
	 * The login if trusted authentication
	 */
	private String login;

	/**
	 * The login if trusted authentication
	 */
	private String initialLoginFromTheConfigurationFile;
	
	/**
	 * If the login is from the configuration file
	 */
	private boolean loginIsFromConfigurationFile = false;
	
	
	/**
	 * The password if trusted authentication, or is asked authentication
	 */
	private String password;


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

	
	/**
	 * The parameters
	 */
	private Hashtable parameters = new Hashtable();
	
	/**
	 * The groups we want to hide in the tree of sharing
	 */
	private Vector aclHiddenGroupsInTree;
	
	

	/**
	 * @return Returns the parameters.
	 */
	public Hashtable getParameters() {
		return parameters;
	}
	/**
	 * @param name the name of the parameter
	 * @return Returns the parameter.
	 */
	public String getParameterValue(String name) {
		Parameter param = (Parameter)parameters.get(name);
		if (param == null)
			return null;
		else return param.getValue();
	}
	
	/**
	 * @param name the name of the parameter
	 * @return Returns the parameter.
	 */
	public Parameter getParameter(String name) {
		return (Parameter)parameters.get(name);
	}
	
	/**
	 * @param space The space to set.
	 */
	public void addParameter(Parameter parameter) {
		parameters.put(parameter.getName(), parameter);
	}
	
	
	
	/**
	 * @return Returns the spaces.
	 */
	public ArrayList getSpaces() {
		return spaces;
	}
	/**
	 * @param space The space to set.
	 */
	public void addSpace(Space space) {
		spaces.add(space);
	}
	/*public void initSpaces() {
		spaces = null;
	}*/
	/**
	 * @param spaces The spaces to set.
	 */
	public void setSpaces(ArrayList spaces) {
		this.spaces = spaces;
	}
	
	
	
	

	/**
	 * @return Returns the aclSecurity.
	 */
	public String getAclSecurity() {
		
		if (getParameterValue(ServerConstants.ACL_SECURITY)==null) {
			if (log.isDebugEnabled()) {
				log.debug("getAclSecurity"+" :: getAclSecurity is null");
			}
		}
		return getParameterValue(ServerConstants.ACL_SECURITY);
	}
	
	
	
	/**
	 * @return the aclHiddenGroupsInTree
	 */
	public Vector getAclHiddenGroupsInTree() {
		if (aclHiddenGroupsInTree==null) {
			this.aclHiddenGroupsInTree = new Vector();
		}
		
		String hidden = getParameterValue(ServerConstants.ACL_HIDDEN_GROUPS_IN_TREE);
		if (hidden!=null) {
			String[] hiddenTab = hidden.split(",");
			for (int i=0; hiddenTab!=null && i<hiddenTab.length; i++) {
				String element = hiddenTab[i];
				if (!element.startsWith("/")) {
					element = "/"+element;
				}
				if (!element.endsWith("/")) {
					element = element+"/";
				}
				this.aclHiddenGroupsInTree.addElement(element);
			}
		}
		
		return aclHiddenGroupsInTree;
	}
	
	
	
	/**
	 * @return Returns the manageAcl.
	 */
	public boolean managesAcl() {		
		boolean parametersSet = hasAclParameterSet() && manageAcl.equals("true");
		if (!parametersSet) {
			log.debug("managesAcl :: there is no acl access parameters set for space "+getId());
			return false;
		}
		return parametersSet;
	}
	
	
	
	String manageAcl = "true";
	
	public String getManageAcl() {		
		return managesAcl()+"";
	}
	
	public void setManageAcl(String manageAcl) {		
		this.manageAcl = manageAcl;
	}
	
	

	/**
	 * @return check if the server allow the personalization
	 */
	public boolean allowsPersonalization() throws PropertiesException {		
		boolean managesAcl = managesAcl();
		boolean spacesPersonalization = ChannelConfiguration.getInstance().isSpacesPersonalization();
		if (!managesAcl && spacesPersonalization) {
			log.debug("allowPersonalization :: there is no acl access parameters set for space "+getId());
			return false;
		}
		return managesAcl && spacesPersonalization;
	}
	
	
	
	/**
	 * @return Returns the name.
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name The name to set.
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	
	/**
	 * @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 aclGroupPrefix.
	 */
	public String getAclGroupPrefix() {
		String prefix = getParameterValue(ServerConstants.ACL_GROUP_PREFIX);
		
		String oldUportalPrefixParameter = getParameterValue(ServerConstants.ACL_UPORTAL_GROUP);
		if (oldUportalPrefixParameter!=null && !oldUportalPrefixParameter.trim().equals("")) {
			prefix = prefix + oldUportalPrefixParameter+"/";
		}
		
		return prefix;
	}
	
	/**
	 * @return Returns the aclNamespace.
	 */
	public String getAclNamespace() {
		return getParameterValue(ServerConstants.ACL_NAMESPACE);
	}
	
	/**
	 * @return Returns the supportAcl.
	 */
	public boolean hasAclParameterSet() {
		if (getParameterValue(ServerConstants.ACL_NAMESPACE)==null || getParameterValue(ServerConstants.ACL_USER_PREFIX) == null || getParameterValue(ServerConstants.ACL_GROUP_PREFIX) == null || getParameterValue(ServerConstants.ACL_SECURITY) == null)
			return false;				
		else return true;			
	}
	
	/**
	 * @return Returns the aclUserPrefix.
	 */
	public String getAclUserPrefix() {
		return getParameterValue(ServerConstants.ACL_USER_PREFIX);
	}
	
	
	/**
	 * 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 "+getId());
			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 "+getId());
			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 "+getId());
			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;
	}
	/**
	 * @param initialLoginFromTheConfigurationFile The login to set.
	 */
	public void setInitialLoginFromTheConfigurationFile(String initialLoginFromTheConfigurationFile) {
		this.login = initialLoginFromTheConfigurationFile;
		this.initialLoginFromTheConfigurationFile = new String(initialLoginFromTheConfigurationFile);
		this.loginIsFromConfigurationFile = true;
	}
	
	
	/**
	 * @return Returns the loginIsFromConfigurationFile.
	 */
	public boolean isLoginIsFromConfigurationFile() {
		return loginIsFromConfigurationFile;
	}
	
	/**
	 * @return Returns the initialLoginFromTheConfigurationFile.
	 */
	public String getInitialLoginFromTheConfigurationFile() {
		return initialLoginFromTheConfigurationFile;
	}
	/**
	 * @param loginIsFromConfigurationFile The loginIsFromConfigurationFile to set.
	 */
	/*public void setLoginIsFromConfigurationFile(
			boolean loginIsFromConfigurationFile) {
		this.loginIsFromConfigurationFile = loginIsFromConfigurationFile;
	}*/
	/**
	 * @return Returns the login used with this space.
	 */
	/*public String getUsedLogin() {
		if (trustedLogin!=null)
			return trustedLogin;
		else return usedLogin;
	}*/	
	/**
	 * @param usedLogin The usedLogin to set.
	 */
	/*public void setUsedLogin(String usedLogin) {
		this.usedLogin = usedLogin;
	}*/
	
	
	
	/**
	 * @return Returns the trustedLogin.
	 */
	/*public String getTrustedLogin() {
		return trustedLogin;
	}*/
	/**
	 * @param trustedLogin The trustedLogin to set.
	 */
	/*public void setTrustedLogin(String trustedLogin) {
		this.trustedLogin = trustedLogin;
	}*/
	
	
	
	/**
	 * @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 "+getId());
			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 "+getId());
			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 authenticationMode.
	 */
	public String getAuthenticationMode() {
		return 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 id.
	 */
	public String getId() {
		return id;
	}
	
	/**
	 * @param id The id to set.
	 */
	public void setId(String id) {
		this.id = id;
	}
	
	
	
	
	
	
	
	
	/**
	 * we look for a {...} form in the attribute. If yes, we replace it with the real value
	 * @param attributeName to check 
	 * @param person uPortal person object
	 */
	public void checkAttribute(String attributeName, IPerson person) {
		
		Class c = this.getClass();
		String value;
		try {
			// we use java refexion to find getter and setter for attributeName
		    BeanInfo bi = Introspector.getBeanInfo(c);
		    PropertyDescriptor[] propertyDescriptor = bi.getPropertyDescriptors();
		    for (int i=0; i<propertyDescriptor.length; i++) {
		    	if (propertyDescriptor[i].getName().equals(attributeName)) {
		    		Method method = propertyDescriptor[i].getReadMethod();
		    		value = (String)method.invoke(this, new Object[0]);
		    		
					if (value!=null) {
						// find and replace {...}
						int firstIndex = value.indexOf("{");
						int lastIndex = value.indexOf("}");
						
						if (firstIndex!=-1 && lastIndex!=-1) {
						
							String begin = value.substring(0, firstIndex);
							String med = value.substring(firstIndex+1, lastIndex);
							String end = value.substring(lastIndex+1, value.length());
							
							String realMedValue = (String)person.getAttribute(med);
							
							String newString = begin+realMedValue+end;								
							
							method = propertyDescriptor[i].getWriteMethod();
							Object[] arg = {newString};
							method.invoke(this, arg);
							if (log.isDebugEnabled()){
								log.debug("checkAttribute"+" :: replace "+attributeName+" value "+value+" with "+newString);
							}

						}	
						
					}
		    		// no more nead to scan propertyDescriptor[] --> exit for statement
		    		i = propertyDescriptor.length;
		    	}
		    }
		}
		catch (InvocationTargetException e) {
			log.error("checkAttribute"+" :: "+e, e);			
		}
		catch (IntrospectionException e) {
			log.error("checkAttribute"+" :: "+e, e);			
		}
		catch (IllegalAccessException e) {
			log.error("checkAttribute"+" :: "+e, e);			
		}
	}
	
	
	

	

	/**
	 * init the server access object for this space
	 * @param person the uportal person object
	 * @throws MalformedURLException
	 * @throws PropertiesException
	 */
	public void initServerAccessObjectForEachSpace(IPerson person) throws MalformedURLException, PropertiesException, IllegalAccessException, InstantiationException, ApplicationException, ClassNotFoundException {
		for (int i=0; spaces!=null && i<spaces.size(); i++) {
			Space space = (Space)spaces.get(i);
			
			space.checkPath(person);
			
			ServerAccess sao = space.getServerAccessObject();
			if (sao==null) {
				space.setServerAccessObject();
				sao = space.getServerAccessObject();
			}
			//System.out.println("initServerAccessObjectForEachSpace:: sao="+sao);
			sao.init(space);
		}
	}
	
	
	
	/**
	 * Compare this to another object
	 * @param o object to compare
	 */
	public boolean equals(Object o) {
		
		Server server = (Server)o;
		
		if ( ( (server.url==null) && (server.url!=this.url) ) || ( (server.url!=null) && (!server.url.equals(this.url)) ) )
			return false;
		
		if ( ( (server.serverType==null) && (server.serverType!=this.serverType) ) || ( (server.serverType!=null) && (!server.serverType.equals(this.serverType)) ) )
			return false;
		
		if ( ( (server.serverAccessClass==null) && (server.serverAccessClass!=this.serverAccessClass) ) || ( (server.serverAccessClass!=null) && (!server.serverAccessClass.equals(this.serverAccessClass)) ) )
			return false;
		
		if ( ( (server.authenticationMode==null) && (server.authenticationMode!=this.authenticationMode) ) || ( (server.authenticationMode!=null) && (!server.authenticationMode.equals(this.authenticationMode)) ) )
			return false;
		
		if ( ( (server.login==null) && (server.login!=this.login) ) || ( (server.login!=null) && (!server.login.equals(this.login)) ) )
			return false;
		
		if (server.loginIsFromConfigurationFile != this.loginIsFromConfigurationFile)
			return false;
		
		if ( ( (server.initialLoginFromTheConfigurationFile==null) && (server.initialLoginFromTheConfigurationFile!=this.initialLoginFromTheConfigurationFile) ) || ( (server.initialLoginFromTheConfigurationFile!=null) && (!server.initialLoginFromTheConfigurationFile.equals(this.initialLoginFromTheConfigurationFile)) ) )
			return false;
		
		if ( ( (server.password==null) && (server.password!=this.password) ) || ( (server.password!=null) && (!server.password.equals(this.password)) ) )
			return false;
		
		if ( !server.parameters.equals(this.parameters) )
			return false;
		
		
		
		return true;
	}
	
	
	
	

	
	/**
	 * Return a String representation of this space
	 */
	public String toString() {
		return 
		"id: "+id+"\n"+
		"url: "+url;
	}
	
	
	
	
	/**
	 * Clone this object
	 * @return a clone of this object
	 */
	public Object clone() {
		Server server = new Server();
		
		if (spaces!=null) {
			ArrayList spacesClone = new ArrayList(spaces.size());
			for (int i=0; i<spaces.size(); i++) {
				Space spaceClone = (Space)((Space)spaces.get(i)).cloneWithoutServer();
				spaceClone.setServer(server);
				spacesClone.add(spaceClone);
			}
			server.spaces = spacesClone;
		}
		
		
		server.name = this.name;
		
		server.id = this.id;
		server.url = this.url;
		server.serverType = this.serverType;
		server.serverAccessClass = this.serverAccessClass;
		server.authenticationMode = this.authenticationMode;
		server.login = this.login;
		server.loginIsFromConfigurationFile = this.loginIsFromConfigurationFile;
		server.initialLoginFromTheConfigurationFile = this.initialLoginFromTheConfigurationFile;
		server.password = this.password;
		
		if (parameters!=null) {
			Hashtable parametersClone = new Hashtable(spaces.size());
			Enumeration keys = parameters.keys();
			while (keys.hasMoreElements()) {
				Object key = keys.nextElement();
				Parameter p = (Parameter)parameters.get(key);
				Parameter pClone = (Parameter)p.clone();
				parametersClone.put(key, pClone);
			}
			server.parameters = parametersClone;
		}
		
		return server;
	}
	
	
	

	/**
	 * Get the xml in the configuration file style
	 * @return the xml in the configuration file style
	 */
	public StringBuffer getLocalXmlBegin() {
		
		StringBuffer xmlServer = new StringBuffer();		
		xmlServer.append("<SERVER");
		
		// url
		try {
			String url = this.getUrl();
			if (url!=null && !url.trim().equals(""))
				xmlServer.append(" url=\""+url+"\"\n");
		}
		catch(PropertiesException e) {
			if (log.isDebugEnabled())
				log.error("getXml :: " + e.toString(), e);
		}

		// serverType
		String serverType = this.getServerType();
		if (serverType!=null && !serverType.trim().equals(""))
			xmlServer.append(" serverType=\""+serverType+"\"\n");

		// authenticationMode
		String authenticationMode = this.getAuthenticationMode();
		if (authenticationMode!=null && !authenticationMode.trim().equals(""))
			xmlServer.append(" authenticationMode=\""+authenticationMode+"\"\n");

		// login
		try {
			if (this.isTrustedAuthentication() || this.isAskedAuthentication()) {

				if (this.isLoginIsFromConfigurationFile()) {
					String login = this.getInitialLoginFromTheConfigurationFile();
					if (login!=null && !login.trim().equals(""))
						xmlServer.append(" login=\""+login+"\"\n");
				}
				
			}
		}
		catch(PropertiesException e) {
			if (log.isDebugEnabled())
				log.error("getXml :: " + e.toString(), e);
		}
		
		// password
		try {
			if (this.isTrustedAuthentication()) {
				try {				
					String trustedPassword = this.getPassword();
					if (trustedPassword!=null && !trustedPassword.trim().equals(""))
						xmlServer.append(" password=\""+trustedPassword+"\"\n");
				}
				catch(PropertiesException e) {
					if (log.isDebugEnabled())
						log.error("getXml :: " + e.toString(), e);
				}
			}
		}
		catch(PropertiesException e) {
			if (log.isDebugEnabled())
				log.error("getXml :: " + e.toString(), e);
		}
		
		// manageAcl
		/*boolean manageAcl = this.managesAcl();
		xmlServer.append(" manageAcl=\""+manageAcl+"\"\n");*/
		

		// aclNamespace
		/*String aclNamespace = this.getAclNamespace();
		if (aclNamespace!=null && !aclNamespace.trim().equals(""))
			xmlServer.append(" aclNamespace=\""+aclNamespace+"\"\n");

		// aclUserPrefix
		String aclUserPrefix = this.getAclUserPrefix();
		if (aclUserPrefix!=null && !aclUserPrefix.trim().equals(""))
			xmlServer.append(" aclUserPrefix=\""+aclUserPrefix+"\"\n");

		// aclGroupPrefix
		String aclGroupPrefix = this.getAclGroupPrefix();
		if (aclGroupPrefix!=null && !aclGroupPrefix.trim().equals(""))
			xmlServer.append(" aclGroupPrefix=\""+aclGroupPrefix+"\"\n");
		
		// aclUportalGroup
		String aclUportalGroup = this.getAclUportalGroup();
		if (aclUportalGroup!=null && !aclUportalGroup.trim().equals(""))
			xmlServer.append(" aclUportalGroup=\""+aclUportalGroup+"\"\n");

		// aclSecurityGroup
		String aclSecurity = this.getAclSecurity();
		if (aclSecurity!=null && !aclSecurity.trim().equals(""))
			xmlServer.append(" aclSecurity=\""+aclSecurity+"\"\n");*/
		
		xmlServer.append(" >\n");
		
		// parameters
		Iterator params = parameters.values().iterator();
		while(params.hasNext()) {
			Parameter param = (Parameter)params.next();
			xmlServer.append(" <PARAMETER name=\""+param.getName()+"\" value=\""+param.getValue()+"\"/>\n");
		}
		
		return xmlServer;
		
	}
	
	
	
	

	/**
	 * Get the xml in the configuration file style
	 * @return the xml in the configuration file style
	 */
	public StringBuffer getLocalXmlEnd() {
		return new StringBuffer("</SERVER>\n");
		
	}
	
	

	/**
	 * Get the xml in the configuration file style
	 * @return the xml in the configuration file style
	 */
	public String getXml() {
		
		StringBuffer xml = new StringBuffer();
		
		xml.append(getLocalXmlBegin());
		
		for (int i=0; i<this.spaces.size(); i++) {
			Space s = (Space)spaces.get(i);
			xml.append(s.getLocalXml());
		}
		
		xml.append(getLocalXmlEnd());
		
		return xml.toString();
	}
	
}
