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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.injac.DirectoryProperties;
import org.esupportail.portal.channels.CStockage.channelAction.injac.acl.InjacAclManager;
import org.esupportail.portal.channels.CStockage.channelAction.injac.config.InjacConfig; 
import org.esupportail.portal.channels.CStockage.channelAction.injac.config.MetadataFileProfile;
import org.esupportail.portal.channels.CStockage.channelAction.injac.config.RenderingType;
import org.esupportail.portal.channels.CStockage.channelAction.injac.metadata.parse.ParseRequiredMetaData;
import org.esupportail.portal.channels.CStockage.config.Space;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
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.spacesPersonalization.target.GroupForPersonalization;
import org.esupportail.portal.channels.CStockage.spacesPersonalization.target.OtherPrincipalForPersonalization;
import org.esupportail.portal.channels.CStockage.spacesPersonalization.target.UserForPersonalization;
import org.esupportail.portal.channels.CStockage.userManagement.Group;
import org.esupportail.portal.channels.CStockage.userManagement.User;



/**
 * Id: InjacSpaceManagementProperties.java,v 1.0 7 oct. 2004
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org)
 * Classes: InjacSpaceManagementProperties
 * Original Author: Yohan Colmant
 * Class used to manage an injac space
 */
public class InjacSpaceManagementProperties {
	

	/**
	 * Logger object
	 */
	protected static final Log log = LogFactory.getLog(InjacSpaceManagementProperties.class);
	
	
	/**
	 * Available metadata profiles for this space
	 */
	private ArrayList availableMetadataProfiles;
	
	/**
	 * The selected metadata profile key
	 */
	private String selectedMetadataProfile;
	
	
	/**
	 * Available rendering types for this space
	 */
	private ArrayList availableRenderingTypes;
	
	/**
	 * The selected rendering type key
	 */
	private String selectedRenderingType;
	
	/**
	 * The space's title
	 */
	private String title;
	
	/**
	 * This space description
	 */
	private String description;
	
	
	/**
	 * The users reader
	 */
	private Vector readerUsers;

	/**
	 * The groups of readers
	 */
	private Vector readerGroups;

	/**
	 * The others of readers
	 */
	private Vector readerOthers;

	/**
	 * If this space is public
	 */
	private boolean publicReading;
	
	/**
	 * the reader users we want to add
	 */
	private Vector modifiedReaderUsers;
	
	/**
	 * the reader groups we want to add
	 */
	private Vector modifiedReaderGroups;
	
	/**
	 * the reader users we want to delete
	 */
	private Vector modifiedReaderOthers;
	
	/**
	 * The acl permissions for the readers
	 */
	//private EsupPermissions readingPermission;
	
	/**
	 * The writer groups
	 */
	private Vector writerGroups;
	
	/**
	 * The writer users
	 */
	private Vector writerUsers;
	
	/**
	 * The editor groups
	 */
	private Vector editorGroups;
	
	/**
	 * The editor users 
	 */
	private Vector editorUsers;
	
	/**
	 * The manager groups
	 */
	private Vector managerGroups;
	
	/**
	 * The manager users
	 */
	private Vector managerUsers;
	
	

