/*
 * injacSpacesCreation.java,v 1.0 20 juil. 2004
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)
 * Classes: injacSpacesCreation.java
 * Original Author: Thomas Bellembois
 */
/**
 * @author : Thomas Bellembois
 * date : 20 juil. 2004
 */

package org.esupportail.portal.utils.injac.injacSpacesCreation;

import java.io.IOException;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.URIException;
import org.apache.log4j.Logger;
import org.apache.webdav.lib.Property;
import org.apache.webdav.lib.PropertyName;
import org.apache.webdav.lib.WebdavResource;
import org.apache.webdav.lib.methods.DepthSupport;
import org.apache.webdav.lib.methods.PropFindMethod;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.esupportail.portal.utils.injac.injacSpacesCreation.config.Config;
import org.esupportail.portal.utils.injac.injacSpacesCreation.exception.ConfigException;
import org.esupportail.portal.utils.injac.injacSpacesCreation.exception.WrongPathException;
import org.esupportail.portal.utils.injac.tools.ACLManager;

/**
 * THE FILE config.xml configures this application, read it with attention !<br/>
 * 
 * injacSpacesCreation [spaceName] [authors] [editors]<br/>
 * [authors] = user1:user2:user3...<br/>
 * [editors] = user1:user2:user3...<br/>
 * 
 * action of the script :<br/>
 * Variables between {} are defined in the configuration file : /properties/config.xml<br/>
 *
 * 1> Create two directories : /{injacPath}/{editorSpacesPath}/[spaceName]<br/>
 *                             /{injacPath}/{publicationSpacesPath}/[spaceName]<br/>
 * 
 * 2> Create the role {AuthorsGroupPrefix}[spaceName]<br/>
 *    Add the authors [authors] to this role<br/>
 *    Grant write and read for this role to /{injacPath}/{editorSpacesPath}/[spaceName]<br/>
 * 
 * 3> Create the role {EditorsGroupPrefix}[spaceName]<br/>
 *    Add the editors [editors] to this role<br/>
 *    Grant write and read for this role to /{injacPath}/{publicationSpacesPath}/[spaceName]<br/>
 *    Grant read for this role to /{injacPath}/{editorSpacesPath}/[spaceName]
 * 
 */

public class InjacSpacesCreation {
	
	private static String EDITOR_SPACE = "editorSpace";
	private static String PUBLICATION_SPACE = "publicationSpace";
	
	private HttpURL httpUrl;
	private WebdavResource webDavResource;
	private String context;
	
	private ACLManager aclManager;
	
	private String injacPath;
	private String editorSpacesPath;
	private String publicationSpacesPath;
	private String authorsGroupPrefix;
	private String editorsGroupPrefix;
	
	private String webdavServerUrl;
	private String webdavServerLogin;
	private String webdavServerPassword;
	private String webdavServerUsersRole;
	
	private String userDirectoryRootDirectory;
	
	private String roleDirectoryRootDirectory;
	
	private Logger logger = Logger.getLogger("InJacSpacesCreation");
	
	/**
	 * Get a ressource property
	 * @param webdavResource
	 * @param path
	 * @param properties
	 * @return Property Enumeration
	 * @throws URIException
	 * @throws IOException
	 */
	private Enumeration getProperty(WebdavResource webdavResource, String path, Vector properties) throws URIException, IOException {
		PropFindMethod method = new PropFindMethod(path, DepthSupport.DEPTH_INFINITY, properties.elements());
		webdavResource.retrieveSessionInstance().executeMethod(method);
		return method.getResponseProperties(path);
	}// getProperty
	
