/*
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.channelAction.injac.acl;
 
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.channelAction.injac.metadata.InjacSpaceManagementProperties;
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.NotSupportedAclException;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.exception.ServerException;
import org.esupportail.portal.channels.CStockage.provider.access.ServerAccess;
import org.esupportail.portal.channels.CStockage.userManagement.Group;
import org.esupportail.portal.channels.CStockage.userManagement.User;
import org.esupportail.portal.utils.webdav.acl.EsupPermission;
import org.esupportail.portal.utils.webdav.acl.EsupPermissions;

/**
 * Id: InjacAclManager.java,v 1.0 10 nov. 2004
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)
 * Classes: InjacAclManager
 * Original Author: Yohan Colmant
 * Use to manage the acl used in injac
 */
public class InjacAclManager {


	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(InjacAclManager.class);
	
	
	/**
	 * Set the acl for reading set by manager on a space
	 * @param currentSpace the current space used
	 * @param path the resource path
	 * @param smp object containing all properties
	 * @throws ServerException
	 * @throws ApplicationException
	 * @throws AclReadException
	 * @throws AclAccessException
	 * @throws AclWriteException
	 * @throws NotSupportedAclException
	 */
	public static void setReadersAclOnSpace(Space currentSpace, String path, InjacSpaceManagementProperties smp) throws ServerException, ApplicationException, AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {		
		
		// to access the server
		ServerAccess access = currentSpace.getServerAccessObject();
		
		// the administrator principal value
		String adminPrincipal = currentSpace.getAclUserPrefix()+currentSpace.getLogin();
		
		// users and groups we ask to add
		Vector usersToAdd = smp.getAddedReaderUsers();
		Vector groupsToAdd = smp.getAddedReaderGroups();
		
		// users and groups we ask to delete
		Vector usersToDelete = smp.getDeletedReaderUsers();
		Vector groupsToDelete = smp.getDeletedReaderGroups();
		
		// The current permissions path
		EsupPermissions perms = smp.getReadingPermission();

		//System.out.println(" >>> we add a grant for all for the administrator");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" add a grant for all for the administrator");
		}
		
		// we add a grant for all for the administrator
		EsupPermission grantAllAdministrator = new EsupPermission(EsupPermission.GRANT, adminPrincipal, EsupPermission.ALL, false, null, false, currentSpace.getAclNamespace(), currentSpace.getAclUserPrefix(), currentSpace.getAclGroupPrefix());		
		if (!access.hasNotInheritedPermission(path, adminPrincipal, EsupPermission.ALL, EsupPermission.GRANT)) {
			perms = access.grant(path, adminPrincipal, EsupPermission.ALL);
		} 
		