	/**
	 * Constructor
	 * @param selectedMetadataProfile The selected metadata profile key
	 * @param selectedRenderingType The selected rendering type key
	 * @param description the space description
	 * @param publicReading is the space is public
	 * @param readingPermission the acl permission of reading
	 * @param readerGroups the reader groups
	 * @param readerUsers the reader users
	 * @param writerGroups the writer groups
	 * @param writerUsers the writer users
	 * @param editorGroups the editor groups
	 * @param editorUsers the editor users
	 * @param managerGroups the manager groups
	 * @param managerUsers the manager users
	 * @throws PropertiesException
	 */
	public InjacSpaceManagementProperties(String selectedMetadataProfile, String selectedRenderingType, String title, String description, boolean publicReading, Vector readerUsers, Vector readerGroups, Vector readerOthers, Vector writerGroups, Vector writerUsers, Vector editorGroups, Vector editorUsers, Vector managerGroups, Vector managerUsers, boolean createNewSpace) throws PropertiesException {
		this.availableMetadataProfiles = InjacConfig.getInstance().getMetadataProfiles();
		
		if (selectedMetadataProfile==null)
			this.selectedMetadataProfile = ((MetadataFileProfile)availableMetadataProfiles.get(0)).getFileName();
		else this.selectedMetadataProfile = selectedMetadataProfile;
		
		
		this.availableRenderingTypes = InjacConfig.getInstance().getRenderingTypes();
		
		if (selectedRenderingType==null)
			this.selectedRenderingType = ((RenderingType)availableRenderingTypes.get(0)).getSkinFile();
		else this.selectedRenderingType = selectedRenderingType;
		
		this.title = title;
		this.description = description;
		
		// the readers
		this.readerUsers = readerUsers;
		this.readerGroups = readerGroups;
		this.readerOthers = readerOthers;
		this.publicReading = publicReading;
		
		// if create new space, we set each reader inherited
		if (createNewSpace)
			setAllReadersInherited();
		
		//System.out.println(readerUsers);
		//System.out.println(readerGroups);
		//System.out.println(readerOthers);
		//System.out.println(publicReading+"\n");
		
		// the readers's clones
		this.modifiedReaderUsers = new Vector(this.readerUsers.size());
		for (int i=0; i<this.readerUsers.size(); i++) {
			UserForPersonalization user = (UserForPersonalization)this.readerUsers.elementAt(i);
			this.modifiedReaderUsers.addElement(user.clone());
		}
		this.modifiedReaderGroups = new Vector();
		for (int i=0; i<this.readerGroups.size(); i++) {
			GroupForPersonalization group = (GroupForPersonalization)this.readerGroups.elementAt(i);
			this.modifiedReaderGroups.addElement(group.clone());
		}
		this.modifiedReaderOthers = new Vector();
		for (int i=0; i<this.readerOthers.size(); i++) {
			OtherPrincipalForPersonalization other = (OtherPrincipalForPersonalization)this.readerOthers.elementAt(i);
			this.modifiedReaderOthers.addElement(other.clone());
		}
		
		// the writers
		this.writerGroups = writerGroups;
		this.writerUsers = writerUsers;
		
		// the editors
		this.editorGroups = editorGroups;
		this.editorUsers = editorUsers;
		
		// the managers
		this.managerGroups = managerGroups;
		this.managerUsers = managerUsers;
	}
	
	
	
	
	/**
	 * @return Returns the readingPermission.
	 */
	/*public EsupPermissions getReadingPermission() {
		return readingPermission;
	}*/
	/**
	 * @param readingPermission The readingPermission to set.
	 */
	/*public void setReadingPermission(EsupPermissions readingPermission) {
		this.readingPermission = readingPermission;
	}*/
	/**
	 * @return Returns the description.
	 */
	public String getDescription() {
		return description;
	}
	/**
	 * @param description The description to set.
	 */
	public void setDescription(String description) {
		this.description = description;
	}
	
	/**
	 * @return Returns the title.
	 */
	public String getTitle() {
		return title;
	}
	/**
	 * @param title The title to set.
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	/**
	 * @return Returns the publicReading.
	 */
	public boolean isPublicReading() {
		return publicReading;
	}
	/**
	 * @param publicReading The publicReading to set.
	 */
	public void setPublicReading(boolean publicReading) {		
		this.publicReading = publicReading;
	}
	/**
	 * @return Returns the readerGroups.
	 */
	public Vector getReaderGroups() {
		return readerGroups;
	}
	/**
	 * @return Returns the readerUsers.
	 */
	public Vector getReaderUsers() {
		return readerUsers;
	}
	
	/**
	 * @return Returns the readerOthers.
	 */
	public Vector getReaderOthers() {
		return readerOthers;
	}
	