	/**
	 * Initialize all the variables and connect to the WebDAV server
	 */
	private void init(){ // context == /slide for example
		try{
			webdavServerUrl = Config.getInstance().getWebdavServerUrl();		     // WebDav server URL
			webdavServerLogin = Config.getInstance().getWebdavServerLogin();	     // WebDav server login
			webdavServerPassword = Config.getInstance().getWebdavServerPassword();   // WebDav server password
			webdavServerUsersRole = Config.getInstance().getWebdavServerUsersRole(); //Role assigned to users
			
			userDirectoryRootDirectory = Config.getInstance().getUserDirectoryRootDirectory(); // Root directory to create homedirs on the WebDav server
			roleDirectoryRootDirectory = Config.getInstance().getRoleDirectoryRootDirectory(); // Root directory to create roles on the WebDav server
			
			editorSpacesPath = Config.getInstance().getEditorSpacesPath();
			publicationSpacesPath = Config.getInstance().getPublicationSpacesPath();
			authorsGroupPrefix = Config.getInstance().getAuthorsGroupPrefix();
			editorsGroupPrefix = Config.getInstance().getEditorsGroupPrefix();
			
			aclManager = new ACLManager(webdavServerUrl+"/", webdavServerLogin, webdavServerPassword);
			
			// Connecting to the Webdav server
			httpUrl = new HttpURL(webdavServerUrl+"/");
			httpUrl.setUserinfo(webdavServerLogin, webdavServerPassword);
			context = httpUrl.getCurrentHierPath();
			webDavResource = new WebdavResource(httpUrl);
			logger.info("Connected to "+webDavResource.getPath());
			
			injacPath = context+"/"+Config.getInstance().getInjacPath();
			//userDirectoryRootDirectory = context+"/"+Config.getInstance().getUserDirectoryRootDirectory(); // Root directory to create homedirs on the WebDav server
			//roleDirectoryRootDirectory = context+"/"+Config.getInstance().getRoleDirectoryRootDirectory(); // Root directory to create roles on the WebDav server
			
		}
		catch (ConfigException configException){logger.info("InjacSpacesCreation::init::"+configException);}
		catch (HttpException httpException){logger.info("InjacSpacesCreation::init::"+httpException);}
		catch (IOException ioException){logger.info("InjacSpacesCreation::init::"+ioException);}
	}// init
	
	/**
	 * Verify if the WebDAV ressource exits
	 * @param webDavResource
	 * @param path syntax: /{context}/path - exemple: /slide/files/myRessource
	 * @return true if the path exists, else false
	 */
	private boolean pathExist(WebdavResource webDavResource, String path){
		try {
			webDavResource.setPath(path);
		} catch (HttpException httpException) {
			return false;
		} catch (IOException ioException) {
			logger.info("InjacSpacesCreation::pathExist::"+ioException);
		}
		return true;
	}// isExist
	
	/**
	 * Create an Injac space with the specified type.
	 * spaceType = EDITOR_SPACE
	 * spaceType = PUBLICATION_SPACE
	 * @param webDavResource
	 * @param spaceName the name of the space to create
	 * @param spaceType the type of the space to create
	 * @throws WrongPathException
	 */
	private void createInjacSpace(WebdavResource webDavResource, String spaceName, String spaceType) throws WrongPathException{
		try{
			String spacePath = null;
			
			// Verify if the spaces root directories exist (must be created by the administrator) - create the new space
			if(spaceType.equals(EDITOR_SPACE)){
				if (!pathExist(webDavResource,injacPath+"/"+editorSpacesPath)){
					throw new WrongPathException("InjacSpacesCreation", "createInjacSpace", injacPath+"/"+editorSpacesPath);
				}// if
				spacePath = new String(injacPath+"/"+editorSpacesPath+"/"+spaceName);
				
				if (pathExist(webDavResource, spacePath)){
					logger.error("Space "+spacePath+" already exists !");
					throw new WrongPathException("InjacSpacesCreation", "createInjacSpace", spacePath);
				}// if
				
			}// if
			else if (spaceType.equals(PUBLICATION_SPACE)){
				if (!pathExist(webDavResource,injacPath+"/"+publicationSpacesPath)){
					throw new WrongPathException("InjacSpacesCreation", "createInjacSpace", injacPath+"/"+publicationSpacesPath);
				}// if
				spacePath = new String(injacPath+"/"+publicationSpacesPath+"/"+spaceName);
				
				if (pathExist(webDavResource, spacePath)){
					logger.error("Space "+spacePath+" already exists !");
					throw new WrongPathException("InjacSpacesCreation", "createInjacSpace", spacePath);
				}// if
			}// else
			
			logger.info("Creation of "+spacePath);
			webDavResource.mkcolMethod(spacePath);
		}
		catch(HttpException httpException){logger.info("InjacSpacesCreation::createInjacSpace::"+httpException);}
		catch(IOException ioException){logger.info("InjacSpacesCreation::createInjacSpace::"+ioException);}
		
	}// createHomedir
	
