package de.uka.ipd.consensus.foundation.user;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import de.uka.ipd.consensus.foundation.ConsensusFoundationModule;
import de.uka.ipd.consensus.foundation.logging.LoggingManager;
import de.uka.ipd.consensus.foundation.schema.User;

/**
 * The UserManager manages the user database (creating/changing/deleting of user accounts etc.).
 * It is also responsible for the roles that can be assigned to users.
 * 
 * <p>The UserManager implementation can be configured with the key <code>cf.usermanager</code>
 * in the <code>ConsensusFoundation.properties</code> configuration file. It's a core component and not optional.</p>
 * 
 * <p>The implementation is loaded by the <code>ConsensusFoundation</code> constructor. For successful instantiation,
 * the UserManager implementation must provide a default constructor without arguments.</p>
 * 
 * @author Thomas Much
 * @version 2006-06-14
 * @see de.uka.ipd.consensus.foundation.ConsensusFoundation
 */
public interface UserManager extends ConsensusFoundationModule {

	/**
	 * <p>This method is called by the <code>ConsensusFoundation</code> constructor to initialize the UserManager.
	 * <p>The UserManager should create default user roles here (e.g. an admin role).</p>
	 * @param config all entries from <code>ConsensusFoundation.properties</code>
	 * @param logging the successfully initialized LoggingManager instance
	 * @throws Exception if any error occurs (startup of the application is aborted in this case)
	 * @see de.uka.ipd.consensus.foundation.ConsensusFoundation#ConsensusFoundation()
	 */
	public void init(Properties config, LoggingManager logging) throws Exception;

	
	/**
	 * Loads a user by the given username and password and sets his status to "logged on".
	 * @param username the username for the user to be loaded and logged on
	 * @param password the password for the username
	 * @return the User object loaded from the user database
	 * @throws UserManagerException if the username does not exist or the password is wrong
	 * @see de.uka.ipd.consensus.foundation.schema.User#isLoggedOn()
	 */
	public User login(String username, String password) throws UserManagerException;
	
	
	/**
	 * Sets a user's status to "logged off".
	 * @param user the user to be logged off
	 * @throws UserManagerException if the user isn't logged on
	 * @see de.uka.ipd.consensus.foundation.schema.User#isLoggedOn()
	 */
	public void logout(User user) throws UserManagerException;
	

	/**
	 * Creates a new user accout with the given username and password, and sets the new user's status to "logged on".
	 * <p>An implementation can define keys for passing additional user information (first name, last name, e-mail address etc.) in the data map.</p>
	 * @param username the username for the new user account
	 * @param password the password for the username
	 * @param data implementation-specific data
	 * @return the newly created user
	 * @throws UserManagerException if the username is invalid or already in use
	 */
	public User createUser(String username, String password, Map data) throws UserManagerException;
	
	
	/**
	 * Changes an existing user account.
	 * @param user the User object to be changed
	 * @param oldPassword the old password or <code>null</code> if the password is not to be changed
	 * @param newPassword a new password or <code>null</code> if the password is not to be changed
	 * @param data implementation-specific data (e.g. for the real name and e-mail address)
	 * @throws UserManagerInvalidUsernameException if the old password is wrong
	 * @throws UserManagerException if the user data could not be changed
	 */
	public void changeUser(User user, String oldPassword, String newPassword, Map data) throws UserManagerException;
	
	
	/**
	 * Deletes a user account permanently from the user database.
	 * @param user the user account to be deleted
	 * @param password the password for the account
	 * @throws UserManagerInvalidUsernameException if the password is wrong
	 * @throws UserManagerException if the user account could not be deleted
	 */
	public void deleteUser(User user, String password) throws UserManagerException;

	
	/**
	 * Returns all users in the user database.
	 * @return an Iterator over all User objects
	 * @throws UserManagerException if the users could not be read
	 * @see de.uka.ipd.consensus.foundation.schema.User
	 */
	public Iterator getUsers() throws UserManagerException;
	
	
	/**
	 * Returns a User with the given username.
	 * @param username the username of the user to be returned
	 * @return the User object with the given username or <code>null</code> if no user with the given username exists
	 * @throws UserManagerException if the user data could not be read
	 * @see de.uka.ipd.consensus.foundation.schema.User#getUsername()
	 */
	public User getUserByUsername(String username) throws UserManagerException;
	
	
	/**
	 * Returns a User with the given id.
	 * @param userid the id of the user to be returned
	 * @return the User object with the given id or <code>null</code> if no user with the given id exists
	 * @throws UserManagerException if the user data could not be read
	 * @see de.uka.ipd.consensus.foundation.schema.User#getId()
	 */
	public User getUserById(String userid) throws UserManagerException;


	/**
	 * Returns a collection of all UserRole objects that the UserManager provides.
	 * @return a collection of all UserRole objects
	 * @see UserRole
	 */
	public Collection getRoles();
	
	
	/**
	 * Returns a UserRole by the given name (e.g. "admin").
	 * @param rolename the name of the role to be returned
	 * @return the UserRole or <code>null</code> if no role with the given name exists
	 */
	public UserRole findRole(String rolename);

	
	/**
	 * Registers a new UserListener.
	 * @param listener the UserListener to be added
	 */
	public void addUserListener(UserListener listener);
	
	
	/**
	 * Removes an UserListener, if it is registered with the UserManager (otherwise this call is ignored).
	 * @param listener the UserListener to be removed
	 */
	public void removeUserListener(UserListener listener);

}