	/**
	 * @return Returns the modifiedReaderGroups.
	 */
	public Vector getModifiedReaderGroups() {
		return modifiedReaderGroups;
	}
	/**
	 * @param modifiedReaderGroups The modifiedReaderGroups to set.
	 */
	public void setModifiedReaderGroups(Vector modifiedReaderGroups) {
		this.modifiedReaderGroups = modifiedReaderGroups;
	}
	/**
	 * @return Returns the modifiedReaderOthers.
	 */
	public Vector getModifiedReaderOthers() {
		return modifiedReaderOthers;
	}
	/**
	 * @param modifiedReaderOthers The modifiedReaderOthers to set.
	 */
	public void setModifiedReaderOthers(Vector modifiedReaderOthers) {
		this.modifiedReaderOthers = modifiedReaderOthers;
	}
	/**
	 * @return Returns the modifiedReaderUsers.
	 */
	public Vector getModifiedReaderUsers() {
		return modifiedReaderUsers;
	}
	/**
	 * @param modifiedReaderUsers The modifiedReaderUsers to set.
	 */
	public void setModifiedReaderUsers(Vector modifiedReaderUsers) {
		this.modifiedReaderUsers = modifiedReaderUsers;
	}
	/**
	 * @return Returns the editorGroups.
	 */
	public Vector getEditorGroups() {
		return editorGroups;
	}
	/**
	 * @return Returns the editorUsers.
	 */
	public Vector getEditorUsers() {
		return editorUsers;
	}
	/**
	 * @return Returns the managerGroups.
	 */
	public Vector getManagerGroups() {
		return managerGroups;
	}
	/**
	 * @return Returns the managerUsers.
	 */
	public Vector getManagerUsers() {
		return managerUsers;
	}
	/**
	 * @return Returns the writerGroups.
	 */
	public Vector getWriterGroups() {
		return writerGroups;
	}
	/**
	 * @return Returns the writerUsers.
	 */
	public Vector getWriterUsers() {
		return writerUsers;
	}
		
	/**
	 * @return Returns the selectedMetadataProfile.
	 */
	public String getSelectedMetadataProfile() {
		return selectedMetadataProfile;
	}
	/**
	 * @param selectedMetadataProfile The selectedMetadataProfile to set.
	 */
	public void setSelectedMetadataProfile(String selectedMetadataProfile) {
		this.selectedMetadataProfile = selectedMetadataProfile;
	}
	
	/**
	 * @return Returns the availableMetadataProfiles.
	 */
	public ArrayList getAvailableMetadataProfiles() {
		return availableMetadataProfiles;
	}
	
	/**
	 * @return Returns the selectedRenderingType.
	 */
	public String getSelectedRenderingType() {
		return selectedRenderingType;
	}
	/**
	 * @param selectedRenderingType The selectedRenderingType to set.
	 */
	public void setSelectedRenderingType(String selectedRenderingType) {
		this.selectedRenderingType = selectedRenderingType;
	}
	
	/**
	 * @return Returns the availableRenderingTypes.
	 */
	public ArrayList getAvailableRenderingTypes() {
		return availableRenderingTypes;
	}
	
	
	
	
	/**
	 * Return in the good format the list of MD that the user have to set
	 * @return in the good format the list of MD that the user have to set
	 * @throws ApplicationException
	 * @throws PropertiesException
	 */
	public String getMetadataProfile() throws ApplicationException, PropertiesException{		
		
		StringBuffer sb = new StringBuffer();
		
		// the file stream
		String fileName = selectedMetadataProfile;		
		String path = "/properties/channels/org_esup/CStockage/injac/metadata/";
		String filePath = path+fileName;
		
		
		try {
		
			InputStream is = InjacConfig.class.getResourceAsStream(filePath);
			
			// if not exists fileName
			if (is==null) {
				
				// get the first
				if (this.availableMetadataProfiles.size()>0) {
					fileName = ((MetadataFileProfile)this.availableMetadataProfiles.get(0)).getFileName();
					filePath = path+fileName;
					is = InjacConfig.class.getResourceAsStream(filePath);
				}
				
				else throw new PropertiesException();				
			}
		
		
			// we read the file
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String temp = null;
			while ((temp = br.readLine())!=null) {
				sb.append(temp);
			}
			br.close();
			
		}
		catch(IOException e) {
			log.error("getMetadataProfile"+" :: "+e);
			throw new ApplicationException();
		}
				
		// return the content of the file
		String fileContent = sb.toString();		
		int index = fileContent.indexOf("<metas");		
		
		String result = "<metas key=\""+fileName+"\" "+fileContent.substring(index+6, fileContent.length());
		
		return result;		
	}
	
	
	/**
	 * Return in the good format the MD : list of readers on the space
	 * @return in the good format the MD : list of readers on the space
	 */ 
	public String getMetadataReadersOnSpace() {
		StringBuffer s = new StringBuffer();
		
		s.append("<readers publicAccess=\"");
		if (this.publicReading)
			s.append("yes");
		else s.append("no");
		s.append("\">");
				
		s.append(getRoleOnSpace(this.readerUsers, this.readerGroups, "reader"));		
		
		s.append("</readers>");
		
		return s.toString();
	}
	
