/* ======================================================================
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.servlet.facilities;

import org.apache.log4j.Logger;

import java.rmi.RemoteException;

import org.bodington.servlet.*;

import java.util.*;
import java.sql.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.math.BigDecimal;

import org.bodington.database.PrimaryKey;
import org.bodington.server.*;
import org.bodington.server.resources.Resource;
import org.bodington.server.resources.ResourceUtils;
import org.bodington.server.BuildingContext;
import org.bodington.server.events.*;
import org.bodington.server.realm.Permission;
import org.bodington.server.realm.User;
import org.bodington.util.DateFormatter;
import org.bodington.assessment.*;



public class TextQFacility extends org.bodington.servlet.facilities.Facility
	{
	
    private static Logger log = Logger.getLogger(TextQFacility.class);

	static final BigDecimal max_weight = new BigDecimal( "100.0" );
	
    public boolean canCopy( Resource resource )
    {
        return true;
    }
    
	public Resource newResource()
		{
		return new TextQPaper();
		}
	
	
	public boolean initResource( Request breq, Resource new_resource )
		throws Exception
		{
		if ( !(new_resource instanceof TextQPaper) )
			throw new Exception( "Technical problem: An incorrect type of resource was created." );
		
		TextQPaper tq;
		tq = (TextQPaper)new_resource;

		String param, strdate;
		java.util.Date date;
		java.sql.Timestamp sqldate=null;

		param=breq.getParameter( "general_notes" );
		tq.setGeneralNotes( param==null?"":param );

		param=breq.getParameter( "general_available" );
		tq.setGeneralAvailable( Integer.parseInt( param ) );

		param=breq.getParameter( "general_weight" );
		tq.setGeneralWeight( new BigDecimal( param==null?"0.0":param ) );

		param=breq.getParameter( "maxmark" );
		tq.setMaximumMark( Integer.parseInt( param ) );


		strdate=breq.getParameter( "date_open" );
		tq.setDateOpen( null );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					throw new Exception( "The opening date couldn't be understood." );
				else
					tq.setDateOpen( new java.sql.Timestamp( date.getTime() ) );
				}
			}
		strdate=breq.getParameter( "date_deadline" );
		tq.setDateDeadline( null );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					throw new Exception( "The deadline date couldn't be understood." );
				else
					tq.setDateDeadline( new java.sql.Timestamp( date.getTime() ) );
				}
			}
		strdate=breq.getParameter( "date_penalty" );
		tq.setDatePenalty( null );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					throw new Exception( "The penalty period date couldn't be understood." );
				else
					tq.setDatePenalty( new java.sql.Timestamp( date.getTime() ) );
				}
			}
		
		return true;  
		}
		
	public boolean initResource( Resource original_resource, Resource new_resource )
		throws BuildingServerException
		{
		if ( !(new_resource instanceof TextQPaper) )
		  throw new BuildingServerException( "Error: The wrong type of resource was created." );

		TextQPaper original = (TextQPaper)original_resource;
		TextQPaper new_paper = (TextQPaper)new_resource;

		new_paper.setDateOpen( original.getDateOpen() );
		new_paper.setDateDeadline( original.getDateDeadline() );
		new_paper.setDatePenalty( original.getDatePenalty() );
		new_paper.setGeneralNotes( original.getGeneralNotes() );
		new_paper.setGeneralAvailable( original.getGeneralAvailable() );
		new_paper.setGeneralWeight( original.getGeneralWeight() );
		new_paper.setMaximumMark( original.getMaximumMark() );

		return true;
	}


    /**
     * Copy the content of one resource to another. <p>
     * <h4>Content copied</h4>
     * <ul>
     * <li>authored questions.
     * </ul>
     * <h4>Content <em>not</em> copied</h4>
     * <ul>
     * <li>user answers.
     * </ul>
     * </p>
     * @param original_resource the resource whose contents are to be copied.
     * @param new_resource the resource to copy content to.
     * @param breq the building request object.
     * @throws BuildingServerException if there is any problem copying the
     *         resource content.
     */
	public void copyContent( Resource original_resource, Resource new_resource, Request breq )
		throws BuildingServerException
		{
//	  authored : questions
//	  userdata : answers? /** @todo  */

		 BuildingSession session = BuildingSessionManagerImpl.getSession( original_resource );
		 if ( !(session instanceof TextQSession) )
		   throw new BuildingServerException( "Unable to access appropriate resource session." );

		 try
		 {
		   if ( breq.getParameter( "authored" ) != null )
		   {
		     copyAuthoredContent( original_resource, new_resource );
//		     if ( breq.getParameter( "userdata" ) != null )
//                       copyUserContent( original_resource, new_resource );
		   }
		 }
		 catch (Exception ex)
		 {
		   throw new BuildingServerException( ex.getMessage() );
		 }
	}


    /**
     * Copy the authored content of an existing Resource to another Resource. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i>
     * @param original_resource The resource with content to copy.
     * @param new_resource The resource to copy content to.
     * @exception BuildingServerException Thrown if there is any problem copying the resource content.
     * @exception RemoteException Thrown if there is any problem copying the resource content.
     *
     */
	private void copyAuthoredContent( Resource original_resource, Resource new_resource )
	        throws BuildingServerException, RemoteException
	        {
	         TextQSession session;
	         Vector questions;
	         TextQuestion orig_question, new_question;

	         session = (TextQSession)BuildingSessionManagerImpl.getSession( original_resource );
	         questions = session.getTextQuestionsInOrder();

	         for (int i=0; i<questions.size(); i++ )
	         {
	           orig_question = (TextQuestion)questions.elementAt( i );
	           new_question = new TextQuestion();
	           new_question.setResourceId( new_resource.getResourceId() );
	           new_question.setQuestion( orig_question.getQuestion() );
	           new_question.setExplanation( orig_question.getExplanation() );
	           new_question.setAvailable( orig_question.getAvailable() );
	           new_question.setNotes( orig_question.getNotes() );
	           new_question.setWeight( orig_question.getWeight() );
	           new_question.setOrdinal( orig_question.getOrdinal() );

	           new_question.save();
	         }
	}

	/**
	 * Setup the TestQ resource to a sensible state. We add Record, Mark 
	 * and Review Permissions to the owner for this.
	 */
	public boolean create(Request request, Connection connection,
        Resource resource)
    {
	    Permission grant[] = {Permission.RECORD, Permission.MARK, Permission.REVIEW};
        return ResourceUtils.grantPermissions(resource, grant);
    }
	
	public boolean createCheck( Request breq, PrintWriter out )
		{
//		try
//			{
			String param, strdate;
			java.util.Date now = new java.util.Date();
			java.util.Date[] date = new java.util.Date[3];
			String p[] = { "date_open", "date_deadline", "date_penalty" };
			int n;
			BigDecimal decimal;
			
			try
				{
				param=breq.getParameter( "general_available" );
				n = Integer.parseInt( param==null?"0":param );

				if ( n<0 || n>100 )
					{
					out.println( "Available extra marks must be between 0 and 100." );
					return false;
					}
					
				param=breq.getParameter( "general_weight" );
				decimal = new BigDecimal( param==null?"0.0":param );

				if ( decimal.doubleValue() < 0.0 || decimal.doubleValue() > 100.0  )
					{
					out.println( "Weighting for extra marks must be between 0.0 and 100.0." );
					return false;
					}

				param=breq.getParameter( "maxmark" );
				n = Integer.parseInt( param==null?"0":param );
				
				if ( n<0 || n>100 )
					{
					out.println( "Maximum marks must be between 0 and 100." );
					return false;
					}
				
				}
			catch ( NumberFormatException nfex )
				{
				out.println( "Invalid numbers were entered in the form." );
				return false;
				}

			for ( int i=0; i<3; i++ )
				{
				strdate=breq.getParameter( p[i] );
				if ( strdate!=null )
					{
					strdate=strdate.trim();
					if ( strdate.length()>0 )
						{
						date[i]=DateParser.parse( strdate );
						}
					}
				if ( date[i]==null )
					{
					out.println( "You must enter valid dates in all three date fields." );
					return false;
					}
				}

			if ( date[0].after( date[1] ) || date[1].after( date[2] ) )
				{
				out.println( "The opening date cannot be after the deadline date and the deadline date cannot be after the penalty date." );
				return false;
				}
			
			if ( date[1].before( now ) || date[1].getYear() > (now.getYear()+100) )
				{
				out.println( "The deadline date must be in the future but not in the extreme distant future." );
				return false;
				}
			if ( date[2].before( now ) || date[2].getYear() > (now.getYear()+100) )
				{
				out.println( "The penalty date must be in the future but not in the extreme distant future." );
				return false;
				}
//			}
//		catch ( IOException ioex )
//			{
//			return false;
//			}
		return true;  
		}

	

	public void insert( Request req, PrintWriter out, String command, String insertname )
		throws ServletException, IOException
		{
		log.debug( Thread.currentThread().getName() + " TextQFacility insert()" );

		try
			{
			BuildingSession session;
			TextQSession tq_session;

			session = BuildingSessionManagerImpl.getSession( req.getResource() );
			if ( !(session instanceof TextQSession) )
		    	{
		    	out.println( "<HR>Technical problem: unable to access appropriate tool session.<HR>" );
		    	return;
		    	}
			tq_session = (TextQSession)session;
			

			if ( 
		    	command.equalsIgnoreCase( "entrystatuslist" ) ||
		    	command.equalsIgnoreCase( "entrystatusconfirm" ) ||
		    	command.equalsIgnoreCase( "adjustedmarkconfirm" ) ||
		    	command.equalsIgnoreCase( "textqmarkconfirm" ) ||
		    	command.equalsIgnoreCase( "textqfield" ) ||
		    	command.equalsIgnoreCase( "textqmodify" ) ||
		    	command.equalsIgnoreCase( "textqpaper" ) ||
		    	command.equalsIgnoreCase( "textqrecord" ) ||
		    	command.equalsIgnoreCase( "textqitemedit" ) ||
		    	command.equalsIgnoreCase( "textqeditqconfirm" ) ||
		    	command.equalsIgnoreCase( "textqdeleteq" ) ||
		    	command.equalsIgnoreCase( "textqmarklist" ) ||
		    	command.equalsIgnoreCase( "textqstatuslist" ) ||
		    	command.equalsIgnoreCase( "textqstatusconfirm" ) ||
		    	command.equalsIgnoreCase( "textqmarkconfirm" ) ||
		    	command.equalsIgnoreCase( "textqremark" ) ||
		    	command.equalsIgnoreCase( "textqrunbutton" ) ||
		    	command.equalsIgnoreCase( "iftextqstage" ) ||
		    	command.equalsIgnoreCase( "ifcanup" ) ||
		    	command.equalsIgnoreCase( "ifentry" ) ||
		    	command.equalsIgnoreCase( "noupmessage" ) ||
				command.equalsIgnoreCase( "textqnewq" )	)
				{

				/*
				if ( command.equalsIgnoreCase( "iftextqstage" ) )
					{
					if ( canMark( req, textq ) )
						req.setSwitchedOff(  !insertname.equalsIgnoreCase( "review" ) );
					else
						req.setSwitchedOff(  !insertname.equalsIgnoreCase( "attempt" ) );
					return;
					}
				*/

				if ( out==null )
					return;

				if ( command.equalsIgnoreCase( "ifcanup" ) )
					ifcanup( req, out, tq_session );

				if ( command.equalsIgnoreCase( "ifentry" ) )
					ifentry( req, out, tq_session );

				if ( command.equalsIgnoreCase( "noupmessage" ) )
					noupmessage( req, out, tq_session );

				if ( command.equalsIgnoreCase( "textqfield" ) )
					textqfield( req, out, tq_session, insertname );

				if ( command.equalsIgnoreCase( "textqmodify" ) )
					textqmodify( req, out, tq_session );

				if ( command.equalsIgnoreCase( "textqpaper" ) )
					textqpaper( req, out, tq_session, insertname );

				if ( command.equalsIgnoreCase( "textqmarklist" ) )
					textqlist( req, out, tq_session );

				//if ( command.equalsIgnoreCase( "textqstatuslist" ) )
				//	textqstatuslist( req, out, tq_session );

				if ( command.equalsIgnoreCase( "adjustedmarkconfirm" ) )
					adjustedmarkconfirm( req, out, tq_session );

				if ( command.equalsIgnoreCase( "textqmarkconfirm" ) )
					textqmarkconfirm( req, out, tq_session );

				//if ( command.equalsIgnoreCase( "textqstatusconfirm" ) )
				//	textqstatusconfirm( req, out, tq_session );

				if ( command.equalsIgnoreCase( "entrystatuslist" ) )
					entrystatuslist( req, out, tq_session );

				if ( command.equalsIgnoreCase( "entrystatusconfirm" ) )
					entrystatusconfirm( req, out, tq_session );

				//if ( command.equalsIgnoreCase( "textqconfirm" ) )
				//	textqconfirm( req, out, tq_session );

				//if ( command.equalsIgnoreCase( "textqremark" ) )
				//	textqremark( req, out, tq_session );

				if ( command.equalsIgnoreCase( "textqrecord" ) )
					textqrecord( req, out, tq_session, insertname );
				if ( command.equalsIgnoreCase( "textqnewq" ) )
					textqnewq( req, out, tq_session, insertname );
				if ( command.equalsIgnoreCase( "textqitemedit" ) )
					textqitemedit( req, out, tq_session, insertname );
				if ( command.equalsIgnoreCase( "textqeditqconfirm" ) )
					textqeditqconfirm( req, out, tq_session, insertname );
				if ( command.equalsIgnoreCase( "textqdeleteq" ) )
					textqdeleteq( req, out, tq_session );
				if ( command.equalsIgnoreCase( "textqrunbutton" ) )
					textqrunbutton( req, out, tq_session );
				
				return;
				}
			}
		catch ( BuildingServerException bsex )
			{
			out.println( bsex.toString() );
			return;
			}
		
		super.insert( req, out, command, insertname );
		}


	//i.e. can submit answers to questions
	private void ifcanup( Request req, PrintWriter out, TextQSession tq_session )
		throws ServletException, IOException
		{
		try
			{
			if ( tq_session.canSubmit() )
				req.setSwitchedOff(  false );
			else
				req.setSwitchedOff(  true );
			}
		catch ( Exception ex )
			{
			logException( null, "TextQFacility", "ifcanup", 
			    "Technical error looking for an entry in the database.",
			    ex );
			return;
			}
		}	


	private void noupmessage( Request req, PrintWriter out, TextQSession tq_session )
		throws ServletException, IOException
		{
		try
			{
			if ( !tq_session.canSubmit() )
				out.print( tq_session.denySubmitMessage() );
			}
		catch ( Exception ex )
			{
			logException( null, "TextQFacility", "noupmessage", 
			    "Technical error looking for an entry in the database.",
			    ex );
			return;
			}
		}	



	private void ifentry( Request req, PrintWriter out, TextQSession tq_session )
		throws ServletException, IOException
		{
		try
			{
			TextQResult entry=tq_session.getTextQResult();
			if ( entry!=null )
				req.setSwitchedOff(  false );
			else
				req.setSwitchedOff(  true );
				
			}
		catch ( Exception ex )
			{
			logException( null, "TextQFacility", "ifentry", 
			    "Technical error looking for an entry in the database.",
			    ex );
			return;
			}
		}	
	



	private void questionToHTML( TextQuestion question, PrintWriter out, String style, TextQResponse response )
		throws IOException, BuildingServerException
		{

		if ( style.equalsIgnoreCase( "edit" ) )
			out.println( "<TR><TD><B>Question</B></TD></TR>" );
		out.println( "<TR><TD>" );
		out.println( question.getQuestion() );
		out.println( "</TD></TR>" );

		if ( style.equalsIgnoreCase( "edit" ) || style.equalsIgnoreCase( "reviewmark" ) )
			{
			String e = null;
			e = question.getExplanation();
			if ( e==null )
				e = "";
			else
				e = e.trim();
			
			if ( e.length()>0 )
				{
				out.println( "<TR><TD><B>Explanation</B></TD></TR><TR><TD>" );
				out.println( e );
				out.println( "</TD></TR>" );
				}
			}
		
		if ( style.equalsIgnoreCase( "edit" ) || style.equalsIgnoreCase( "mark" ) )
			{
			out.println( "<TR><TD><B>Notes</B></TD></TR><TR><TD>" );
			out.println( question.getNotes() );
			out.println( "</TD></TR>" );
			}

		if (	style.equalsIgnoreCase( "view" ) || 
				style.equalsIgnoreCase( "review" ) || 
				style.equalsIgnoreCase( "mark" )		)
			{
			String r = null;
			if ( response!=null )
				r = response.getResponse();
			if ( r==null )
				r = "";
				
			out.println( "<TR><TD><B>Your Response</B></TD></TR><TR><TD>" );
			if ( style.equalsIgnoreCase( "view" ) )
				{
				out.print( "<SPAN CLASS=bs-textarea><TEXTAREA COLS=70 ROWS=5 NAME=Q" );
				out.print( question.getTextQuestionId().toString() );
				out.print( ">" );
				out.print( r );
				out.println( "</TEXTAREA></SPAN>" );
				}
			else
				out.println( r );
			out.println( "</TD></TR>" );
			}


		if ( style.equalsIgnoreCase( "mark" ) )
			{
			String f = null;
			if ( response!=null )
				f = response.getFeedback();
			if ( f==null )
				f = "";
			else
				f = f.trim();
				
			out.println( "<TR><TD><B>Feedback</B></TD></TR><TR><TD>" );
			out.print( "<SPAN CLASS=bs-textarea><TEXTAREA NAME=QF" );
			out.print( question.getTextQuestionId().toString() );
			out.print( ">" );
			if ( f.length()>0 )
				out.print( f );
			out.println( "</TEXTAREA></SPAN>" );
			out.println( "</TD></TR>" );
			}
		if ( style.equalsIgnoreCase( "reviewmark" ) )
			{
			String f = null;
			if ( response!=null )
				f = response.getFeedback();
			if ( f==null )
				f = "";
			else
				f = f.trim();
				
			if ( f.length()>0 )
				{
				out.println( "<TR><TD><B>Feedback</B></TD></TR><TR><TD>" );
				out.print( f );
				out.println( "</TD></TR>" );
				}
			}


		
		if ( style.equalsIgnoreCase("mark") )
			{
			out.println( "<TR><TD><B>Mark</B></TD></TR><TR><TD>" );
			int a = question.getAvailable();
			int r=-1;

			if ( response!=null && response.getMark() != null )
				r = response.getMark().intValue();
				
			out.print( "<SELECT NAME=QR" );
			out.print( question.getTextQuestionId().toString() );
			out.println( ">" );
			if ( r==-1 )
				out.println( "<OPTION VALUE=\"-1\" SELECTED>Not Marked" );
			else
				out.println( "<OPTION VALUE=\"-1\">Not Marked" );
				
			for ( int i=0; i<=a; i++ )
				{
				if ( r==i )
					out.println( "<OPTION VALUE=\"" + i + "\" SELECTED>" + i );
				else
					out.println( "<OPTION VALUE=\"" + i + "\">" + i );
				}
			out.println( "</SELECT>" );
			}
		else
			{
			if ( style.equalsIgnoreCase( "markreview" ) )
				{
				out.println( "<TR><TD><B>Mark</B></TD></TR><TR><TD>" );
				if ( response!=null && response.getMark() != null )
					{
					out.print( response.getMark().intValue() );
					out.print( " out of " );
					out.print( question.getAvailable() );
					out.println( "." );
					}
				else
					out.println( "No mark assigned." );
				out.println( "</TD></TR>" );
				}
			else
				{
				if ( style.equalsIgnoreCase( "edit" ) )
					{
					out.println( "<TR><TD><B>Available Marks</B></TD></TR><TR><TD>" );
					out.println( question.getAvailable() );
					out.println( "</TD></TR>" );
					}
				}
			}
		
		if ( style.equalsIgnoreCase("edit") )
			{
			out.println( "<TR><TD><B>Weight</B></TD></TR><TR><TD>" );
			out.println( question.getWeight().toString() );
			out.println( "</TD></TR>" );
			}
		}
	



	//insertname == view, edit, review, mark or attempt
	private void textqpaper( Request req, PrintWriter out, TextQSession tq_session, String mode )
		throws IOException, BuildingServerException
		{
		int i;
		boolean edit, mark=false, attempt=false, review=false, canmark=false, canseemark=false;
		String param;
		PrimaryKey uid;
		
		Vector questions_in_order;
		Hashtable responses=null;
		TextQuestion q;
		TextQResult entry=null;
		TextQResponse response=null;
		TextQPaper paper = tq_session.getTextQPaper();
		
		Resource resource;

		edit = ( mode!=null && mode.equalsIgnoreCase( "edit" ) );
		mark = ( mode!=null && mode.equalsIgnoreCase( "mark" ) );

		if ( mode!=null && mode.equalsIgnoreCase( "view" ) )
			{
			attempt = tq_session.canSubmit();
			review = !attempt;
			canseemark = tq_session.canSeeMark();
			}

		if ( !edit && !mark && !attempt && !review )
			{
			out.println( "Unkown presentation format selected." );
			return;
			}
			
		if ( edit )
			{
			if ( !BuildingContext.getContext().checkPermission( Permission.EDIT ) )
				{
				out.println( "<PRE>You don't have permission to edit questions here.</PRE>\n" );
				return;
				}
			uid=null;
			}

		if ( mark )
			{
			if ( !BuildingContext.getContext().checkPermission( Permission.MARK ) )
				{
				out.println( "<PRE>You don't have permission to mark papers here.</PRE>\n" );
				return;
				}
			if ( req.getTemplateParameterCount()<1 )
				{
				out.println( "Invalid page address - no user specified" );
				return;
				}

			param=(String)req.getTemplateParameter( 0 );
			if ( param==null )
				{
				out.println( "Invalid page address - no user specified" );
				return;
				}
			uid = new PrimaryKey( Integer.parseInt( param ) );

			entry=tq_session.getTextQResult( uid );
			
			if ( entry==null )
				{
				out.println( "<HR>No database entry for this student.</HR>" );
				return;
				}
			}
			
		if ( attempt || review )
			{
			entry=tq_session.getTextQResult();
			}
			
		if ( canseemark )
			{
			if ( entry.getAdjustedMark() != null )
				{
				out.println( "<TABLE BORDER><TR><TD><B>Mark</B></TD><TD>" );
				out.println( entry.getAdjustedMark().toString() );
				out.println( "</TD></TR></TABLE>" );
				}
			if ( entry.getFeedback() != null )
				{
				out.println( "<TABLE BORDER><TR><TD><B>General Feedback</B></TD><TD>" );
				out.println( entry.getFeedback() );
				out.println( "</TD></TR></TABLE>" );
				}
			}
			
		if ( mark )
			{
			if ( entry.getStatus() == TextQResult.STATUS_UPLOAD_BY_DATE || 
				entry.getStatus() == TextQResult.STATUS_UPLOAD_CHANGEABLE  )
				{
				out.println( "<HR><CENTER><H1>This student's work is not ready for assessment.</H1></CENTER>" );
				return;
				}
				
			canmark=true;
			if ( entry.getStatus() != TextQResult.STATUS_UPLOAD_LOCKED &&
				 entry.getStatus() != TextQResult.STATUS_UPLOAD_PROCESSED )
				{
				out.println( "<HR><CENTER><H1>Assessment of this student's work is completed.</H1></CENTER>" );
				canmark=false;
				}
			if ( canmark )
				out.println( "<FORM ACTION=bs_template_textqmarkconfirm.html METHOD=POST>" );
			}
			
		if ( mark || review || attempt )
			{
			responses = null;
			
			if ( entry!=null )
				responses=tq_session.getTextQResponses( entry.getTextQResultId() );
				
			if ( responses==null )
				responses = new Hashtable();
			}
		else
			responses = null;
		
		
		if ( attempt )
			{
			out.println( "<FORM METHOD=POST ACTION=bs_template_textqrecord.html>" );
			}
		
		resource = BuildingContext.getContext().getResource();

		questions_in_order = tq_session.getTextQuestionsInOrder();
			
			
		for ( i=0; i<questions_in_order.size(); i++ )
			{
			q=(TextQuestion)questions_in_order.elementAt( i );
				
			out.print( "<P></P><TABLE BORDER><TR><TD><H4>Question " +  (i+1) );
			if ( edit )
				out.print( " (" + q.getOrdinal() + ")" );
			out.println( "</H4>" );
						
			if ( edit )
				{
				out.print( "<P><FORM METHOD=POST ACTION=\"" );
				out.print( req.getContextPath() );
				out.print( req.getServletPath() );
				out.print( resource.getFullName()  );
				out.print( q.getTextQuestionId() + "/bs_template_textqeditq.html\">" );
				out.println( "<INPUT TYPE=SUBMIT VALUE=\"Edit This Question\"></FORM></P>" );
				}
					
			out.println( "</TD></TR>" );
				
			if ( responses==null )
				response = null;
			else
				response = (TextQResponse)responses.get( q.getTextQuestionId() );
			
			if ( mark )
				{
				if ( canmark )
					questionToHTML( q, out, mode, response );
				else
					questionToHTML( q, out, "markreview", response );
				}
			else
				{
				if ( review )
					{
					if ( canseemark )
						questionToHTML( q, out, "reviewmark", response );
					else
						questionToHTML( q, out, "review", response );
					}
				else
					questionToHTML( q, out, mode, response );
				}
					
			out.println( "</TABLE>" );
			}

		if ( i==0 )
			out.println( "<P>There are currently no question in this paper.</P>" );

		if ( mark )
			{
			if ( canmark )
				{
				if ( paper.getGeneralAvailable() >0 )
					{
					out.println( "<H4>Extra Marks for General Performance</H4>" );
					out.print( "<SELECT NAME=QG>" );
					
					if ( entry.getGeneralMark()==null )
						out.println( "<OPTION VALUE=\"-1\" SELECTED>Not Marked" );
					else
						out.println( "<OPTION VALUE=\"-1\">Not Marked" );
						
					for ( i=0; i<=paper.getGeneralAvailable(); i++ )
						{
						if ( entry.getGeneralMark()!=null && entry.getGeneralMark().intValue()==i )
							out.println( "<OPTION VALUE=\"" + i + "\" SELECTED>" + i );
						else
							out.println( "<OPTION VALUE=\"" + i + "\">" + i );
						}
					out.println( "</SELECT>" );
					}
				
				out.println( "<H4>General Feedback</H4>" );
				out.print( "<SPAN CLASS=bs-textarea><TEXTAREA COLS=50 ROWS=5 NAME=feedback>" );
				if ( entry.getFeedback()!=null )
					out.print( entry.getFeedback() );
				out.println( "</TEXTAREA></SPAN><BR>" );
				out.println( "<H4>Private Comments</H4>" );
				out.print( "<SPAN CLASS=bs-textarea><TEXTAREA COLS=50 ROWS=5 NAME=comments>" );
				if ( entry.getComments()!=null )
					out.print( entry.getComments() );
				out.println( "</TEXTAREA></SPAN><BR>" );
				out.println( "<INPUT TYPE=SUBMIT VALUE=\"Save Changes\">" );
				out.println( "</FORM>" );
				}
			else
				{
				if ( BuildingContext.getContext().checkPermission( Permission.MANAGE ) && !tq_session.canSeeMark( entry.getUserId() ) )
					{
					out.println( "<HR><H4>Assign Adjusted Mark for Release</H4>" );
					out.println( "<P>The final released mark may be adjusted.  E.g." );
					out.println( " a penalty for handing in late or extra marks " );
					out.println( " because the student was absent or suffered some  " );
					out.println( " other impediment.</P>" );
					out.println( "<FORM NAME=adjustedform METHOD=POST ACTION=bs_template_adjustedmarkconfirm.html>" );
					out.println( "<TABLE CLASS=bs-table-opaque><TR><TD><B>Uploaded:</B></TD><TD><H4>" );
					if ( entry.getWhenSaved()!=null )
						{
						String d=DateFormatter.formatDate( entry.getWhenSaved(), 1 );
						out.println( d );
						}
					else
						out.println( "No date." );
					out.println( "</H4></TR><TR><TD><B>Total Mark:</B></TD><TD><H2>" );
					if ( entry.getMark()!=null )
						{
						out.println( entry.getMark().toString() );
						out.println( "<INPUT TYPE=BUTTON VALUE=\"Set\" ONCLICK=" );
						out.println( "\"adjustedform.adjustedmark.value=" );
						out.println( entry.getMark().toString() );
						out.println( "\">" );
						}
					else
						out.println( "No Mark" );
					out.println( "</H2></TD></TR><TR><TD><B>Adjusted Mark</B></TD><TD>" );
					out.print( "<INPUT NAME=adjustedmark VALUE=\"" );
					if ( entry.getAdjustedMark()!=null )
						out.print( entry.getAdjustedMark().toString() );
					out.println( "\"></TD></TR><TR><TD><B>General Feedback</B></TD><TD>" );
					out.print( "<SPAN CLASS=bs-textarea><TEXTAREA COLS=50 ROWS=5 NAME=feedback>" );
					if ( entry.getFeedback()!=null )
						out.print( entry.getFeedback() );
					out.println( "</TEXTAREA></SPAN>" );
					out.println( "</TD></TR><TR><TD><B>Private Comments</B></TD><TD>" );
					out.print( "<SPAN CLASS=bs-textarea><TEXTAREA COLS=50 ROWS=5 NAME=comments>" );
					if ( entry.getComments()!=null )
						out.print( entry.getComments() );
					out.println( "</TEXTAREA></SPAN></TD></TR><TR><TD></TD><TD>" );
					out.println( "<INPUT TYPE=SUBMIT VALUE=\"Save Adjusted Mark\">" );
					out.println( "</TD></TR></TABLE></FORM>" );
					}
				else
					{
					out.println( "<P>It isn't possible to edit marks or to save a final adjusted mark.</P>" );
					}
				}
			}			
			
		if ( attempt )
			{
			out.println( "<INPUT TYPE=SUBMIT VALUE=\"Save Responses\">" );
			out.println( "</FORM>" );
			}
		
		}




	
	private void textqmarkconfirm(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int i;
		Vector questions_in_order;
		PrimaryKey[] qids;
		int[] marks;
		String[] feedback_list;
		String feedback, comments, uid;
		PrimaryKey user_id;
		TextQuestion q;
		TextQResult entry;

		
		if ( !BuildingContext.getContext().checkPermission( Permission.MARK ) )
			{
			out.println( "<PRE>You don't have permission to mark papers here.</PRE>\n" );
			return;
			}

		if ( req.getTemplateParameterCount()<1 )
			{
			out.println( "Invalid page address - no user specified" );
			return;
			}

		uid=(String)req.getTemplateParameter( 0 );
		if ( uid==null )
			{
			out.println( "Invalid page address - no user specified" );
			return;
			}

		user_id = new PrimaryKey( Integer.parseInt( uid ) );
		entry = tq_session.getTextQResult( user_id );
		if ( entry == null )
			{
			out.println( "Unable to find database entry." );
			return;
			}
		
		
		questions_in_order = tq_session.getTextQuestionsInOrder();
		qids = new PrimaryKey[questions_in_order.size()];
		marks = new int[questions_in_order.size()+1];				//extra entry for general mark
		feedback_list=new String[questions_in_order.size()];

		feedback=req.getParameter( "feedback" );
		comments=req.getParameter( "comments" );
		if ( feedback==null || comments==null )
			{
			out.println( "<HR>Invalid form input.<HR>" );
			return;
			}
		
		for ( i=0; i<questions_in_order.size(); i++ )
			{
			q=(TextQuestion)questions_in_order.elementAt( i );
			
			qids[i] = q.getTextQuestionId();
			
			marks[i] = Integer.parseInt( req.getParameter( "QR" + q.getTextQuestionId() ) );
			
			if ( marks[i]<0 )
				out.println( "Warning: no mark assigned for category " + (i+1) + "<BR>" );
				
			feedback_list[i] = req.getParameter( "QF" + q.getTextQuestionId() );
			}

		//general marks.
		marks[i]=-1;
		if ( req.getParameter( "QG" )!=null && req.getParameter( "QG" ).length()>0 )
			{
			marks[i] = Integer.parseInt( req.getParameter( "QG" ) );
			if ( marks[i]<0 )
				out.println( "Warning: no mark assigned under the general performance category <BR>" );
			}
			
		entry = tq_session.recordMarks( 	entry.getTextQResultId(), 
											qids, 
											marks, 
											feedback_list, 
											feedback, 
											comments );
			
		out.println( "<P>Entries were recorded." );
		
		if ( entry!=null && entry.getMark() != null )
			{
                        //set a provisional adjusted mark
                        entry.setAdjustedMark(entry.getMark());
                            
			out.print( "<BR>The total mark, before moderation is " );
			out.print( entry.getMark().toString() );
			out.print( " out of " );
			TextQPaper tq = tq_session.getTextQPaper();
			out.print( tq.getMaximumMark() );
			out.println( "." );
			}
		else
			out.println( "Marking is incomplete for this work." );
			
		out.print( "</P>" );
		}
	

	private void adjustedmarkconfirm(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int i, amark;
		Vector questions_in_order;
		PrimaryKey[] qids;
		String feedback, comments, uid;
		PrimaryKey user_id;
		TextQuestion q;
		TextQResult entry;

		
		if ( !BuildingContext.getContext().checkPermission( Permission.MARK) )
			{
			out.println( "<PRE>You don't have permission to mark papers here.</PRE>\n" );
			return;
			}

		if ( req.getTemplateParameterCount()<1 )
			{
			out.println( "Invalid page address - no user specified" );
			return;
			}

		uid=(String)req.getTemplateParameter( 0 );
		if ( uid==null )
			{
			out.println( "Invalid page address - no user specified" );
			return;
			}

		user_id = new PrimaryKey( Integer.parseInt( uid ) );
		entry = tq_session.getTextQResult( user_id );
		if ( entry == null )
			{
			out.println( "Unable to find database entry." );
			return;
			}
		
		
		feedback=req.getParameter( "feedback" );
		comments=req.getParameter( "comments" );

		if ( feedback==null || comments==null )
			{
			out.println( "<HR>Invalid form input.<HR>" );
			return;
			}
		
		//general marks.
		amark=-1;
		if ( req.getParameter( "adjustedmark" )!=null && req.getParameter( "adjustedmark" ).length()>0 )
			{
			try
				{
				amark = Integer.parseInt( req.getParameter( "adjustedmark" ) );
				}
			catch ( NumberFormatException nfex )
				{
				out.println( "The value entered in the adjusted mark box was not recognized as a number." );
				return;
				}
			}
			
		
		entry = tq_session.recordAdjustedMark( entry.getTextQResultId(), amark, feedback, comments );
			
		out.println( "<P>Your entries were recorded.</P>" );
		
			
		}

	
	private void textqlist(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int i, j, status;
		Vector users;
		Hashtable entries;
		User user;
		TextQResult entry;
		
		
		users = tq_session.getTextQUsers();
		entries = tq_session.getTextQResults();
		
		out.println( "<TABLE BORDER><TR><TD>Entry</TD><TD>Mark</TD><TD>Mod</TD></TR>" );
		
		for ( i=0; i<users.size(); i++ )
			{
			user = (User)users.elementAt( i );
			entry = (TextQResult)entries.get( user.getUserId() );
			
			if ( user==null || entry==null )
				{
				out.println( "<TR><TD COLSPAN=3>Problem fetching entry details.</TD></TR>" );
				continue;
				}
				
			out.print(  "<TR><TD><A TARGET=docmain HREF=" + 
						entry.getUserId() +
						"/bs_template_textqmarkpaper.html>" );

			if ( user.getName() == null )
				out.print( "no name" );
			else
				out.print( user.getName() );

			out.println( "</A></TD>" );
			
			out.print( "<TD>" );
			if ( entry.getMark() != null )
				out.print( entry.getMark().toString() );
			else
				out.print( "~" );
			out.print( "</TD>" );
			
			out.print( "<TD>" );
			if ( entry.getAdjustedMark() != null )
				out.print( entry.getAdjustedMark().toString() );
			else
				out.print( "~" );
			out.print( "</TD></TR>" );
			}

		out.println( "</TABLE>" );
		}


	
	private void textqrecord(  Request req, PrintWriter out, TextQSession tq_session, String insertname )
		throws IOException, BuildingServerException
		{
		int i, j;
		String param;
		Vector questions_in_order;
		TextQuestion q;
		PrimaryKey[] list;
		String responses[];
		
		questions_in_order = tq_session.getTextQuestionsInOrder();
			
		responses = new String[questions_in_order.size()];
		list = new PrimaryKey[questions_in_order.size()];
		
		for ( i=0; i<questions_in_order.size(); i++ )
			{
			q=(TextQuestion)questions_in_order.elementAt( i );
			list[i] = q.getTextQuestionId();
		
			responses[i]=req.getParameter( "Q" + q.getTextQuestionId() );

			if ( responses[i] == null )
				responses[i]="";
			}
			
			
		TextQResult result =  tq_session.record( list, responses );

		if ( req.getUserId()==null )
			out.println( "<p>Your responses were recorded anonymously.</P>" );
		else
			{
			User user = (User)BuildingContext.getContext().getUser();
			out.println( "<p>Your responses were recorded under the name " + user.getName() + "</P>" );
			}
			
        Event event = new AssessmentEvent( 
        				AssessmentEvent.EVENT_SUBMISSION,
        				req.getResource().getResourceId(), 
        				req.getUserId(), 
						null,
        				new Integer( result.getTextQResultId().intValue() ), 
        				null  );
        event.save();
		}

	private void textqnewq( Request req, PrintWriter out, TextQSession tq_session, String insertname )
		throws IOException
		{
		try
			{
			tq_session.createQuestion();
			}
		catch ( Exception ex )
			{
			out.println( "<HR>A technical problem occured while trying to create a new question.<HR>" + ex.getMessage() );
			}
		}	

	private void textqitemedit(  Request req, PrintWriter out, TextQSession tq_session, String insertname )
		throws IOException, BuildingServerException
		{
		String id;
		Hashtable questions;
		TextQuestion question;
		
		if ( !BuildingContext.getContext().checkPermission( Permission.EDIT ) )
			{
			out.println( "<PRE>You don't have permission to edit questions in this location of the building.</PRE>\n" );
			return;
			}


		//must have an id in the parameter part of the URL
		if ( req.getTemplateParameterCount() < 1 )
			{
			out.println( "<I>Can't display edit field.</I>" );
			return;
			}
		id=(String)req.getTemplateParameter( 0 );

		questions=tq_session.getTextQuestions();
		if ( questions == null )
			{
			out.println( "<I>Can't display edit field.</I>" );
			return;
			}
			
		question = (TextQuestion)questions.get( new PrimaryKey( Integer.parseInt( id ) ) );
		
		if ( question==null )
			{
			out.println( "<I>Can't display edit field.</I>" );
			return;
			}

		if ( insertname.equalsIgnoreCase( "ordinal" ) )
			{
			out.println( "<INPUT NAME=ordinal VALUE=\"" +question.getOrdinal() + "\">" );
			return;
			}
		if ( insertname.equalsIgnoreCase( "available" ) )
			{
			out.println( "<INPUT NAME=available VALUE=\"" +question.getAvailable() + "\">" );
			return;
			}
		if ( insertname.equalsIgnoreCase( "weight" ) )
			{
			out.println( "<INPUT NAME=weight VALUE=\"" +question.getWeight().toString() + "\">" );
			return;
			}
		if ( insertname.equalsIgnoreCase( "question" ) )
			{
			out.print( "<SPAN CLASS=bs-textarea><TEXTAREA NAME=question COLS=45 ROWS=8>" );
			out.print( question.getQuestion() );
			out.println( "</TEXTAREA></SPAN>" );
			return;
			}
		if ( insertname.equalsIgnoreCase( "explanation" ) )
			{
			out.print( "<SPAN CLASS=bs-textarea><TEXTAREA NAME=explanation COLS=30 ROWS=4>" );
			out.print( question.getExplanation() );
			out.println( "</TEXTAREA></SPAN>" );
			return;
			}
		if ( insertname.equalsIgnoreCase( "notes" ) )
			{
			out.print( "<SPAN CLASS=bs-textarea><TEXTAREA NAME=notes COLS=45 ROWS=8>" );
			out.print( question.getNotes() );
			out.println( "</TEXTAREA></SPAN>" );
			return;
			}
		}

	
	private void textqeditqconfirm(  Request req, PrintWriter out, TextQSession tq_session, String insertname )
		throws IOException, BuildingServerException
		{
		int n;
		String id, param;
		PrimaryKey qid;
		Hashtable questions;
		TextQuestion q;
		
		if ( !BuildingContext.getContext().checkPermission( Permission.EDIT ) )
			{
			out.println( "<PRE>You don't have permission to edit questions in this location of the building.</PRE>\n" );
			return;
			}


		//must have an id in the parameter part of the URL
		if ( req.getTemplateParameterCount() < 1 )
			{
			out.println( "<I>Can't display edit field.</I>" );
			return;
			}
		id=(String)req.getTemplateParameter( 0 );
		qid= new PrimaryKey( Integer.parseInt( id ) );

		
		questions = tq_session.getTextQuestions();
		q=(TextQuestion)questions.get( qid );

		if ( q==null )
			{
			out.println( "<I>Can't display edit field.</I>" );
			return;
			}

		param=req.getParameter( "ordinal" );
		try
			{
			q.setOrdinal( Integer.parseInt( param ) );
			}
		catch ( NumberFormatException ex )
			{
			out.println( "<HR>Invalid number in ordinal field.<HR>" );
			return;
			}

		param=req.getParameter( "available" );
		try
			{
			int a = Integer.parseInt( param );
			if ( a<1 || a>100 )
				{
				out.println( "Available Mark must be between 1 and 100" );
				return;
				}
			q.setAvailable( a );
			}
		catch ( NumberFormatException ex )
			{
			out.println( "<HR>Invalid number in available marks field.<HR>" );
			return;
			}

		param=req.getParameter( "weight" );
		try
			{
			BigDecimal big = new BigDecimal( param );
			if ( big.scale()>3 )
				{
				out.println( "The weighting will be rounded because a maximum of 3 decimal places are allowed." );
				big = big.setScale( 3, BigDecimal.ROUND_HALF_UP );
				}
			if ( big.compareTo( max_weight )>0 )
				{
				out.println( "A weight greater than 100.0 is not allowed - the weight has been adjusted to 100.0." );
				big = max_weight;
				}
			q.setWeight( big );
			}
		catch ( NumberFormatException ex )
			{
			out.println( "<HR>Invalid number in weight field.<HR>" );
			return;
			}


		
		tq_session.changeQuestionText( q.getTextQuestionId(), 
										q.getExplanationBigStringId(), 
										req.getParameter( "explanation" ) );

		tq_session.changeQuestionText( q.getTextQuestionId(), 
										q.getQuestionBigStringId(), 
										req.getParameter( "question" ) );

		tq_session.changeQuestionText( q.getTextQuestionId(), 
										q.getNotesBigStringId(), 
										req.getParameter( "notes" ) );


		tq_session.changeQuestion( q.getTextQuestionId(), q );
		
		out.println( "<HR>Question Saved<HR>" );
		
/*
   			AssessmentEvent event = new AssessmentEvent( 
       							AssessmentEvent.EVENT_EDIT_ASSESSMENT_ITEM,
       							req.getResource().getResourceId(), 
       							user.getUserId(), 
  								null,
       							q.question_id, 
       							null    );
   			event.save();
  */
		}


	
	private void textqdeleteq(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int n;
		String id, param, notparam;
		PrimaryKey qid;

		if ( !BuildingContext.getContext().checkPermission( Permission.EDIT) )
			{
			out.println( "<PRE>You don't have permission to delete (edit) questions in this location of the building.</PRE>\n" );
			return;
			}

		//must have an id in the parameter part of the URL
		if ( req.getTemplateParameterCount() < 1 )
			{
			out.println( "<I>Can't delete question.</I>" );
			return;
			}
		id=(String)req.getTemplateParameter( 0 );
		qid= new PrimaryKey( Integer.parseInt( id ) );

		
		param=req.getParameter( "confirm" );
		if ( param==null ) param="";
		notparam=req.getParameter( "notconfirm" );
		if ( notparam==null ) notparam="";
		if ( param.length()<1 || notparam.length()>0 )
			{
			out.println( "<HR>Wrong checkboxes selected - question not deleted.<HR>" );
			return;
			}

		tq_session.removeQuestion( qid );

/*			
   			AssessmentEvent event = new AssessmentEvent( 
       							AssessmentEvent.EVENT_DELETE_ASSESSMENT_ITEM,
       							req.getResource().getResourceId(), 
       							user.getUserId(), 
  								null,
       							qid, 
       							null    );
   			event.save();
*/   			
		}

	
	private void textqrunbutton(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException
		{
		/*
		String can=canrun( req, mcq );
		
		if ( can!=null )
			out.println( can );
		else	
		*/
		out.println( "<INPUT NAME=run TYPE=BUTTON ONCLICK=\"launchtest()\" VALUE=\"Show Questions Now\">" );
		
		return;
		}


	private void textqfield( Request req, PrintWriter out, TextQSession tq_session, String name )
		throws ServletException, IOException, BuildingServerException
		{
		if ( !BuildingContext.getContext().checkPermission(Permission.MANAGE) )
			{
			out.println( "<PRE>You don't have permission to manage this pigeon hole.</PRE>\n" );
			return;
			}


		TextQPaper paper = tq_session.getTextQPaper();

		if ( name.equalsIgnoreCase( "general_notes" ) )
			{
			out.print( "<SPAN CLASS=bs-textarea><TEXTAREA NAME=general_notes>" );
			out.print( paper.getGeneralNotes() );
			out.println( "</TEXTAREA></SPAN>" );
			return;
			}
		if ( name.equalsIgnoreCase( "general_available" ) )
			{
			out.print( "<INPUT NAME=general_available VALUE=\"" );
			out.print( paper.getGeneralAvailable() );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "general_weight" ) )
			{
			out.print( "<INPUT NAME=general_weight VALUE=\"" );
			if ( paper.getGeneralWeight()!= null )
				out.print( paper.getGeneralWeight().toString() );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "maximum_mark" ) )
			{
			out.print( "<INPUT NAME=maximum_mark VALUE=\"" );
			out.print( paper.getMaximumMark() );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "date_open" ) )
			{
			out.print( "<INPUT NAME=date_open VALUE=\"" );
			if ( paper.getDateOpen()!=null )
				DateFormatter.outputDate( out, paper.getDateOpen(), 1 );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "date_deadline" ) )
			{
			out.print( "<INPUT NAME=date_deadline VALUE=\"" );
			if ( paper.getDateDeadline()!=null )
				DateFormatter.outputDate( out, paper.getDateDeadline(), 1 );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "date_penalty" ) )
			{
			out.print( "<INPUT NAME=date_penalty VALUE=\"" );
			if ( paper.getDatePenalty()!=null )
				DateFormatter.outputDate( out, paper.getDatePenalty(), 1 );
			out.println( "\">" );
			return;
			}

		
		return;
		}


	private void textqmodify( Request req, PrintWriter out, TextQSession tq_session )
		throws ServletException, IOException, BuildingServerException
		{
		String strdate, gen_notes;
		java.util.Date date;
		java.sql.Timestamp open, deadline, penalty;
		int max, gen_av;
		BigDecimal gen_wt;
		
		open=null;
		deadline=null;
		penalty=null;

		strdate=req.getParameter( "date_open" );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					{
					out.println( "<HR><P>The opening date couldn't be understood and has been cleared.<HR>" );
					open=null;
					}
				else
					open=new java.sql.Timestamp( date.getTime() );
				}
			}

		strdate=req.getParameter( "date_deadline" );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					{
					out.println( "<HR><P>The deadline date couldn't be understood and has been cleared.<HR>" );
					deadline=null;
					}
				else
					deadline=new java.sql.Timestamp( date.getTime() );
				}
			}

		strdate=req.getParameter( "date_penalty" );
		if ( strdate!=null )
			{
			strdate=strdate.trim();
			if ( strdate.length()>0 )
				{
				date=DateParser.parse( strdate );
				if ( date==null )
					{
					out.println( "<HR><P>The penalty date couldn't be understood and has been cleared.<HR>" );
					penalty=null;
					}
				else
					penalty=new java.sql.Timestamp( date.getTime() );
				}
			}


		gen_notes=req.getParameter( "general_notes" );

		
		strdate=req.getParameter( "general_available" );
		try
			{
			gen_av = Integer.parseInt( strdate );
			}
		catch ( NumberFormatException nfex )
			{
			out.println( "The entry in the extra marks availabhle field could not be understood as a valid number - changes have not been saved." );
			return;
			}

		strdate=req.getParameter( "general_weight" );
		try
			{
			gen_wt = new BigDecimal( strdate );
			}
		catch ( NumberFormatException nfex )
			{
			out.println( "The entry in the extra marks weight field could not be understood as a valid number - changes have not been saved." );
			return;
			}

		strdate=req.getParameter( "maximum_mark" );
		try
			{
			max = Integer.parseInt( strdate );
			}
		catch ( NumberFormatException nfex )
			{
			out.println( "The entry in the maximum mark field could not be understood as a valid number - changes have not been saved." );
			return;
			}

			
		tq_session.setDates( open, deadline, penalty );
		
		out.println( "<p>Dates saved.</P>" );
		
		if ( max<1 )
			{
			max = 1;
			out.println( "The maximum mark field has been adjusted up to 1." );
			}

		if ( max>100 )
			{
			max = 100;
			out.println( "The maximum mark field has been adjusted down to 100." );
			}
		tq_session.setMaximumMark( max );

		out.println( "<p>Maximum mark saved.</P>" );

		if ( gen_av < 0 )
			{
			gen_av = 0;
			out.println( "The extra marks available field has been adjusted up to 0." );
			}
		
		if ( gen_av > 100 )
			{
			gen_av = 100;
			out.println( "The extra marks available field has been adjusted down to 100." );
			}
		
		if ( gen_wt.doubleValue() < 0.0 )
			{
			gen_wt = new BigDecimal( 0.0 );
			out.println( "The extra marks weighting field has been adjusted up to 0.0." );
			}
		
		if ( gen_wt.doubleValue() > 100.0 )
			{
			gen_wt = new BigDecimal( 100.0 );
			out.println( "The extra marks weighting field has been adjusted down to 100.0." );
			}


		tq_session.setGeneralAssessment( gen_av, gen_wt, gen_notes );
		out.println( "<p>General Assessment options saved.</P>" );

		}

	private void entrystatuslist(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int i, j, status;
		Vector users;
		Hashtable entries;
		User user;
		TextQResult entry;
		
		
		users = tq_session.getTextQUsers();
		entries = tq_session.getTextQResults();
		
		out.println( "<TABLE BORDER>" );
                out.print(  "<TR VALIGN=TOP><TD>Set all entries" );
                out.println( "</TD><TD><SELECT NAME=\"status\">" );
                out.println("<OPTION VALUE=\"-1\">Set individually");
                for ( j=0; j<TextQResult.status_message.length; j++ )
		{
			out.print( "<OPTION VALUE=\"" + j + "\"" );
			out.print( " >CHANGE ALL TO: " );
			out.println( TextQResult.status_message[j] );
		}
                out.println("</SELECT>");
                out.println( "</TD></TR>" );
                out.println("</TABLE>");
                out.println("<TABLE BORDER=1>");
                out.println( "<TR><TD>Name</TD><TD>Status</TD><TD>Lock</TD>" +
			         "<TD>If set to date dependent would user be able to upload now?</TD></TR>" );
		for ( i=0; i<users.size(); i++ )
			{
			user = (User)users.elementAt( i );
			entry = (TextQResult)entries.get( user.getUserId() );
			
			if ( user==null || entry==null )
				{
				out.println( "<TR><TD COLSPAN=3>Problem fetching entry details.</TD></TR>" );
				continue;
				}
				
			out.print(  "<TR VALIGN=TOP><TD>" );
				
			if ( user.getName() == null )
				out.print( "no name" );
			else
				out.print( user.getName() );

			out.println( "</TD><TD><SELECT NAME=\"status" + entry.getTextQResultId() + "\">" );
			for ( j=0; j<TextQResult.status_message.length; j++ )
				{
				out.print( "<OPTION VALUE=\"" + j + "\"" );
				if ( j==entry.getStatus() )
					{
					out.print( " SELECTED>" );
					out.println( TextQResult.status_message[j] );
					}
				else
					{
					out.println( " >CHANGE TO: " );
					out.println( TextQResult.status_message[j] );
					}
				}

			status=entry.getStatus();
			entry.setStatus( TextQResult.STATUS_UPLOAD_BY_DATE );
			if ( tq_session.canSubmit( user.getUserId() ) )
				out.println( "</SELECT></TD><TD><INPUT NAME=\"lock" + entry.getTextQResultId() + "\" TYPE=CHECKBOX VALUE=\"TRUE\"></TD><TD>Yes</TD> " );
			else
				out.println( "</SELECT></TD><TD><INPUT NAME=\"lock" + entry.getTextQResultId() + "\" TYPE=CHECKBOX VALUE=\"TRUE\"></TD><TD>No, because " + 
								tq_session.denySubmitMessage( user.getUserId() ) +
								".</TD>" );
			entry.setStatus( status );

			out.println( "</TD></TR>" );
			}

		out.println( "</TABLE>" );
		}

	private void entrystatusconfirm(  Request req, PrintWriter out, TextQSession tq_session )
		throws IOException, BuildingServerException
		{
		int i, j, status;
                boolean changeall=false;
                boolean locked = false;
		String param;
                String lock;
		Vector users;
		Hashtable entries;
		User user;
		TextQResult entry;
		
		//check to see if change must be made to all entries
		
                param = req.getParameter("status");
                if (param != null)
                {
                    if (param.equalsIgnoreCase("-1")) 
                         changeall = false;
                    else changeall = true;
                }
                
		users = tq_session.getTextQUsers();
		entries = tq_session.getTextQResults();
		
		out.println( "<TABLE BORDER><TR><TD>Name</TD><TD>Status</TD></TR>" );
		for ( i=0; i<users.size(); i++ )
			{
			user = (User)users.elementAt( i );
			entry = (TextQResult)entries.get( user.getUserId() );
			
			if ( user==null || entry==null )
				{
				out.println( "<TR><TD COLSPAN=3>Problem fetching entry details.</TD></TR>" );
				continue;
				}
		
                        //check to see if this entry is locked
                        lock = req.getParameter("lock"+entry.getTextQResultId().toString());
                        if (lock == null) locked=false; else locked=true;
                        
                        
                        if ((changeall==false) || locked)
			param=req.getParameter( "status" + entry.getTextQResultId().toString() );
                        else
                            param=req.getParameter( "status");
                        
			if ( param==null ) continue;
			
			try
				{
				status=Integer.parseInt( param );
				}
			catch ( Exception numex )
				{
				continue;
				}
			if ( status == entry.getStatus() ||
					status < 0 ||
					status > TextQResult.STATUS_MAX )
				continue;
				
			// got this far so entry must need changing	
			
			tq_session.recordStatus( entry.getTextQResultId(), status );
			
			out.print(  "<TR VALIGN=TOP><TD>" );
				
			if ( user.getName() == null )
				out.print( "no name" );
			else
				out.print( user.getName() );

			out.println( "</TD><TD>" );
			out.println( TextQResult.status_message[status] );
			out.println( "</TD></TR>" );
			}

		out.println( "</TABLE>" );
		}


	}

