/* ======================================================================
The Bodington System Software License, Version 1.0
  
Copyright (c) 2001 The University of Leeds.  All rights reserved.
  
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1.  Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2.  Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3.  The end-user documentation included with the redistribution, if any,
must include the following acknowledgement:  "This product includes
software developed by the University of Leeds
(http://www.bodington.org/)."  Alternately, this acknowledgement may
appear in the software itself, if and wherever such third-party
acknowledgements normally appear.

4.  The names "Bodington", "Nathan Bodington", "Bodington System",
"Bodington Open Source Project", and "The University of Leeds" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
d.gardner@leeds.ac.uk.

5.  The name "Bodington" may not appear in the name of products derived
from this software without prior written permission of the University of
Leeds.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  TITLE,  THE IMPLIED WARRANTIES 
OF QUALITY  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO 
EVENT SHALL THE UNIVERSITY OF LEEDS OR ITS CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
=========================================================

This software was originally created by the University of Leeds and may contain voluntary 
contributions from others.  For more information on the Bodington Open Source Project, please 
see http://bodington.org/

====================================================================== */

package org.bodington.assessment;

import java.rmi.RemoteException;
import java.sql.Timestamp;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.Iterator;

import org.bodington.sqldatabase.*;
import org.bodington.database.*;
import org.bodington.server.BuildingServerException;

/**
 * Class that encapsulates a users response to a questionnaire. This class
 * pertains to the questionnaire as a whole. It includes information such as 
 * who the corresponding user is and when the questionnaire was started / saved
 * to the database.
 * @see org.bodington.assessment.Questionnaire
 * @author Jon Maber
 * @author Alexis O'Connor
 */