	/**
	 * Create a role
	 * @param webDavResource
	 * @param roleName the name of the role to create
	 * @throws WrongPathException
	 */
	private void createRole(WebdavResource webDavResource, String roleName) throws WrongPathException{
		
		try{
			String rolePath = new String(context+"/"+roleDirectoryRootDirectory+"/"+roleName);
			
			if (pathExist(webDavResource, rolePath)){
				logger.error("Role "+rolePath+" already exists !");
				throw new WrongPathException("InjacSpacesCreation", "createRole", rolePath);
			}// if
			
			logger.info("Creation of "+rolePath);
			webDavResource.mkcolMethod(rolePath);
		}
		catch(HttpException httpException){logger.info("InjacSpacesCreation::create::"+httpException);}
		catch(IOException ioException){logger.info("InjacSpacesCreation::create::"+ioException);}
		
	}// createRole
	
	/**
	 * Add a String Enumeration of users to a role
	 * @param webDavResource
	 * @param roleName the target role
	 * @param userList the String Enumeration of users to add in the role
	 */
	private void addUserToRole(WebdavResource webDavResource, String roleName, Enumeration userList){
		
		try {
			StringBuffer rolePatch = new StringBuffer();
			
			// Getting the current value of the "group-member-set" property
			// --Calling the propFinMethod method
			Vector properties = new Vector();
			String propName = "group-member-set";
			PropertyName property = new PropertyName("DAV:", "group-member-set");
			properties.addElement(property);
			Enumeration propertyValues;
			
			propertyValues = getProperty(webDavResource, context+"/"+roleDirectoryRootDirectory+"/"+roleName, properties);
			
			// --Parsing the answer
			StringBuffer oldGroupMemberSetValue = new StringBuffer("");
			StringReader stringReader;
			SAXReader reader = new SAXReader();
			String currentEntry = new String();
			Document document;
			
			while(propertyValues.hasMoreElements()){
				currentEntry = ((Property)(propertyValues.nextElement())).toString();
				stringReader = new StringReader(currentEntry);
				document = reader.read(stringReader);
				Element element = document.getRootElement();
				
				Iterator iter = element.elementIterator();
				while(iter.hasNext()){
					Element e = (Element)iter.next();
					oldGroupMemberSetValue.append("<D:href xmlns:D='DAV:'>");
					oldGroupMemberSetValue.append(e.getStringValue());
					oldGroupMemberSetValue.append("</D:href>");
				}// while
			}// while	
			
			// Adding the new users to the group-member-set
			String currentUser = null;
			while(userList.hasMoreElements()){
				currentUser = (String)userList.nextElement();
				rolePatch.append("<D:href xmlns:D='DAV:'>");
				rolePatch.append(userDirectoryRootDirectory+"/"+currentUser);
				rolePatch.append("</D:href>");
			}// for
			
			oldGroupMemberSetValue.append(rolePatch);
			rolePatch = oldGroupMemberSetValue;
			
			boolean successPatchRole = webDavResource.proppatchMethod(context+"/"+roleDirectoryRootDirectory+"/"+roleName, new PropertyName("DAV:", "group-member-set"), rolePatch.toString(), true);	
			logger.info(">Proppatch role :"+successPatchRole+"");
			logger.info(rolePatch.toString());	
		} 
		catch (HttpException httpException) {logger.info("InjacSpacesCreation::addUserToRole::"+httpException);}
		catch (IOException ioException) {logger.info("InjacSpacesCreation::addUserToRole::"+ioException);}
		catch (DocumentException documentException) {logger.info("InjacSpacesCreation::addUserToRole::"+documentException);}
	}// addUserToRole
	
	/**
	 * Parse a user list given in parameter of the application
	 * @param userList syntax: user1:user2:user3:...
	 * @return an Enumeration of String with Element1=user1 Element2=user2...
	 */
	private Enumeration parseUserList(String userList){
		Vector userVector = new Vector();
		
		StringTokenizer st = new StringTokenizer(userList, ":", false);
		while (st.hasMoreTokens()) {
			userVector.addElement(st.nextToken());
		}// while
		
		return userVector.elements();
	}// parseUserList
	
