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

import org.apache.log4j.Logger;

import org.bodington.servlet.*;

import java.util.*;
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 List initResource( HttpServletRequest breq, Resource new_resource )
		{
		if ( !(new_resource instanceof TextQPaper) )
			throw new IllegalArgumentException( "Technical problem: An incorrect type of resource was created." );
		
		TextQPaper tq;
		tq = (TextQPaper)new_resource;
        List errors = new LinkedList();

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

		param=breq.getParameter( "general_notes" );
        try
        {
            tq.setGeneralNotes( param==null?"":param );
        }
        catch (BuildingServerException bse)
        {
            throw new RuntimeException("Failed to set general notes.", bse);
        }

        try {
            param=breq.getParameter( "general_available" );
            tq.setGeneralAvailable( Integer.parseInt( param ) );
        } catch (NumberFormatException nfe) {
            errors.add("Value entered for extra marks is not valid.");
        }

        try {
        	param=breq.getParameter( "general_weight" );
        	tq.setGeneralWeight( new BigDecimal( param ) );
        } catch (NumberFormatException nfe) {
        	errors.add("Value entered for weighting is not valid.");
        }

		try {
			param=breq.getParameter( "maxmark" );
			tq.setMaximumMark( Integer.parseInt( param ) );
		} catch (NumberFormatException e) {
			errors.add("Value entered for maximum marks is not valid.");
		}

		
		tq.setDateOpen( parseDate(breq, errors, "date_open", "Opening Date"));
        tq.setDateDeadline( parseDate(breq, errors, "date_deadline", "Deadline"));
        tq.setDatePenalty( parseDate(breq, errors, "date_penalty", "Penalty Date"));
		
        errors.addAll(super.initResource(breq, new_resource));
		return errors;  
		}
		
	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.
     *
     */
	private void copyAuthoredContent( Resource original_resource, Resource new_resource )
	        throws BuildingServerException
	        {
	         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 List postCreate(Request request, Resource resource) throws Exception
    {
	    List errors = super.postCreate(request, resource);
	    
	    Permission grant[] = {Permission.RECORD, Permission.MARK, Permission.REVIEW};
        if (ResourceUtils.grantPermissions(resource, grant))
        {
        	try {
        		resource.getAcl().save();
        		return errors;
        	} catch (BuildingServerException e) {
        		log.error("Failed to save resource ACL.");
        	}
        }
        errors = new ArrayList(errors);
        errors.add("Failed to add extra permissions.");
        return errors;
    }
	
	public List validate( Resource newResource )
		{
            TextQPaper paper = (TextQPaper) newResource;
			Date now = new java.util.Date();
			int n;
			BigDecimal decimal;
            List errors = new LinkedList();

			n = paper.getGeneralAvailable();

			if ( n<0 || n>100 )
			{
			    errors.add( "Available extra marks must be between 0 and 100." );
			}

			decimal = paper.getGeneralWeight();

			if ( decimal.doubleValue() < 0.0 || decimal.doubleValue() > 100.0  )
			{
			    errors.add( "Weighting for extra marks must be between 0.0 and 100.0." );
			}

			n = paper.getMaximumMark();
			if ( n<0 || n>100 )
			{
			    errors.add( "Maximum marks must be between 0 and 100." );
			}
            Date open = paper.getDateOpen();
            Date deadline = paper.getDateDeadline();
            Date penalty = paper.getDatePenalty();
            
//            Removed checks for null, seems that the time fields *are* optional, even though the template indicated otherwise.
            
			if ( open != null && deadline != null && open.after(deadline))
			{
				errors.add( "The opening date cannot be after the deadline date");
			}
            if ( deadline != null && penalty != null && deadline.after(penalty))
            {
                errors.add( "The deadline date cannot be after the penalty date." );
            }
			if ( deadline != null && deadline.before( now ))
			{
				errors.add( "The deadline date must be in the future." );
			}
			if ( penalty != null && penalty.before( now ))
			{
				errors.add( "The penalty date must be in the future." );
			}

		return errors;  
		}

	

	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(), DateFormatter.SHORT );
						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 occurred 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 short answer paper.</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 CLASS=\"datetime\" NAME=date_open VALUE=\"" );
			if ( paper.getDateOpen()!=null ) out.print( DateFormatter.formatDate( paper.getDateOpen(), DateFormatter.MEDIUM ) );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "date_deadline" ) )
			{
			out.print( "<INPUT CLASS=\"datetime\" NAME=date_deadline VALUE=\"" );
			if ( paper.getDateDeadline()!=null ) out.print( DateFormatter.formatDate( paper.getDateDeadline(), DateFormatter.MEDIUM ) );
			out.println( "\">" );
			return;
			}
		if ( name.equalsIgnoreCase( "date_penalty" ) )
			{
			out.print( "<INPUT CLASS=\"datetime\" NAME=date_penalty VALUE=\"" );
			if ( paper.getDatePenalty()!=null ) out.print( DateFormatter.formatDate( paper.getDatePenalty(), DateFormatter.MEDIUM ) );
			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 available 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>" );
		}


	}