	/**
	 * Return in the good format the MD : list of writers on the space
	 * @return in the good format the MD : list of writers on the space
	 */
	public String getMetadataWritersOnSpace() {
		StringBuffer s = new StringBuffer();
		
		s.append("<writers>");		
		s.append(getRoleOnSpace(this.writerUsers, this.writerGroups, "writer"));		
		s.append("</writers>");
		
		return s.toString();
	}
	
	/**
	 * Return in the good format the MD : list of editors on the space
	 * @return in the good format the MD : list of editors on the space
	 */
	public String getMetadataEditorsOnSpace() {
		StringBuffer s = new StringBuffer();
		
		s.append("<editors>");		
		s.append(getRoleOnSpace(this.editorUsers, this.editorGroups, "editor"));		
		s.append("</editors>");
		
		return s.toString();
	}
	
	/**
	 * Return in the good format the MD : list of managers on the space
	 * @return in the good format the MD : list of managers on the space
	 */
	public String getMetadataManagersOnSpace() {
		StringBuffer s = new StringBuffer();
		
		s.append("<managers>");		
		s.append(getRoleOnSpace(this.managerUsers, this.managerGroups, "manager"));		
		s.append("</managers>");
		
		return s.toString();
	}
	
	
	/**
	 * Return the list of roles in the good format
	 * @param users the list of users
	 * @param groups the list of groups
	 * @param type the type of role: manager, writer, ...
	 * @return the list of roles in the good format
	 */
	private StringBuffer getRoleOnSpace(Vector users, Vector groups, String type) {
		StringBuffer s = new StringBuffer();
		
		for (int i=0; i<users.size(); i++) {
			User u = (User)users.elementAt(i);
			s.append("<"+type+" type=\""+"user"+"\" key=\""+u.getKey()+"\" displayName=\""+u.getDisplayName()+"\"/>");
		}
		
		for (int i=0; i<groups.size(); i++) {
			Group g = (Group)groups.elementAt(i);
			s.append("<"+type+" type=\""+"group"+"\" key=\""+g.getKey()+"\" displayName=\""+g.getDisplayName()+"\"/>");
		}
		
		return s;
	}
	
	
	
	
	/**
	 * To set all users, groups, and others inherited
	 *
	 */
	private void setAllReadersInherited() {

		// we delete each inherited permission for users
		for (int i=0; i<this.readerUsers.size(); i++) {
			UserForPersonalization user = (UserForPersonalization)readerUsers.elementAt(i);
			user.getPersonalization().setInheritedAcl(true);
		}
		
		// we delete each inherited permission for groups
		for (int i=0; i<this.readerGroups.size(); i++) {
			GroupForPersonalization group = (GroupForPersonalization)readerGroups.elementAt(i);
			group.getPersonalization().setInheritedAcl(true);
		}

		// we delete each inherited permission for others
		for (int i=0; i<this.readerOthers.size(); i++) {
			OtherPrincipalForPersonalization other = (OtherPrincipalForPersonalization)readerOthers.elementAt(i);
			other.getPersonalization().setInheritedAcl(true);
		}
	}
	
	
	
	
	/**
	 * Get the properties sets on a space
	 * @param currentSpace the current space
	 * @param path the resource path
	 * @return the properties sets on a space
	 * @throws ChannelException
	 */
	public static InjacSpaceManagementProperties getProperties(Space currentSpace, DirectoryProperties directoryProperties, boolean createNewSpace) throws ChannelException {
		
		String path = currentSpace.getCurrentPath();
		
		String mdDescription = MetaDataManager.getMetadataDescription(currentSpace, path);
		String mdTitle = MetaDataManager.getMetadataTitle(currentSpace, path);
		
		// the metadata list
		ParseRequiredMetaData metadataList = directoryProperties.getMetadataList();
		String metadataKey = null;
		if (metadataList==null) {
			String mdMetadata = MetaDataManager.getMetadataSpaceProfile(currentSpace, path);
			if (mdMetadata==null || mdMetadata.equals("")) {
				metadataKey = null;
			}
			else {
				ParseRequiredMetaData parse = new ParseRequiredMetaData(mdMetadata);
				directoryProperties.setMetadataList(parse);
				metadataKey = parse.getKey();
			}
		}
		else {
			metadataKey = metadataList.getKey();
		}
		 
		// the rendering type
		String mdRenderingType = MetaDataManager.getMetadataRenderingType(currentSpace, path);
		if (mdRenderingType==null || mdRenderingType.equals("")) {
			mdRenderingType = null;
		}
		
		Vector readerGroups = new Vector();
		Vector readerUsers = new Vector();
		Vector readerOthers = new Vector();
		//EsupPermissions perms = new EsupPermissions();  
		boolean publicReading = InjacAclManager.getReadersAclOnSpace(currentSpace, readerUsers, readerGroups, readerOthers);
		
		
		Vector writerGroups = new Vector();
		Vector writerUsers = new Vector();
		MetaDataManager.getMetadataWritersOnSpace(currentSpace, path, writerUsers, writerGroups);
		
		Vector editorGroups = new Vector();
		Vector editorUsers = new Vector();
		MetaDataManager.getMetadataEditorsOnSpace(currentSpace, path, editorUsers, editorGroups);
		
		Vector managerGroups = new Vector();
		Vector managerUsers = new Vector();
		MetaDataManager.getMetadataManagersOnSpace(currentSpace, path, managerUsers, managerGroups);
				
		InjacSpaceManagementProperties smp = new InjacSpaceManagementProperties(metadataKey, mdRenderingType, mdTitle, mdDescription, publicReading, readerUsers, readerGroups, readerOthers, writerGroups, writerUsers, editorGroups, editorUsers, managerGroups, managerUsers, createNewSpace);
		
		return smp;				
	}
	
	
	
	
	
	
	/**
	 * Check if a user is manager on a space
	 * @param login the user login
	 * @param userGroups the groups of the user
	 * @param currentSpace the current space used
	 * @param path the resource path
	 * @return true if user is manager, false else
	 * @throws ServerException
	 */
	public static boolean isUserManager(String login, Vector userGroups, Space currentSpace, String path) throws ServerException {
		
		Vector managerGroups = new Vector();
		Vector managerUsers = new Vector();
		MetaDataManager.getMetadataManagersOnSpace(currentSpace, path, managerUsers, managerGroups);
		
		User user = new User(login, login);
		
		// check if the login is in the list
		if (managerUsers.contains(user))
			return true;
		
		// check if the group is ok
		for (int i=0; i<managerGroups.size(); i++) {
			
			Group g = (Group)managerGroups.elementAt(i);
			if (userGroups.contains(g.getKey()))
				return true;
			
		}
		
		return false;
	}
	
	
	