		//System.out.println(" >>> if public, we delete all permissions (not those of administrator) on the resource and add a grant for all");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" if public, we delete all permissions (not those of administrator) on the resource and add a grant for all");
		}
		
		// if public, we delete all permissions (not those of administrator) on the resource and add a grant for "all"		
		if (smp.isPublicReading()) {
			//System.out.println("c'est public");
			Iterator iter = perms.iterator();
			while (iter.hasNext()) {				
				EsupPermission perm = (EsupPermission)iter.next();				
				if (!perm.isInherited() && !perm.getPrincipal().equals(adminPrincipal)) {					
					perms = access.revoke(path, perm.getPrincipal(), EsupPermission.READ);		
				}
			}	
			//System.out.println(access.getPermissions(path)+"\n\n\n\n\n\n\n\n");
			perms = access.grant(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ);		
			//System.out.println(perms);
			return;
		}
		
		//System.out.println(" >>> if not public, we add a deny for all");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" if not public, we add a deny for all");
		}
		
		// if not public, we add a deny for "all"
		if (!smp.isPublicReading()) {
			perms = access.deny(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ);
		}
		
		//System.out.println(" >>> for each inherited permission, if there is no local grant, we add one ");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each inherited permission, if there is no local grant, we add one");
		}
		
		// for each inherited permission, if there is no local grant, we add one 
		Iterator iter = perms.iterator();
		Vector forceHerited = new Vector();
		while (iter.hasNext()) {				
			EsupPermission perm = (EsupPermission)iter.next();
			
			// if the permission is not inherited, read, the principal is not the administrator and not all
			if (!perm.isInherited() && perm.getPermissionType().equals(EsupPermission.READ) && !perm.getPrincipal().equals(EsupPermission.PRINCIPAL_ALL) && !perm.getPrincipal().equals(adminPrincipal)) {
				
				// if deny, we add to the vector
				if (perm.isDenyPermission()) {
					//System.out.println("    --> ajoute deny LOCAL "+perm);
					forceHerited.addElement(perm);
				}
				
			}
			
			
			// if the permission is inherited, read, the principal is not the administrator and not all
			else if (perm.isInherited() && perm.getPermissionType().equals(EsupPermission.READ) && !perm.getPrincipal().equals(EsupPermission.PRINCIPAL_ALL) && !perm.getPrincipal().equals(adminPrincipal)) {
				
			
				// if deny, we add
				if (perm.isDenyPermission()) {
					//System.out.println("    --> ajoute deny HERITE "+perm);
					forceHerited.addElement(perm);
				}
					
				else {
					// if does not contain deny
					EsupPermission permTempInherited = new EsupPermission(EsupPermission.DENY, perm.getPrincipal(), EsupPermission.READ, true, null, false, currentSpace.getAclNamespace(), currentSpace.getAclUserPrefix(), currentSpace.getAclGroupPrefix());
					EsupPermission permTempNotInherited = new EsupPermission(EsupPermission.DENY, perm.getPrincipal(), EsupPermission.READ, false, null, false, currentSpace.getAclNamespace(), currentSpace.getAclUserPrefix(), currentSpace.getAclGroupPrefix());
					if (!forceHerited.contains(permTempInherited) && !forceHerited.contains(permTempNotInherited) && !forceHerited.contains(perm)) {
						//System.out.println("    --> ajoute grant HERITE "+perm);
						//System.out.println("        ne contient pas "+permTempInherited+" ni "+permTempNotInherited);
						forceHerited.addElement(perm);
					}
				}
				
			}			
		}
		
		for (int i=0; i<forceHerited.size(); i++) {
			EsupPermission perm = (EsupPermission)forceHerited.elementAt(i);
			if (perm.isGrantPermission() )	 {
				perms = access.grant(path, perm.getPrincipal(), EsupPermission.READ);
			}
		}
	
		
		
		
		
		
		//System.out.println(" >>> for each user we want to delete, if we have a not inherated grand read, we revoke it");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each user we want to delete, if we have a not inherated grand read, we revoke it");
		}
		
		// for each user we want to delete, if we have a not inherated grand read, we revoke it
		for (int i=0; i<usersToDelete.size(); i++) {
			
			User u = (User)usersToDelete.elementAt(i);
			String key = u.getKey();
			String principal = currentSpace.getAclUserPrefix()+key;
						
			// we check if we have an inherited grant
			boolean stop = false;
			boolean grant = false;
			iter = perms.iterator();
			while (!stop && iter.hasNext()) {
				EsupPermission perm = (EsupPermission)iter.next();
				if (perm.getPrincipal().equals(principal) && perm.getPermissionType().equals(EsupPermission.READ) && !perm.isInherited()) {
					if (perm.isGrantPermission()) {
						stop = true;
						grant = true;
					}
					else {
						stop = true;
						grant = false;
					}
				}				
			}
			
			// if we have a not inherited grant
			if (grant)
				access.revoke(path, principal, EsupPermission.READ);			
		}

		//System.out.println(" >>> for each group we want to delete, if we have a not inherated grand read, we revoke it");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each group we want to delete, if we have a not inherated grand read, we revoke it");
		}
		
		// for each group we want to delete, if we have a not inherated grand read, we revoke it TODO VERIFIER
		for (int i=0; i<groupsToDelete.size(); i++) {
			
			Group g = (Group)groupsToDelete.elementAt(i);
			Vector groupHierarchyKey = g.getGroupHierarchy();
			if (groupHierarchyKey!=null) {
				String principal = currentSpace.getAclGroupPrefix();
				if (currentSpace.getAclUportalGroup()!=null && !currentSpace.getAclUportalGroup().trim().equals("")) {
					principal = principal+currentSpace.getAclUportalGroup()+"/";
				}
				for (int j=0; j<groupHierarchyKey.size(); j++) {
					principal = principal + groupHierarchyKey.elementAt(j);
					if (j!=groupHierarchyKey.size()-1)
						principal = principal + "/";
				}
				
				// we check if we have an inherited grant
				boolean stop = false;
				boolean grant = false;
				iter = perms.iterator();
				while (!stop && iter.hasNext()) {
					EsupPermission perm = (EsupPermission)iter.next();
					if (perm.getPrincipal().equals(principal) && perm.getPermissionType().equals(EsupPermission.READ) && !perm.isInherited()) {
						if (perm.isGrantPermission()) {
							stop = true;
							grant = true;
						}
						else {
							stop = true;
							grant = false;
						}
					}				
				}
				
				// if we have a not inherited grant
				if (grant)
					access.revoke(path, principal, EsupPermission.READ);
				
			}
		}
		
		//System.out.println(" >>> for each user we want to delete, if we have an inherated grant read, we put a deny on the resource");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each user we want to delete, if we have an inherated grant read, we put a deny on the resource");
		}
		
		// for each user we want to delete, if we have an inherated grant read, we put a deny on the resource
		for (int i=0; i<usersToDelete.size(); i++) {
			
			User u = (User)usersToDelete.elementAt(i);
			String key = u.getKey();
			String principal = currentSpace.getAclUserPrefix()+key;
			
			// we check if we have an inherited grant
			boolean stop = false;
			boolean grant = false;
			iter = perms.iterator();
			while (!stop && iter.hasNext()) {
				EsupPermission perm = (EsupPermission)iter.next();
				if (perm.getPrincipal().equals(principal) && perm.getPermissionType().equals(EsupPermission.READ) && perm.isInherited()) {
					if (perm.isGrantPermission()) {
						stop = true;
						grant = true;
					}
					else {
						stop = true;
						grant = false;
					}
				}				
			}
			
			// if we have an inherited grant
			if (grant)
				access.deny(path, principal, EsupPermission.READ);			
		}

		
		//System.out.println(" >>> for each group we want to delete, if we have an inherated grant read, we put a deny on the resource");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each group we want to delete, if we have an inherated grant read, we put a deny on the resource");
		}
		
		// for each group we want to delete, if we have an inherated grant read, we put a deny on the resource TODO VERIFIER
		for (int i=0; i<groupsToDelete.size(); i++) {
			
			Group g = (Group)groupsToDelete.elementAt(i);
			Vector groupHierarchyKey = g.getGroupHierarchy();
			if (groupHierarchyKey!=null) {
				String principal = currentSpace.getAclGroupPrefix();
				if (currentSpace.getAclUportalGroup()!=null && !currentSpace.getAclUportalGroup().trim().equals("")) {
					principal = principal+currentSpace.getAclUportalGroup()+"/";
				}
				for (int j=0; j<groupHierarchyKey.size(); j++) {
					principal = principal + groupHierarchyKey.elementAt(j);
					if (j!=groupHierarchyKey.size()-1)
						principal = principal + "/";
				}
				
				// we check if we have an inherited grant
				boolean stop = false;
				boolean grant = false;
				iter = perms.iterator();
				while (!stop && iter.hasNext()) {
					EsupPermission perm = (EsupPermission)iter.next();
					if (perm.getPrincipal().equals(principal) && perm.getPermissionType().equals(EsupPermission.READ) && perm.isInherited()) {
						if (perm.isGrantPermission()) {
							stop = true;
							grant = true;
						}
						else {
							stop = true;
							grant = false;
						}
					}				
				}
				
				// if we have an inherited grant
				if (grant)
					access.deny(path, principal, EsupPermission.READ);		// TODO Yoyo
			}
		}
		
		//System.out.println(" >>> for each user we want to add");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each user we want to add");
		}
		
		// for each user we want to add TODO VERIFIER
		for (int i=0; i<usersToAdd.size(); i++) {
			
			User u = (User)usersToAdd.elementAt(i);
			String key = u.getKey();
			String principal = currentSpace.getAclUserPrefix()+key;
			
			access.grant(path, principal, EsupPermission.READ);
		}
		
		//System.out.println(" >>> for each group we want to add");
		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" for each group we want to add");
		}
		

		// for each group we want to add TODO VERIFIER
		for (int i=0; i<groupsToAdd.size(); i++) {
			
			Group g = (Group)groupsToAdd.elementAt(i);
			Vector groupHierarchyKey = g.getGroupHierarchy();
			String principal = currentSpace.getAclGroupPrefix();
			if (currentSpace.getAclUportalGroup()!=null && !currentSpace.getAclUportalGroup().trim().equals("")) {
				principal = principal+currentSpace.getAclUportalGroup()+"/";
			}
			for (int j=0; j<groupHierarchyKey.size(); j++) {
				principal = principal + groupHierarchyKey.elementAt(j);
				if (j!=groupHierarchyKey.size()-1)
					principal = principal + "/";
			}
			
			access.grant(path, principal, EsupPermission.READ);		 //TODO Yoyo	
		}
		

		// log
		if (log.isDebugEnabled()){
			log.debug("setReadersAclOnSpace"+" :: "+path+" end of acl setting");
		}
		
		//System.out.println("\nusers a ajouter:\n"+usersToAdd);
		//System.out.println("groups a ajouter:\n"+groupsToAdd);		
		//System.out.println("users a supprimer:\n"+usersToDelete);
		//System.out.println("groups a supprimer:\n"+groupsToDelete);
	}
	
	
	

	/**
	 * Return the ACL for reading on a space
	 * @param access the server access object
	 * @param path the resource path
	 * @param permissions the permissions list
	 * @param users the users
	 * @param groups the groups
	 * @param userPrefix the acl user prefix
	 * @param groupPrefix the acl group prefix
	 * @return true if public, false if not public
	 * @throws AclAccessException
	 * @throws AclReadException
	 * @throws NotSupportedAclException
	 */
	public static boolean getReadersAclOnSpace(ServerAccess access, String path, EsupPermissions permissions, Vector users, Vector groups, String userPrefix, String groupPrefix) throws AclAccessException, AclReadException, NotSupportedAclException, PropertiesException  {		
				
		// check if public
		boolean publicAccess = false;
		boolean localPublicAccess = false;
		String inheritedFromPublicAccess = null;
		
		// log
		if (log.isDebugEnabled()){
			log.debug("getReadersAclOnSpace"+" :: "+path+" begin of acl getting");
		}
		
		// if local grant for all
		if (access.hasNotInheritedPermission(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ, EsupPermission.GRANT)) {
			publicAccess = true;
			localPublicAccess = true;
		}
		
		// if local deny for all
		else if (access.hasNotInheritedPermission(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ, EsupPermission.DENY)) {
			publicAccess = false;
			localPublicAccess = true;
		}
		
		// if no local permissions for all
		else {
			Vector grantPermissions = access.hasInheritedPermission(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ, EsupPermission.GRANT);
			Vector denyPermissions = access.hasInheritedPermission(path, EsupPermission.PRINCIPAL_ALL, EsupPermission.READ, EsupPermission.DENY);
			
			// if we have inherited grant permission(s)
			if (grantPermissions != null) {
				
				// if we have not inherited deny permission(s)
				if (denyPermissions == null) {					
					publicAccess = true;
					EsupPermission permGrant = (EsupPermission)grantPermissions.elementAt(0);
					inheritedFromPublicAccess = permGrant.getInheritedFrom();
				}

				// if we have inherited deny permission(s)
				else {
					EsupPermission permGrant = (EsupPermission)grantPermissions.elementAt(0);
					EsupPermission permDeny = (EsupPermission)denyPermissions.elementAt(0);
					if (permGrant.getInheritedFrom().compareTo(permDeny.getInheritedFrom()) > 1) {
						publicAccess = true;
						inheritedFromPublicAccess = permGrant.getInheritedFrom();
					}
					else {
						inheritedFromPublicAccess = permDeny.getInheritedFrom();
					}
				}
			}

			// if we have not inherited grant permission(s)
			else {

				// if we have not inherited deny permission(s)
				if (denyPermissions == null) {					
					publicAccess = false;					
					inheritedFromPublicAccess = null;
				}

				// if we have inherited deny permission(s)
				else {					
					EsupPermission permDeny = (EsupPermission)denyPermissions.elementAt(0);
					inheritedFromPublicAccess = permDeny.getInheritedFrom();
					publicAccess = false;
				}
			}
		}		

		//System.out.println("public: "+publicAccess);
		//System.out.println("localPublicAccess: "+localPublicAccess);
		//System.out.println("inheritedFromPublicAccess: "+inheritedFromPublicAccess);
		
		
		// the denied users and groups
		Vector deniedUsers = new Vector();
		Vector deniedGroups = new Vector();
		
		// for each permission
		EsupPermissions perms = access.getPermissions(path);//, EsupPermission.READ);
		permissions.clone(perms);
		
		//System.out.println("je recupere les ACL");
		//System.out.println(perms);
		
		// each permission
		Iterator iter = perms.iterator();
		while(iter.hasNext()) {
			
			EsupPermission perm = (EsupPermission)iter.next();
			boolean inherited = perm.isInherited();
			String inheritedFrom = perm.getInheritedFrom();
			
			// if the type is read
			String type = perm.getPermissionType();
			if (type.equals(EsupPermission.READ)) {
			
				String principal = perm.getPrincipal();
				boolean isGrant = perm.isGrantPermission();
				
				// check if user
				int index = principal.indexOf(userPrefix);
				if (index != -1) {
					String userKey = principal.substring(userPrefix.length());					
					User u = new User(userKey);
					/*if (inherited)
						u.setDisplayName(u.getDisplayName()+" HERITEE de "+inheritedFrom);*/
					
					// if deny, we add it into the deny vector
					if (!isGrant) {
						deniedUsers.addElement(u);
					}
					else {
						// if not denieded before, and not added to users
						if (!users.contains(u) && !deniedUsers.contains(u)) {						
							users.addElement(u);
						}
					}
				}			
				
				//	check if group
				index = principal.indexOf(groupPrefix);
				if (index != -1) {
					String groupKeysHierarchy = principal.substring(groupPrefix.length());					
					try {
						Group g = new Group(groupKeysHierarchy);
						/*if (inherited)
							g.setDisplayName(g.getDisplayName()+" HERITEE de "+inheritedFrom);*/

						// if deny, we add it into the deny vector
						if (!isGrant) {
							deniedGroups.addElement(g);
						}
						else {
							// if not denieded before, and not added to groups
							if (!groups.contains(g) && !deniedGroups.contains(g)) {						
								groups.addElement(g);
							}
						}
					}
					catch(ServerException e) {

						// log
						if (log.isDebugEnabled()){
							log.debug("getReadersAclOnSpace"+" :: "+e);
						}
					}
				}
			}
		}
		
		// log
		if (log.isDebugEnabled()){
			log.debug("getReadersAclOnSpace"+" :: "+path+" end of acl getting");
		}
		
		return publicAccess;
	}
	
	
	
}