	public static void main(String[] args) {
		
		InjacSpacesCreation injacSpacesCreation = new InjacSpacesCreation();
		
		///////////////////////////
		//
		// Verifying the parameters
		//
		if(!(args.length==3)){
			injacSpacesCreation.logger.info("Wrong number of parameters");
			System.exit(0);
		}
		if(args[0].equals("-help")){
			injacSpacesCreation.logger.info("InjacSpacesCreation <spaceName> <authors> <editors>\n"+"<authors> = author1:author2:author3:...\n"+"<editors> = editor1:editor2:editor3:...\n");
			System.exit(0);
		}
		
		String spaceName = args[0];
		String authors = args[1];
		String editors = args[2];
		
		injacSpacesCreation.logger.info("spaceName > "+spaceName);
		injacSpacesCreation.logger.info("authors > "+authors);
		injacSpacesCreation.logger.info("editors > "+editors);
		
		// Initializing variables - conencting to the WebDAV server
		injacSpacesCreation.init();
		
		injacSpacesCreation.logger.info("Starting process...");
		
		try {
			
			// Creating the author and editor spaces
			injacSpacesCreation.createInjacSpace(injacSpacesCreation.webDavResource, spaceName, InjacSpacesCreation.EDITOR_SPACE);
			injacSpacesCreation.createInjacSpace(injacSpacesCreation.webDavResource, spaceName, InjacSpacesCreation.PUBLICATION_SPACE);
			
			// Creating the author and editor roles
			injacSpacesCreation.createRole(injacSpacesCreation.webDavResource, injacSpacesCreation.authorsGroupPrefix+spaceName);
			//--> adding the authors to this role
			injacSpacesCreation.addUserToRole(injacSpacesCreation.webDavResource, injacSpacesCreation.authorsGroupPrefix+spaceName, injacSpacesCreation.parseUserList(authors));
			
			injacSpacesCreation.createRole(injacSpacesCreation.webDavResource, injacSpacesCreation.editorsGroupPrefix+spaceName);
			//--> adding the authors to this role
			injacSpacesCreation.addUserToRole(injacSpacesCreation.webDavResource, injacSpacesCreation.editorsGroupPrefix+spaceName, injacSpacesCreation.parseUserList(editors));
			
			// Positionning the rights
			// Grant write and read for the role {AuthorsGroupPrefix}<spaceName> to /{injacPath}/{editorSpacesPath}/<spaceName>
			injacSpacesCreation.aclManager.grant(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.editorSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.authorsGroupPrefix+spaceName, "read");
			injacSpacesCreation.aclManager.grant(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.editorSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.authorsGroupPrefix+spaceName, "write");
			injacSpacesCreation.aclManager.grant(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.editorSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.editorsGroupPrefix+spaceName, "read");
			injacSpacesCreation.aclManager.deny(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.editorSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.webdavServerUsersRole, "read");
			injacSpacesCreation.aclManager.deny(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.editorSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.webdavServerUsersRole, "write");
			
			// Grant write and read for the role {EditorsGroupPrefix}<spaceName> to /{injacPath}/{publicationSpacesPath}/<spaceName>
			// Grant read for the role {EditorsGroupPrefix}<spaceName> to /{injacPath}/{editorSpacesPath}/<spaceName>
			injacSpacesCreation.aclManager.grant(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.publicationSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.editorsGroupPrefix+spaceName, "read");
			injacSpacesCreation.aclManager.grant(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.publicationSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.editorsGroupPrefix+spaceName, "write");				
			injacSpacesCreation.aclManager.deny(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.publicationSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.webdavServerUsersRole, "read");
			injacSpacesCreation.aclManager.deny(injacSpacesCreation.injacPath+"/"+injacSpacesCreation.publicationSpacesPath+"/"+spaceName, "/"+injacSpacesCreation.roleDirectoryRootDirectory+"/"+injacSpacesCreation.webdavServerUsersRole, "write");
			
			// Disconnecting from the Webdav server
			injacSpacesCreation.webDavResource.close();
			injacSpacesCreation.logger.info("Disconnected from "+injacSpacesCreation.webDavResource.getPath());
			
		}
		catch (WrongPathException e) {injacSpacesCreation.logger.info("InjacSpacesCreation::main::"+e);}
		catch (IOException e2){injacSpacesCreation.logger.info("InjacSpacesCreation::main::"+e2);}
		
	}// main
}// injacSpacesCreation
