/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.sword;

import java.sql.SQLException;

import org.dspace.core.Context;
import org.dspace.eperson.EPerson;

/**
 * This class holds information about authenticated users (both the
 * depositing user and the on-behalf-of user), and their associated
 * DSpace Context objects.
 *
 * Since this class will be used to make authentication requests on
 * both user types, it may hold up to 2 active DSpace Context objects
 * at any one time
 *
 * WARNING: failure to use the contexts used in this class in the
 * appropriate way may result in exceptions or data loss.  Unless
 * you are performing authentication processes, you should always
 * access the context under which to deposit content into the archive
 * from:
 *
 * getContext()
 *
 * and not from any of the other context retrieval methods in this
 * class
 * 
 * @author Richard Jones
 *
 */
public class SWORDContext 
{
	/** The primary authenticated user for the request */
	private EPerson authenticated = null;
	
	/** The onBehalfOf user for the request */
	private EPerson onBehalfOf = null;

	/** The primary context, representing the on behalf of user if exists, and the authenticated user if not */
	private Context context;

	/** the context for the authenticated user, which may not, therefore, be the primary context also */
	private Context authenticatorContext;

	/**
	 * @return	the authenticated user
	 */
	public EPerson getAuthenticated() 
	{
		return authenticated;
	}

	/**
	 * @param authenticated	the eperson to set
	 */
	public void setAuthenticated(EPerson authenticated) 
	{
		this.authenticated = authenticated;
	}

	/**
	 * @return	the onBehalfOf user
	 */
	public EPerson getOnBehalfOf() 
	{
		return onBehalfOf;
	}

	/**
	 * @param onBehalfOf	the eperson to set
	 */
	public void setOnBehalfOf(EPerson onBehalfOf) 
	{
		this.onBehalfOf = onBehalfOf;
	}

	/**
	 * Returns the most appropriate context for operations on the
	 * database.  This is the on-behalf-of user's context if the
	 * user exists, or the authenticated user's context otherwise.
	 */
	public Context getContext()
	{
		return context;
	}

	public void setContext(Context context)
	{
		this.context = context;
	}

	/**
	 * Get the context of the user who authenticated.  This should only be
	 * used for authentication purposes.  If there is an on-behalf-of user,
	 * that context should be used to write database changes.  Use:
	 *
	 * getContext()
	 *
	 * on this class instead.
	 */
	public Context getAuthenticatorContext()
	{
		return authenticatorContext;
	}

	public void setAuthenticatorContext(Context authenticatorContext)
	{
		this.authenticatorContext = authenticatorContext;
	}

	/**
	 * Get the context of the on-behalf-of user.  This method should only
	 * be used for authentication purposes.  In all other cases, use:
	 *
	 * getContext()
	 *
	 * on this class instead.  If there is no on-behalf-of user, this
	 * method will return null.
	 */
	public Context getOnBehalfOfContext()
	{
		// return the obo context if this is an obo deposit, else return null
		if (this.onBehalfOf != null)
		{
			return context;
		}
		return null;
	}

	/**
	 * Abort all of the contexts held by this class.  No changes will
	 * be written to the database
	 */
	public void abort()
	{
		// abort both contexts
		if (context != null && context.isValid())
		{
			context.abort();
		}

		if (authenticatorContext != null && authenticatorContext.isValid())
		{
			authenticatorContext.abort();
		}
	}

	/**
	 * Commit the primary context held by this class, and abort the authenticated
	 * user's context if it is different.  This ensures that only changes written
	 * through the appropriate user's context is persisted, and all other
	 * operations are flushed.  You should, in general, not try to commit the contexts directly
	 * when using the sword api.
	 *
	 * @throws DSpaceSWORDException
	 */
	public void commit()
			throws DSpaceSWORDException
	{
		try
		{
			// commit the primary context
			if (context != null && context.isValid())
			{
				context.commit();
			}

			// the secondary context is for filtering permissions by only, and is
			// never committed, so we abort here
			if (authenticatorContext != null && authenticatorContext.isValid())
			{
				authenticatorContext.abort();
			}
		}
		catch (SQLException e)
		{
			throw new DSpaceSWORDException(e);
		}
	}
}
