/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

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

package org.bodington.assessment;

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 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;
            }
        }
	}