public class QuestionnaireResult extends org.bodington.sqldatabase.SqlPersistentObject
	{
    private PrimaryKey primary_key;
    private PrimaryKey questionnaire_id;
	private PrimaryKey user_id;
	private java.sql.Timestamp when_started;
	private java.sql.Timestamp when_saved;
    
    /**
     * Creates a blank instance of this class.
     */
    public QuestionnaireResult()
        {
        }
    
    /**
     * Find the specified result.
     * @param key the ID of the result you want to find.
     * @return the required result.
     * @see #getQuestionnaireResultId()
     */
	public static QuestionnaireResult findQuestionnaireResult( PrimaryKey key )
	    throws BuildingServerException
	    {
	    return (QuestionnaireResult)findPersistentObject( 
            key, QuestionnaireResult.class.getName() );
	    }
	
	/**
     * Find the specified result.
     * @param whereSQL a string representing the <code>WHERE</code> clause of
     *        some SQL representing the criteria upon which to select the
     *        result.
	 * @return the required result.
	 */
	public static QuestionnaireResult findQuestionnaireResult( String whereSQL )
	    throws BuildingServerException
	    {
        return (QuestionnaireResult)findPersistentObject( 
            whereSQL, QuestionnaireResult.class.getName() );
	    }
	
	/**
     * Find the specified results.
     * @param whereSQL a string representing the <code>WHERE</code> clause of
     *        some SQL representing the criteria upon which to select the
     *        results.
	 * @return an enumeration of instances of this class.
	 */
	public static Enumeration findQuestionnaireResults( String whereSQL )
	    throws BuildingServerException
	    {
	    return findPersistentObjects( whereSQL, QuestionnaireResult.class.getName() );
	    }
	
	/**
     * Find the specified results.
     * @param whereSQL a string representing the <code>WHERE</code> clause of
     *        some SQL representing the criteria upon which to select the
     *        results.
     * @param orderSQL a string representing the <code>ORDER BY</code> clause of
     *        some SQL representing the criteria upon which to order the
     *        results.
     * @return an enumeration of instances of this class.
	 */
	public static Enumeration findQuestionnaireResults( String whereSQL, String orderSQL )
	    throws BuildingServerException
	    {
	    return findPersistentObjects( whereSQL, orderSQL, QuestionnaireResult.class.getName() );
	    }
	
    /**
     * Find the specified results. This method provides a way of retrieving all
     * the results to a given questionnaire.
     * @param questionnaireID the ID of the questionnaire.
     * @return an enumeration of results matching the search criteria.
     * @see #getQuestionnaireId()
     */
    public static Enumeration findQuestionnaireResults(
        PrimaryKey questionnaireID ) throws BuildingServerException
        {
        return findQuestionnaireResults( "resource_id = " + questionnaireID );
        }
    
    public PrimaryKey getPrimaryKey()
    	{
        return primary_key;
    	}

    public void setPrimaryKey(PrimaryKey key)
    	{
        primary_key = key;
        setUnsaved();
    	}

	public PrimaryKey getQuestionnaireResultId()
		{
		return getPrimaryKey();
		}
		
	public void setQuestionnaireResultId( PrimaryKey id )
		{
		setPrimaryKey(id);
		}

    /**
     * Kept for backwards compatibility. This class is <em>not</em> an
     * instance of {@link org.bodington.server.resources.Resource} therefore it
     * should not have this method. Unfortunately, it's use is embedded in the
     * persistence layer so it is maintained for the time being. In practice,
     * the value of this property is synonymous with
     * {@link #getQuestionnaireId()}, which is why you should call that method
     * directly instead.
     * @return the ID.
     * @deprecated Use {@link #getQuestionnaireId()} instead.
     */
    public PrimaryKey getResourceId()
        {
        return getQuestionnaireId();
        }
		
    /**
     * Kept for backwards compatibility. This class is <em>not</em> an
     * instance of {@link org.bodington.server.resources.Resource} therefore it
     * should not have this method. Unfortunately, it's use is embedded in the
     * persistence layer so it is maintained for the time being.
     * @param id the ID to set.
     * @deprecated Use {@link #setQuestionnaireId(PrimaryKey)} instead.
     * @see #getResourceId()
     */
    public void setResourceId( PrimaryKey id )
        {
        setQuestionnaireId(id);
        }
    
	/**
     * Get the ID of the user to which this response refers.
	 * @return the ID of the user to which this response refers.
     * @see org.bodington.server.realm.User
	 */
	public PrimaryKey getUserId()
		{
		return user_id;
		}
		
	/**
     * Set the ID of the user to which this response refers.
	 * @param id the ID of the user to which this response refers.
     * @see #getUserId()
	 */
	public void setUserId( PrimaryKey id )
		{
		user_id = id;
		setUnsaved();
		}

	/**
     * Get the time stamp of when the user started recording their response.
	 * @return the time stamp of when the user started recording their response.
	 */
	public Timestamp getWhenStarted()
		{
		return when_started;
		}
		
	/**
     * Set the time stamp of when the user started recording their response. 
	 * @param t the time stamp of when the user started recording their response.
     * @see #getWhenStarted()
	 */
	public void setWhenStarted( Timestamp t )
		{
		when_started = t;
		setUnsaved();
		}
		
	/**
     * Get the time stamp of when this object was saved to the database.
	 * @return the time stamp of when this object was saved to the database.
	 */
	public Timestamp getWhenSaved()
		{
		return when_saved;
		}
		
	/**
     * Set the time stamp of when this object was saved to the database.
	 * @param t the time stamp of when this object was saved to the database.
     * @see #getWhenSaved()
	 */
	public void setWhenSaved( Timestamp t )
		{
		when_saved = t;
		setUnsaved();
		}
    
    /**
     * Get a map of the responses associated with this instance. The form of the
     * returned map is as follows:
     * 
     * <pre>
     * <code>
     *   Map &lt;{@link QuestionnaireResponse#getQuestionnaireQuestionId()}, 
     *     {@link QuestionnaireResponse}&gt;
     * </code>
     * </pre>
     * 
     * If a given question has no response, the map will return
     * <code>null</code>.
     * @return a map of the responses associated with this instance.
     * @see QuestionnaireResponse
     */
    public Map getQuestionnaireResponses()
        throws RemoteException, BuildingServerException
        {
        Hashtable map = new Hashtable();
        // Query what the recorded responses are.
        Enumeration responses 
            = QuestionnaireResponse.findQuestionnaireResponses( 
                "questionnaire_result_id = " + getPrimaryKey() );

        while ( responses.hasMoreElements() )
            {
            QuestionnaireResponse response 
                = (QuestionnaireResponse)responses.nextElement();
            map.put( response.getQuestionnaireQuestionId(), response );
            }

        return map;
        }
    
    /**
     * Get the ID of the associated questionnaire. This is the questionnaire to
     * which this instance is a result.
     * <p>
     * NOTE: for legacy reasons, the corresponding name for this field in the
     * persistence layer is currently <code>resource_id</code>.
     * @return the ID of the associated questionnaire.
     */
    public PrimaryKey getQuestionnaireId()
        {
        return questionnaire_id;
        }
    
    /**
     * Set the ID of the associated questionnaire.
     * @param id the ID of the associated questionnaire.
     * @see #getQuestionnaireId()
     */
    public void setQuestionnaireId(PrimaryKey id)
        {
        questionnaire_id = id;
        setUnsaved();
        }

    /**
     * Get the associated questionnaire. This is the questionnaire
     * to which this object is a users questionnaire result. 
     * @return the associated questionnaire.
     * @see #getQuestionnaireId()
     */
    public Questionnaire getQuestionnaire()
        {
        // TODO: we could cache this as an instance variable:
        try
            {
            return Questionnaire.findQuestionnaire(getQuestionnaireId());
            }
        catch (BuildingServerException e)
            {
            return null;
            }
        }
	}