	/**
	 * Check if a user is writer on a space
	 * @param login the user login
	 * @param userGroups the groups of the user
	 * @param currentSpace the current space used
	 * @param path the resource path
	 * @return true is user is writer
	 * @throws ServerException
	 */
	public static boolean isUserWriter(String login, Vector userGroups, Space currentSpace, String path) throws ServerException {
		
		Vector writerGroups = new Vector();
		Vector writerUsers = new Vector();
		MetaDataManager.getMetadataWritersOnSpace(currentSpace, path, writerUsers, writerGroups);
		
		User user = new User(login, login);
		
		// check if the login is in the list
		if (writerUsers.contains(user))
			return true;
		
		// check if the group is ok
		for (int i=0; i<writerGroups.size(); i++) {
			
			Group g = (Group)writerGroups.elementAt(i);
			if (userGroups.contains(g.getKey()))
				return true;
			
		}
		
		return false;
	}
	
	
	 
	
	/**
	 * Check if a user is editor on a space
	 * @param login the user login
	 * @param userGroups the groups of the user
	 * @param currentSpace the current space used
	 * @param path the resource path
	 * @return true is user is editor
	 * @throws ServerException
	 */
	public static boolean isUserEditor(String login, Vector userGroups, Space currentSpace, String path) throws ServerException {
		
		Vector editorGroups = new Vector();
		Vector editorUsers = new Vector();
		MetaDataManager.getMetadataEditorsOnSpace(currentSpace, path, editorUsers, editorGroups);
		
		User user = new User(login, login);
		
		// check if the login is in the list
		if (editorUsers.contains(user))
			return true;
		
		// check if the group is ok
		for (int i=0; i<editorGroups.size(); i++) {
			
			Group g = (Group)editorGroups.elementAt(i);
			if (userGroups.contains(g.getKey()))
				return true;
			
		}
		
		return false;
	}
	
	
	
	
}
