/* ======================================================================
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 java.util.logging.*;


import org.bodington.servlet.*;

import java.awt.Color;
import java.awt.color.*;
import java.rmi.RemoteException;
import java.lang.reflect.InvocationTargetException;
import java.math.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.text.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.URLEncoder;
import java.net.URL;
import java.net.HttpURLConnection;

//import java.security.*;
import java.security.cert.*;
import java.security.spec.*;
import java.math.BigInteger;
import javax.security.auth.x500.X500Principal;

import org.bodington.database.*;
import org.bodington.server.*;
import org.bodington.server.events.*;
import org.bodington.server.realm.*;
import org.bodington.server.realm.User;
import org.bodington.server.resources.*;
import org.bodington.servlet.*;
import org.bodington.servlet.template.GifTemplateProcessor;
import org.bodington.servlet.template.GifColourStatement;
import org.bodington.text.*;
import org.bodington.sqldatabase.SqlDatabase;
import org.bodington.servlet.template.Template;
import org.bodington.xml.XMLRepository;
import org.bodington.xml.XMLQuery;
import org.bodington.xml.XMLObjectRecord;
import org.bodington.util.ColourPreferenceMapper;
import org.bodington.util.DateFormatter;
import org.bodington.util.ResourceBundleHelper;


public class Facility extends java.lang.Object
	{
	


    static final int MAX_FILENAME_LENGTH = 48;
	static final int MAX_FILE_SIZE = 10;
	static final int MAX_ZIP_SIZE  = 10;


	private static String file_store=null;
	private static String published=null;
	static final int LISTSTYLE_NORMAL=0;
	static final int LISTSTYLE_DELETE=1;
	static final int LISTSTYLE_SID=2;
	static final int LISTSTYLE_UID=3;
	static final int LISTSTYLE_SURNAME=4;
	static final int LISTSTYLE_MODULE=5;

	Vector bigvector;


        X509CertificateBuilder x509_cert_builder=null;
	
	
    static boolean copy_in_progress=false;
    static Object copy_synch = new Object();
    
        
	//Hashtable templates;
	Integer id;
	public String facilityname;
	//Facility deffacility;

	public Facility()
		{
		int i;

		facilityname="building";
		//templates=new Hashtable();
		}


    public void logException( PrintWriter out, String sourceClassName, String sourceMethodName, String message, Throwable th )
	{
	BuildingServerException bsex=null;
	if ( th instanceof BuildingServerException )
	    bsex = (BuildingServerException)th;
	
	LogRecord lrec = new LogRecord( Level.SEVERE, th.getMessage() );
	
	lrec.setSourceClassName( sourceClassName );
	lrec.setSourceMethodName( sourceMethodName );
	lrec.setThrown( th );
	Logger.getLogger( "org.bodington" ).log( lrec );
	
	String strdate=null;
	try
	    {
            strdate = DateFormatter.formatDate( new java.util.Date( lrec.getMillis() ), 2 );
	    }
	catch ( IOException ioex ) {}

	if ( out!=null )
	    {
	    out.println( "<p align=\"center\">" );
	    if ( bsex!=null )
		out.println( bsex.friendlyMessage() );
	    else
		out.println( th.getMessage() );
	    out.println( "</p>" );
	    out.println( "<hr />" );
	    out.println( "<p>Please quote the following trace code, date and time if you contact support staff about this.</p>" );
	    out.print( "<p><strong>TC" );
	    out.print( lrec.getSequenceNumber() );
	    out.print( " " );
	    out.print( strdate );
	    out.println( "</strong></p>" );
	    }
	}	
		
		
    public String getTitle()
        {
        return null;
        }

    public String getTitle( boolean capital, boolean article )
        {
        return getTitle( capital, article, false );
        }
        
    public String getTitle( boolean capital, boolean article, boolean plural )
        {
        String t = getTitle();
        if ( t==null ) return null;
        
        StringBuffer buffer = new StringBuffer( t.length() + 4 );
        char first = Character.toLowerCase( t.charAt( 0 ) );
        
        if ( article )
            {
            buffer.append( capital?"A":"a" );
            if ( first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u' )
                buffer.append( "n" );
            buffer.append( " " );
            }
        
        
        if ( capital && !article )
            first = Character.toUpperCase( first );
            
        buffer.append( first );
        buffer.append( t.substring( 1 ) );
        
        if ( plural )
            buffer.append( "s" );
        
        return buffer.toString();
        }

	public Resource newResource()
		{
		return new Resource();
		}
		
	public boolean initResource( Request breq, Resource new_resource )
		throws Exception
		{
		return true;
		}


    /**
     * Facility subclasses can refuse copying of resources.
     * @return True if resources that use this facility can be copied.
     */
    public boolean canCopy( Resource resource )
    {
        // if here then resource is either served by Facility or by a subclass
        // that doesn't override this method.
        FacilityList facilityList = FacilityList.getFacilities();
        Facility facility = facilityList.get( new Integer( resource.getHttpFacilityNo() ) );
        // if resource is served by Facility itself then allow copy
        if ( facility instanceof Facility )            
            return true;
        // if resource is served by subclass of Facility but that subclass doesn't
        // overide this method then refuse copy operation.  Subclass must override
        // this method to allow copying.
        return false;
    }
    
    /**
     * Looks through resource children.....
     * @return True if resources that use this facility can be copied.
     */
    public boolean canCopyWithChildren( Resource resource )
    throws BuildingServerException
    {
    if ( !canCopy( resource ) )
        return false;

    if ( !resource.checkPermission( Permission.MANAGE ) )
        return false;
    
    FacilityList facilityList = FacilityList.getFacilities();
    Facility facility = null;
    Resource child;

    Enumeration enum = resource.findChildren();
    while ( enum.hasMoreElements() )
    {
        child = (Resource)enum.nextElement();
        facility = facilityList.get( new Integer( child.getHttpFacilityNo() ) );
        if ( !facility.canCopyWithChildren( child ) )
        return false;
    }

    return true;
    }    
    
    /**
     * Use the properties of an existing Resource to initialise a newly created Resource. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i>
     * @param original The resource with properties to copy.
     * @param new_resource The resource to initialise.
     * @return True if initialisation was OK.
     * @exception BuildingServerException Thrown if there is any problem initialising the resource.
     *
     */
	public boolean initResource( Resource original, Resource new_resource)
		throws BuildingServerException
	        {
	        //default init routine does nothing but
	        //other facilities can check/copy specific properties.
		return true;
		}


    /**
     * 
     * 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 The resource with content to copy.
     * @param new_resource The resource to copy content to.
     * @param breq The building HTTP request, which is used to determine which type of content to copy.
     * @exception BuildingServerException Thrown if there is any problem copying the resource content.
     *
     */
	public void copyContent( Resource original, Resource new_resource, Request breq  )
		throws BuildingServerException
		{
		//default routine does nothing but
		//other facilities can copy specific content.
		}

	public void userevent(  Request req, PrintWriter out )
		throws IOException
		{
		String user_message, notify;
		
        user_message=req.getParameter( "user_message" );
        if ( user_message!=null  )
        	user_message = user_message.trim();
        	
        if ( user_message==null || user_message.length()==0 )
        	{
        	out.println( "You have to enter a message to generate an event." );
        	return;
        	}

		if ( user_message.length()>250 )
			{
			user_message = user_message.substring( 0, 250 );
			out.println( "<P>Your message will be truncated because it is too long.</P>" );
			}

        notify=req.getParameter( "notify" );
		
		
		User user = (User)BuildingContext.getContext().getUser();
		UserEvent event = new UserEvent( UserEvent.EVENT_USER_EVENT,
										 req.getResource().getResourceId(),
										 user.getUserId(),
										 user_message,
										 (notify!=null && notify.length()>0) );
		try
			{
			event.save();
			}
		catch ( BuildingServerException bsex )
			{
			out.println( "<P>There was a technical problem generating the event.</P>" );
			out.println( bsex.toString() );
			return;
			}
			
		out.println( "<P>The event was generated.</P>" );
		}

	public void eventlog(  Request req, PrintWriter out )
		throws IOException
		{
		int j;
		Event event;
		PrimaryKey event_id;
		StringBuffer where;

		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
			{
			out.println( "<HR>You need manage access to view the log.<HR>" );
			return;
			}
		out.println( "<! ------------------------------------------------- >" );
		out.println( "<! ------------------------------------------------- >" );
		out.println( "<! ------------------------------------------------- >" );
		out.println( "<! ------------------------------------------------- >" );
		out.flush();
		
		try
			{
			where = new StringBuffer();
			where.append( "resource_id = " );
			where.append( req.getResource().getResourceId().toString() );
			where.append( " AND importance >= " );
			where.append( Event.IMPORTANCE_MANAGEMENT_MIN );
			
			Enumeration enum = Event.findEventPrimaryKeys( where.toString(), "event_time" );
			
			for ( j=0; enum.hasMoreElements();  )
				{
				event_id = (PrimaryKey)enum.nextElement();
				event=Event.findEvent( event_id );
				if ( event== null )
					continue;
				
				if ( j%10 == 0 )
					{
					if ( j>=0 )
						{
						out.println( "</TABLE>" );
						}
					out.println( "<TABLE CLASS=bs-table-opaque>" );
					}

				out.println( "<TR><TD><I>" );
				DateFormatter.outputDate( out, event.getEventTime(), 0 );
				out.println( "</I></TD><TD>" );
				event.printMessage( out, true );
				out.flush();
				out.println( "</TD></TR>" );
				j++;
				}
			if ( j>0 )
				out.println( "</TABLE>" );
			else
				out.println( "<P>There are no events in the event log here.</P>" );
			}
		catch ( Exception ex )
			{
			out.println( "</TD></TR></TABLE><HR>There was a technical problem trying to get a list of events.<HR>" );
			out.println( ex.toString() );
			return;
			}
		
		}

	public Object create( Object creation )
		{
		//as yet the plain vanilla facility doesn't cache any data
		//sub classes will have to over ride this do do fancy stuff
		return new Object();
		}
		
	public boolean clearCacheEntry( Object d, boolean force )
		{
		//no cached data so no clean up to do
		//sub classes will have to over ride this do do fancy stuff
		return true;
		}

	public void init( Integer i, Facility def )
		{
		id=i;
		//deffacility=def;
		}

	public void beginPage( Request req )
		throws ServletException
		{
		//this facility does nowt here
		return;
		}

	public void endPage( Request req )
		throws ServletException
		{
		//this facility does nowt here
		return;
		}

	public boolean generateFile( Request req, HttpServletResponse res )
		throws ServletException, IOException
		{
		// generate a file, or select a previously generated file
		
		try
			{
			Logger.getLogger( "org.bodington" ).fine( "Generated file requested: " + req.getPageName() );
			if ( req.getPageName().equals( "filelisting.xml" ) )
				{
				return generateFileListing( req, res );
				}
			else if ( req.getPageName().equals( "menu.xml" ) )
				{
				return generateResourceMenu( req, res );
				}
			else if ( req.getPageName().equals( "metadata.xml" ) )
				{
				Logger.getLogger( "org.bodington" ).fine( "Generated file metadata.xml requested." );
				File d = req.getResource().getGeneratedFileFolder();
				File man = new File( d, "metadata.xml" );
				
				if ( !man.exists() )
					{
					PrintWriter writer = new PrintWriter( new FileWriter( man ) );
					writer.println( "Just testing!" );
					writer.close();
					}
				
				res.setContentType( "text/plain" );
				
				return true;
				}
			}
		catch ( BuildingServerException bsex )
			{
			Logger.getLogger( "org.bodington" ).logp( 
			    Level.SEVERE, 
			    "Facility", 
			    "generateFile", 
			    bsex.getMessage(), 
			    bsex );
			throw new ServletException( bsex.getMessage() );
			}

			
		return false;
		}

		
	public boolean generateFileListing( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		BuildingSession session;

		Logger.getLogger( "org.bodington" ).fine( "Generated file filelisting.xml requested." );

		session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		session.generateFileListing();

		Logger.getLogger( "org.bodington" ).fine( "Generated file filelisting.xml generated." );

		res.setContentType( "text/plain" );
		return true;
		}
		
	public boolean generateResourceMenu( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		BuildingSession session;

		Logger.getLogger( "org.bodington" ).fine( "Generated file menu.xml requested." );

		session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		session.generateResourceMenu();

		Logger.getLogger( "org.bodington" ).fine( "Generated file menu.xml generated." );

		res.setContentType( "text/plain" );
		return true;
		}
		
		
		
	public void sendVirtualFile( Request req, HttpServletResponse res )
		throws ServletException, IOException
		{
		try
		    {
		    if ( req.getPageName().equals( "author.css" ) )
			{
			sendAuthorStyleSheet( req, res );
			}
		    // user style sheets may have varying names to force the browser to reload when
		    // options are changed.
		    else if ( req.getPageName().startsWith( "user" ) && req.getPageName().endsWith( ".css" ) )
			{
			sendUserStyleSheet( req, res );
			}
		    else if ( req.getPageName().startsWith( "auto" ) && req.getPageName().endsWith( ".css" ) )
			{
			sendAutoStyleSheet( req, res );
			}
		    else if ( req.getPageName().equals( "uploadconfirm.txt" ) )
			{
			sendUploadConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "menuconfirm.txt" ) )
			{
			sendMenuConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "createfolderconfirm.txt" ) )
			{
			sendCreateFolderConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "renameconfirm.txt" ) )
			{
			sendRenameConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "deleteconfirm.txt" ) )
			{
			sendDeleteConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "undeleteconfirm.txt" ) )
			{
			sendUndeleteConfirmation( req, res );
			}
		    else if ( req.getPageName().equals( "userclientcert.cer" ) )
			{
			sendUserClientCert( req, res );
			}
		    else
			{
			res.setContentType( "text/plain" );
			PrintWriter writer = new PrintWriter( res.getWriter() );

			writer.println( "ERROR" );
			writer.print( "Unknown virtual file requested: " );
			writer.println( req.getPageName() );
			writer.close();
			}
			}
		catch ( RemoteException rex )
			{
			Logger.getLogger( "org.bodington" ).logp( 
			    Level.SEVERE, 
			    "Facility", 
			    "sendVirtualFile", 
			    rex.getMessage(), 
			    rex );
			    throw new ServletException( rex.getMessage() );
                        }   
		catch ( BuildingServerException bsex )
			{
			Logger.getLogger( "org.bodington" ).logp( 
			    Level.SEVERE, 
			    "Facility", 
			    "sendVirtualFile", 
			    bsex.getMessage(), 
			    bsex );
			try
			    {
			    res.setContentType( "text/plain" );
			    PrintWriter writer = new PrintWriter( res.getWriter() );

			    writer.println( "ERROR" );
			    writer.println( bsex.friendlyMessage() );
			    writer.close();
			    }
			catch ( Throwable th )
			    {
			    throw new ServletException( th.getMessage() );
			    }
			}
		}

        
    public void writeClientX509( Request request, PrintWriter writer )
    throws IOException
    {
        Object obj = request.getAttribute( "javax.servlet.request.X509Certificate" );
        if ( obj == null )
        {
            writer.println( "No client X509 certificate in page request." );
            return;
        }
        if ( !(obj instanceof java.security.cert.X509Certificate[]) )
        {
            writer.println( "Request attribute had wrong data type." );
            return;
        }
        
        java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[])obj;
        for ( int i=0; i<certs.length; i++ )
        {
            writer.println( "Certificate chain item " + i );
            writer.println( certs[i].toString() );
        }
    }
        
    public void sendUserClientCert( Request req, HttpServletResponse res )
    throws IOException, BuildingServerException
    {
        NavigationSession nav_session = req.getServerNavigationSession();
        if ( !nav_session.isAuthenticated() )
        {
            res.sendError( 500, "User is not authenticated" );
            return;
        }
        if ( nav_session.isAnonymous() )
        {
            res.sendError( 500, "Can't issue certificate to anonymous user." );
            return;
        }

        User user = nav_session.getAuthenticatedUser();
        
        String pubkey = req.getParameter( "public_key" );
        if ( pubkey==null || pubkey.length() <= 0 )
        {
            res.sendError( 500, "No public key was supplied by the web browser." );
            return;
        }
        
        if ( x509_cert_builder == null )
        {
            String kstr = req.getServletConfig().getServletContext().getRealPath( "WEB-INF/ca.keystore" );
            x509_cert_builder = new X509CertificateBuilder( kstr );
            x509_cert_builder.init();
        }
        
        X509Certificate client_cert;
        byte[] encoded_cert=null;

        try
        {
            UserX509 user_x509 = new UserX509();
            user_x509.setUserId( user.getUserId() );
            // save to generate primary key
            user_x509.save();
            
            client_cert = x509_cert_builder.createClientCertificate( 
                user.getName(),
                1000*60*60, 
                user_x509.getUserX509Id().intValue(),
                pubkey );

            user_x509.setX509Certificate( client_cert );
            user_x509.setSerialNumber( user_x509.getUserX509Id().intValue() );
            user_x509.setDistinguishedName( client_cert.getSubjectDN().getName() );
            user_x509.save();
            
            encoded_cert = client_cert.getEncoded();
        }
        catch ( Exception e )
        {
            Logger.getLogger( "org.bodington" ).severe( "Unable to set stylesheet preference." );
            Logger.getLogger( "org.bodington" ).logp( 
                Level.SEVERE, 
                "Facility", 
                "processStylesheetPreferences", 
                e.getMessage(), 
                e );
            //throw new ServletException( e );
            res.sendError( 500, "Problem creating certificate." );
            return;
        }

        if ( encoded_cert == null || encoded_cert.length==0 )
        {
            res.sendError( 500, "Generated certificate was empty." );
            return;
        }
        
        res.setContentType( "application/x-x509-user-cert" );
        ServletOutputStream out = res.getOutputStream();


        System.err.println( "cert length: " + encoded_cert.length );

        out.write( encoded_cert );
        out.close();
    }

        
        private void stylesheetEntry( StringBuffer buffer, String entry )
        {
            buffer.append( entry );
            buffer.append( "\r\n    {\r\n" );
        }
        private void stylesheetEndEntry( StringBuffer buffer )
        {
            buffer.append( "    }\r\n\r\n" );
        }
        private void stylesheetProperty( StringBuffer buffer, String name, String value )
        {
            buffer.append( name );
            buffer.append( ": " );
            buffer.append( value );
            buffer.append( ";\r\n" );
        }
        private void stylesheetProperty( StringBuffer buffer, String name, Color value )
        {
            buffer.append( name );
            buffer.append( ": " );
            buffer.append( "#" );
            buffer.append( Integer.toHexString( value.getRGB() ).substring( 2 ) );
            buffer.append( ";\r\n" );
        }

        
       /**
        * Get the style sheet session data. <p> 
        * <i>(WebLearn modification. Method made protected for use in EasyBuilderFacility. 26/07/2004 Colin Tatham)</i> 
        */
        protected StyleSheetSessionData getStyleSheetSessionData( org.bodington.servlet.HttpSession http_session )
        {
            StyleSheetSessionData sss_data = (StyleSheetSessionData)
                http_session.getAttribute( "org.bodington.user_style_sheet_session_data" );
            if ( sss_data == null )
            {
                sss_data = new StyleSheetSessionData();
                http_session.setAttribute( "org.bodington.user_style_sheet_session_data", sss_data );
            }
            return sss_data;
        }
        
     /**
      * The class StyleSheetSessionData. <p> 
      * <i>(WebLearn modification. Class made protected for use in EasyBuilderFacility. 26/07/2004 Colin Tatham)</i> 
      */
        protected class StyleSheetSessionData
	{
	    int number_of_changes = random.nextInt() & 0x7fffffff;
	    
	    long last_changed_options=0L;
	    
	    boolean enable_style_sheets = true;

	    boolean was_unauth_style = true;
            boolean unsaved_changes = false;
	    
	    Properties preferences = new Properties();
            
            String getPreference( org.bodington.servlet.HttpSession http_session, String key )
            throws BuildingServerException, RemoteException
            {
                // try current value (in http_session)
                String value=null;
                value = preferences.getProperty( key );
                if ( value != null )
                    return value;
                
                // go to database through nav_session
                NavigationSession nav_session = http_session.getServerNavigationSession();
                // must be authenticated and a real person to use stored values
                if ( nav_session == null || !nav_session.isAuthenticated() || nav_session.isAnonymous() )
                    return null;
                value = nav_session.getUserProperty( key );
                if ( value == null )
                    return null;
                
                // if found there store in session data for later use
                preferences.setProperty( key, value );
                return value;
            }

            void setPreference( org.bodington.servlet.HttpSession http_session, String key, String value )
            throws BuildingServerException, RemoteException
            {
                // if found there store in session data for later use
                preferences.setProperty( key, value );
                
                // if real person store in database too
                NavigationSession nav_session = http_session.getServerNavigationSession();
                // must be authenticated and a real person to use stored values
                if ( nav_session == null || !nav_session.isAuthenticated() || nav_session.isAnonymous() )
                {
                    unsaved_changes = true;
                    return;
                }
                nav_session.setUserProperty( key, value );
            }
            
            ColourPreferenceMapper getUserColourPreferenceMapper( org.bodington.servlet.HttpSession http_session )
            throws BuildingServerException, RemoteException
            {
                String colour_option = getPreference( http_session, "preference.stylesheet.colour_option" );
                if ( colour_option == null )
                    colour_option = "normal";
                ColourPreferenceMapper colour_mapper=new ColourPreferenceMapper();
                
                if ( colour_option.equals( "black" ) )
                    colour_mapper.setType( ColourPreferenceMapper.TYPE_BLACK_ON_WHITE );
                else if ( colour_option.equals( "white" ) )
                    colour_mapper.setType( ColourPreferenceMapper.TYPE_WHITE_ON_BLACK );
                else if ( colour_option.equals( "contrast" ) )
                    colour_mapper.setType( ColourPreferenceMapper.TYPE_CONTRAST );
                else if ( colour_option.equals( "soft" ) )
                    colour_mapper.setType( ColourPreferenceMapper.TYPE_SOFT );
                else
                    colour_mapper.setType( ColourPreferenceMapper.TYPE_NORMAL );

                return colour_mapper;
            }
        }
	
	private class StyleSheetEntry
        {
            StringBuffer content=null;
            long last_modified=0L;
	    //int version = 0;
        }
        
        Hashtable author_style_sheets = new Hashtable();
        
        static final int FOREGROUND         =0;
        static final int FOREGROUND_EM      =1;
        static final int FOREGROUND_VSTRONG =2;
        static final int FOREGROUND_LINK    =3;
        static final int FOREGROUND_VISITED =4;
        static final int FOREGROUND_ACTIVE  =5;
        static final int FOREGROUND_HOVER   =6;

        static final int BACKGROUND             =0;
        static final int BACKGROUND_TABLE       =1;
        static final int BACKGROUND_TABLE_EM    =2;
        static final int BACKGROUND_MENU_HEAD   =3;
        static final int BACKGROUND_MENU_1      =4;
        static final int BACKGROUND_MENU_2      =5;

        
        // CSS elements that have background colours indexed with above constants excepting trees
        String[][] css_back_elements = 
        {
            {"body",".bs-plain"},
            {".bs-table-opaque", ".bs-logbook-command"},
            {".bs-cell-special", ".bs-table-acl" },
            {".res_tree_header", ".res_tree_big_header"}
        };
        // CSS elements that have foreground colours
        String[][] css_fore_elements = 
        {
            {"",".bs-messaging-date"},
            {"em", "strong", ".bs-links-heading", ".bs-messaging-week", ".bs-logbook-menu-command", ".bs-logbook-menu-command A", ".bs-logbook-menu-section A", ".bs-logbook-menu-section A:visited", ".bs-logbook-entry-author", ".bs-logbook-entry-date"},
            {".bs-messaging-day"},
            {"a:link"},
            {"a:visited"},
            {"a:active"},
            {"a:hover"}
        };
                               
        
        static final Color[][] def_fore_col =
        {
            {
                new Color( 0x333366 ), 
                new Color( 0xaa6600 ), 
                new Color( 0xaa6600 ), 
                new Color( 0x403399 ), 
                new Color( 0x333380 ), 
                new Color( 0x333399 ), 
                new Color( 0x8040ff )
            },
            {
                new Color( 0xffffff ), 
                new Color( 0xffa401 ), 
                new Color( 0xff0000 ), 
                new Color( 0xaaaaff ), 
                new Color( 0xccccdd ), 
                new Color( 0x333399 ), 
                new Color( 0x8040ff ) 
            }
        };

        static final Color[][] def_back_col =
        {
            {
                new Color( 0xccccc0 ), 
                new Color( 0x9090b0 ), 
                new Color( 0x8080b0 ), 
                null, 
                null, 
                null
            },
            {
                new Color( 0x007c88 ), 
                new Color( 0x9090b0 ), 
                new Color( 0x8080b0 ), 
                null, 
                null, 
                null
            }
        };
        
        private Color[] getForegroundColors( BuildingSession s, String style )
            throws BuildingServerException, RemoteException
        {
            int def = "style_navigation".equalsIgnoreCase( style )?1:0;
            Color[] c = new Color[7];
            c[FOREGROUND]          = s.getPropertyColor( style + "_foreground_colour",     def_fore_col[def][0] );
            c[FOREGROUND_EM]       = s.getPropertyColor( style + "_emphasis_colour",       def_fore_col[def][1] );
            c[FOREGROUND_VSTRONG]  = s.getPropertyColor( style + "_extra_emphasis_colour", def_fore_col[def][2] );
            c[FOREGROUND_LINK]     = s.getPropertyColor( style + "_link_colour",           def_fore_col[def][3] );
            c[FOREGROUND_VISITED]  = s.getPropertyColor( style + "_link_visited_colour",   def_fore_col[def][4] );
            c[FOREGROUND_ACTIVE]   = s.getPropertyColor( style + "_link_active_colour",    def_fore_col[def][5] );
            c[FOREGROUND_HOVER]    = s.getPropertyColor( style + "_link_hover_colour",     def_fore_col[def][6] );
            return c;
        }

        private  Color[] getBackgroundColors( BuildingSession s, String style )
            throws BuildingServerException, RemoteException
        {
            int def = "style_navigation".equalsIgnoreCase( style )?1:0;
            Color[] c = new Color[6];
            c[BACKGROUND]          = s.getPropertyColor( style + "_background_colour",       def_back_col[def][0] );
            c[BACKGROUND_TABLE]    = s.getPropertyColor( style + "_table_colour",            def_back_col[def][1] );
            c[BACKGROUND_TABLE_EM] = s.getPropertyColor( style + "_table_emphasis_colour",   def_back_col[def][2] );
            c[BACKGROUND_MENU_HEAD]= s.getPropertyColor( style + "_menu_header_colour",      def_back_col[def][3] );
            c[BACKGROUND_MENU_1]   = s.getPropertyColor( style + "_menu_highlight_colour_1", def_back_col[def][4] );
            c[BACKGROUND_MENU_2]   = s.getPropertyColor( style + "_menu_highlight_colour_2", def_back_col[def][5] );
            return c;
        }
        
        private StyleSheetEntry compileAuthorStyleSheet( Request req, BuildingSession session, PrimaryKey resource_id )
        throws RemoteException, BuildingServerException
        {
            int i, j, k, l;
            
       	    Logger.getLogger("org.bodington").fine( "Compiling Style Sheet" );

            synchronized ( author_style_sheets )
            {
		String property;
		
		String nav_background_image = null;
                property = session.getProperty( "style_navigation_background_image" );
		if ( "none".equals( property ) )
		    nav_background_image = "none";
		else if ( property != null )
		{
                    nav_background_image = "url('" + req.getContextPath();
		    if ( !property.startsWith( "/" ) )
			nav_background_image += "/";
		    nav_background_image += property + "')";
		}
                
                // starting to reform and simplify colour processing
                Color[] nav_foreground_colours  = getForegroundColors( session, "style_navigation" );
                Color[] foreground_colours      = getForegroundColors( session, "style" );
                Color[] nav_background_colours  = getBackgroundColors( session, "style_navigation" );
                Color[] background_colours      = getBackgroundColors( session, "style" );
                Color res_menu_border_colour = session.getPropertyColor( "style_navigation_menu_border_colour", null );
                boolean tree_lines = "yes".equalsIgnoreCase( session.getProperty( "ui_navigation_menu_lines", "yes" ) );
		
                // These lines of code are about determining the colour of lines in the background 
                // of tree diagrams.  The code determined will be used to transform the colour of
                // the GIF files via a query string to the servlet that processed them.
                // Line will be black or white depending on background colour of page
                Color tree_line_colour = null;
                // if background is lighter than mid grey use black lines
                // otherwise use white lines.
                float[] hsb = Color.RGBtoHSB( nav_background_colours[BACKGROUND].getRed(), nav_background_colours[BACKGROUND].getGreen(), nav_background_colours[BACKGROUND].getBlue(), null );
                if ( hsb[2] < 0.5 )
                    tree_line_colour = new Color( 0xffffff );
                else
                    tree_line_colour = new Color( 0x000000 );
                // not concerned with user preference here.
                ColourPreferenceMapper tree_line_colour_mapper = null;
                String tree_line_path = null;
                if ( tree_lines )
                {
                    tree_line_colour_mapper = new ColourPreferenceMapper();
                    tree_line_colour_mapper.setReferenceColours( nav_background_colours[BACKGROUND], tree_line_colour );
                    // next we need to set up a path to a transformed sample tree line 
                    // GIF file.  It is assumed that all GIFs will be in the same place.
                    tree_line_path = "bs_template_";  // defaults to be relative to stylesheet and with prefix
                    Resource resource = req.getResource();
                    String sample_tree_line = "tree_node_lines_snundnbc_22_22.gif";
                    Template template = Template.get( this.facilityname, resource.getImplicitHttpUIStyle(), resource.getResourceId(), sample_tree_line );
                    if ( template != null )
                    {
                        tree_line_path = req.getContextPath() + "/processedgif/templates" + template.getUrl();
                        tree_line_path = tree_line_path.substring( 0, tree_line_path.length() - sample_tree_line.length() );
                    }
                }

		String background_image = null;
                property = session.getProperty( "style_background_image" );
		if ( "none".equals( property ) )
		    background_image = "none";
		else if ( property != null )
		{
                    background_image = "url('" + req.getContextPath();
		    if ( !property.startsWith( "/" ) )
			background_image += "/";
		    background_image += property + "')";
		}
                
                StyleSheetEntry entry = new StyleSheetEntry();
                entry.content = new StringBuffer();

                entry.content.append( "/* Bodington Virtual Style Sheet - Author's */\r\n\r\n" );

                stylesheetEntry( entry.content, "body, .bs-plain" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND] );
                if ( background_image != null )
                {
                    stylesheetProperty( entry.content, "background-image", background_image );
                    stylesheetProperty( entry.content, "background-repeat", "repeat" );
                }

                stylesheetProperty( entry.content, "background-color", background_colours[BACKGROUND] );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page, .bodington_navigation_page .bs-plain" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND] );
                if ( nav_background_image != null )
                {
                    stylesheetProperty( entry.content, "background-image", nav_background_image );
                    stylesheetProperty( entry.content, "background-repeat", "repeat" );
                }

                stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND] );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-textarea" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, "textarea" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, "input" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, "select" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font-family", "Arial Unicode MS, sans-serif" );
                stylesheetEndEntry( entry.content );
                
		// It's likely that some block elements have defined absolute sizes in the browser's
                // default style which mean that they are not tied to the font size in the body
                // tag.  So the set of likely elements are defined here with relative sizes.
                stylesheetEntry( entry.content, "table" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h1" );
                stylesheetProperty( entry.content, "font-size", "190%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h2" );
                stylesheetProperty( entry.content, "font-size", "150%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h3" );
                stylesheetProperty( entry.content, "font-size", "120%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h4" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h5" );
                stylesheetProperty( entry.content, "font-size", "85%" );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, "h6" );
                stylesheetProperty( entry.content, "font-size", "75%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:link" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_LINK] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:visited" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_VISITED] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:active" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_ACTIVE] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:hover" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_HOVER] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:link" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_LINK] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:visited" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_VISITED] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:active" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_ACTIVE] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:hover" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_HOVER] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page em" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "em" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page strong" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "strong" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-title" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-table-acl" );
                stylesheetProperty( entry.content, "background-color", background_colours[BACKGROUND_TABLE_EM] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page .bs-table-acl" );
                stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND_TABLE_EM] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-table-opaque" );
                stylesheetProperty( entry.content, "background-color", background_colours[BACKGROUND_TABLE] );
                stylesheetProperty( entry.content, "border-left", "thin ridge" );
                stylesheetProperty( entry.content, "border-top", "thin ridge" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page .bs-table-opaque" );
                stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND_TABLE] );
                stylesheetProperty( entry.content, "border-left", "thin ridge" );
                stylesheetProperty( entry.content, "border-top", "thin ridge" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-cell-special" );
                stylesheetProperty( entry.content, "background-color", background_colours[BACKGROUND_TABLE_EM] );
                stylesheetProperty( entry.content, "border-right", "thin ridge" );
                stylesheetProperty( entry.content, "border-bottom", "thin ridge" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page .bs-cell-special" );
                stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND_TABLE_EM] );
                stylesheetProperty( entry.content, "border-right", "thin ridge" );
                stylesheetProperty( entry.content, "border-bottom", "thin ridge" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-introduction" );
                stylesheetProperty( entry.content, "margin-bottom", "+1ex" );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-links-title" );
                stylesheetProperty( entry.content, "font-size", "95%" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-links-heading" );
                stylesheetProperty( entry.content, "color", nav_foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-size", "95%" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetProperty( entry.content, "margin-top", "+25px" );
                stylesheetProperty( entry.content, "margin-bottom", "0px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-links-icon" );
                stylesheetProperty( entry.content, "margin-right", "10px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-links-description" );
                stylesheetProperty( entry.content, "font-size", "90%" );
                stylesheetProperty( entry.content, "margin-bottom", "1ex" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-links-heading-description" );
                stylesheetProperty( entry.content, "margin-left", "+30px" );
                stylesheetProperty( entry.content, "margin-top", "0px" );
                stylesheetProperty( entry.content, "margin-bottom", "+15px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, ".bs-messaging-detail" );
                stylesheetProperty( entry.content, "padding-top", "0px" );
                stylesheetProperty( entry.content, "padding-bottom", "32px" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, ".bs-messaging-introduction" );
                stylesheetProperty( entry.content, "padding-bottom", "+2ex" );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-messaging-date" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "normal" );
                stylesheetProperty( entry.content, "font-size", "80%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title .bs-messaging-date" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "normal" );
                stylesheetProperty( entry.content, "font-size", "50%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-day" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_VSTRONG] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title .bs-messaging-day" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_VSTRONG] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetProperty( entry.content, "font-size", "80%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-week" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "normal" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title .bs-messaging-week" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetProperty( entry.content, "font-weight", "normal" );
                stylesheetProperty( entry.content, "font-size", "80%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-author" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title .bs-messaging-author" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-size", "80%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-number" );
                stylesheetProperty( entry.content, "font-size", "50%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-commands" );
                stylesheetProperty( entry.content, "padding-top", "4px" );
                stylesheetProperty( entry.content, "padding-bottom", "4px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-command" );
                stylesheetProperty( entry.content, "border", "thin white" ); 
                stylesheetProperty( entry.content, "padding-left", "0px" );
                stylesheetProperty( entry.content, "padding-right", "32px" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, ".bs-messaging-sample" );
                stylesheetProperty( entry.content, "padding-top", "4px" );
                stylesheetProperty( entry.content, "padding-bottom", "4px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-sample-text" );
                stylesheetProperty( entry.content, "font-style", "italic" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-mcq-marks" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-commands" );
                stylesheetProperty( entry.content, "text-align", "center" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-command" );
                stylesheetProperty( entry.content, "background-color", background_colours[BACKGROUND_TABLE] ); 
                stylesheetProperty( entry.content, "margin-left", "10px" );
                stylesheetProperty( entry.content, "margin-right", "10px" );
                stylesheetProperty( entry.content, "padding", "4px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-command-disabled" );
                stylesheetProperty( entry.content, "color", "#202020" );
		stylesheetProperty( entry.content, "background-color", "#a8a8a8" );
                stylesheetProperty( entry.content, "margin-left", "10px" );
		stylesheetProperty( entry.content, "margin-right", "10px" );
                stylesheetProperty( entry.content, "padding", "4px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu" );
                stylesheetProperty( entry.content, "border", "thin dashed white" ); 
                stylesheetProperty( entry.content, "margin", "16px" );
                stylesheetProperty( entry.content, "padding-top", "4px" );
		stylesheetProperty( entry.content, "padding-bottom", "15px" );
                stylesheetProperty( entry.content, "padding-left", "4px" );
		stylesheetProperty( entry.content, "padding-right", "4px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-command" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
		stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-logbook-menu-command A" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
		stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-section" );
                stylesheetProperty( entry.content, "font-size", "120%" );
		stylesheetProperty( entry.content, "margin-top", "5px" );
		stylesheetProperty( entry.content, "margin-left", "5px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-section A" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-logbook-menu-section A:visited" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-question" );
                stylesheetProperty( entry.content, "margin-left", "15px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-new-q" );
                stylesheetProperty( entry.content, "font-style", "italic" );
		stylesheetProperty( entry.content, "margin-left", "30px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-menu-new-s" );
                stylesheetProperty( entry.content, "font-style", "italic" );
		stylesheetProperty( entry.content, "font-size", "120%" );
		stylesheetProperty( entry.content, "margin-top", "5px" );
		stylesheetProperty( entry.content, "margin-left", "5px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated" );
		stylesheetProperty( entry.content, "padding", "8px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-name" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
		stylesheetProperty( entry.content, "font-size", "250%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-section-title" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
		stylesheetProperty( entry.content, "font-size", "200%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-section-intro" );
                stylesheetProperty( entry.content, "font-style", "italic" );
		stylesheetProperty( entry.content, "font-size", "90%" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-question-title" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
		stylesheetProperty( entry.content, "font-size", "150%" );
		stylesheetProperty( entry.content, "margin-left", "16px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-question-text" );
                stylesheetProperty( entry.content, "font-style", "italic" );
		stylesheetProperty( entry.content, "font-size", "90%" );
		stylesheetProperty( entry.content, "margin-left", "16px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-entry" );
                stylesheetProperty( entry.content, "border", "thin black dotted" );
		stylesheetProperty( entry.content, "margin", "32px" );
		stylesheetProperty( entry.content, "padding", "8px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-entry-author" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-collated-entry-date" );
                stylesheetProperty( entry.content, "font-style", "italic" );
                stylesheetEndEntry( entry.content );

                //stylesheetEntry( entry.content, ".bs-logbook-collated-entry-text P
                //stylesheetProperty( entry.content, "color: #202040}
                //stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry" );
                //stylesheetProperty( entry.content, "background-color", #9090b0; 
		stylesheetProperty( entry.content, "border", "thin white dashed" );
		stylesheetProperty( entry.content, "margin", "32px" );
		stylesheetProperty( entry.content, "padding", "8px" );
                stylesheetEndEntry( entry.content );

		stylesheetEntry( entry.content, ".bs-logbook-entry-title" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-author" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
		stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-date" );
                stylesheetProperty( entry.content, "color", foreground_colours[FOREGROUND_EM] );
                stylesheetProperty( entry.content, "font-style", "italic" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-draft" );
                stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-checkbox" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-text" );
                stylesheetProperty( entry.content, "border-top", "thin white dotted line" ); 
                stylesheetProperty( entry.content, "margin-top", "8px" );
                stylesheetProperty( entry.content, "padding-top", "8px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-editlink" );
                stylesheetProperty( entry.content, "text-align", "center" );
                stylesheetEndEntry( entry.content );
		
                //  Tree diagram style sheet entries
                
                stylesheetEntry( entry.content, ".tree, .tree_without_stalk" );
                stylesheetProperty( entry.content, "padding-left", "0px" );
                stylesheetProperty( entry.content, "padding-right", "16px" );
                stylesheetProperty( entry.content, "padding-top", "0px" );
                stylesheetProperty( entry.content, "padding-bottom", "0px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_selection .tree, .tree_selection .tree_without_stalk" );
                stylesheetProperty( entry.content, "padding-left", "0px" );
                stylesheetProperty( entry.content, "padding-right", "16px" );
                stylesheetProperty( entry.content, "padding-top", "0px" );
                stylesheetProperty( entry.content, "padding-bottom", "12px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_whole_trimmed_branch" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_trimmed_branch" );
                stylesheetProperty( entry.content, "margin-left", "24px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_branch" );
                stylesheetProperty( entry.content, "padding-bottom", "12px" );
                stylesheetProperty( entry.content, "background", "url(bs_template_tree_vline_black_22_22.gif) repeat-y 0px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_selection .tree_end_branch" );
                stylesheetProperty( entry.content, "padding-bottom", "12px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_end_branch" );
                stylesheetProperty( entry.content, "padding-bottom", "0px" );
                stylesheetEndEntry( entry.content );

                
                // new scheme for naming tree_node classes
                // s = stalk, u = up ( i.e. to senior sibling or to parent ),
                // d = down (i.e. to junior sibling), branch (to child),
                // n = no, y = yes, c = continuation (i.e. skips siblings or child(ren).)
                //
                // some permutations don't exist - if s = n then u and d must be n
                // if u = n then d must be n
                // 
                // tree_node classes differ only in the background image that provides lines
                
                // 0=n, 1=y, 2=c
                String letters[] = new String[3];
                letters[0] = "n"; letters[1] = "y"; letters[2] = "c";
                StringBuffer class_code = new StringBuffer( 10 );
                for ( i=0; i<2; i++ )
                    for ( j=0; j<3; j++ )
                        for ( k=0; k<3; k++ )
                        {
                            if ( i==0 && (j>0 || k>0) )
                                continue;
                            if ( j==0 && k>0 )
                                continue;
                            for ( l=0; l<3; l++ )
                            {
                                class_code.setLength( 0 );
                                class_code.append( "s" );
                                class_code.append( letters[i] );
                                class_code.append( "u" );
                                class_code.append( letters[j] );
                                class_code.append( "d" );
                                class_code.append( letters[k] );
                                class_code.append( "b" );
                                class_code.append( letters[l] );
                                stylesheetEntry( entry.content, ".tree_node_" + class_code.toString() );
                                stylesheetProperty( entry.content, "padding-left", "0px" );
                                stylesheetProperty( entry.content, "background", "url(bs_template_tree_node_lines_" + class_code.toString() + "_22_22.gif) no-repeat 0px 0px;" );
                                stylesheetEndEntry( entry.content );
                            }
                        }
                
                stylesheetEntry( entry.content, ".tree_node_expander_icon" );
                stylesheetProperty( entry.content, "margin", "0px" );
                stylesheetProperty( entry.content, "padding", "0px" );
                stylesheetProperty( entry.content, "float", "left" );
                stylesheetProperty( entry.content, "border", "none" );
                stylesheetProperty( entry.content, "width", "12px" );
                stylesheetProperty( entry.content, "height", "20px" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".tree_node_icon" );
                stylesheetProperty( entry.content, "margin-left", "2px" );
                stylesheetProperty( entry.content, "margin-top", "4px" );
                stylesheetProperty( entry.content, "float", "left" );
                stylesheetProperty( entry.content, "width", "22px" );
                stylesheetProperty( entry.content, "height", "22px" );
                stylesheetEndEntry( entry.content );

                // level based tree structure entries...
                
                stylesheetEntry( entry.content, ".tree_siblings_2_without_stalk" );
                stylesheetProperty( entry.content, "margin-left", "6px" );
                stylesheetProperty( entry.content, "padding-right", "16px" );
                stylesheetProperty( entry.content, "padding-bottom", "12px" );
                stylesheetEndEntry( entry.content );
                
                stylesheetEntry( entry.content, ".tree_node_content_1_without_stalk" );
                stylesheetProperty( entry.content, "margin-left", "28px" );
                stylesheetProperty( entry.content, "margin-right", "0px" );
                stylesheetProperty( entry.content, "margin-top", "0px" );
                stylesheetProperty( entry.content, "margin-bottom", "0px" );
		// can't remember why height property was put in here but it doesn't
		// work well on text blocks - IE treats it as a minimum height
		// but Netscape really messes up - layout assumes this is the 
		// height of the block but excess text spills out the bottom of
		// the box over the content below
                //stylesheetProperty( entry.content, "height", "28px" );
                stylesheetEndEntry( entry.content );

                StringBuffer element_spec = new StringBuffer();
                
                for ( i=1; i<=10; i++ )
                {
                    // these could be given varying background colours...
                    stylesheetEntry( entry.content, ".tree_siblings_" + i );
                    stylesheetProperty( entry.content, "margin-left", "24px" );
                    stylesheetProperty( entry.content, "padding-right", "16px" );
                    stylesheetProperty( entry.content, "padding-bottom", "12px" );
                    stylesheetEndEntry( entry.content );
                }

                
                element_spec.setLength( 0 );
                for ( i=1; i<=10; i++ )
                {
                    element_spec.append( ".tree_node_content_" );
                    element_spec.append( i );
                    if ( i<10 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                }
                stylesheetEntry( entry.content,  element_spec.toString() );
                stylesheetProperty( entry.content, "margin-left", "46px" );
                stylesheetProperty( entry.content, "margin-right", "0px" );
                stylesheetProperty( entry.content, "margin-top", "0px" );
                stylesheetProperty( entry.content, "margin-bottom", "0px" );
                //stylesheetProperty( entry.content, "height", "28px" );
                stylesheetEndEntry( entry.content );

                element_spec.setLength( 0 );
                for ( i=1; i<=10; i++ )
                {
                    element_spec.append( ".tree_selection .tree_node_content_" );
                    element_spec.append( i );
                    if ( i<10 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                }
                stylesheetEntry( entry.content,  element_spec.toString() );
                stylesheetProperty( entry.content, "margin-left", "46px" );
                stylesheetProperty( entry.content, "margin-right", "0px" );
                stylesheetProperty( entry.content, "margin-top", "0px" );
                stylesheetProperty( entry.content, "margin-bottom", "0px" );
                stylesheetProperty( entry.content, "padding-top", "0px" );
                stylesheetProperty( entry.content, "padding-bottom", "16px" );
                stylesheetProperty( entry.content, "padding-right", "0px" );
                stylesheetProperty( entry.content, "padding-left", "0px" );
                stylesheetEndEntry( entry.content );


                element_spec.setLength( 0 );
                for ( i=1; i<=11; i++ )
                {
                    if ( i==11 )
                        element_spec.append( ".tree_node_content_1_without_stalk" );
                    else
                    {
                        element_spec.append( ".tree_node_content_" );
                        element_spec.append( i );
                    }
                    element_spec.append( " p" );
                    if ( i<11 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                }
                stylesheetEntry( entry.content,  element_spec.toString() );
                stylesheetProperty( entry.content, "margin-top", "6px" );
                stylesheetProperty( entry.content, "margin-bottom", "4px" );
                stylesheetProperty( entry.content, "margin-left", "0px" );
                stylesheetProperty( entry.content, "margin-right", "0px" );
                stylesheetProperty( entry.content, "padding", "0px" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font_weight", "normal" );
                stylesheetEndEntry( entry.content );

                element_spec.setLength( 0 );
                for ( i=1; i<=11; i++ )
                {
                    for ( j=1; j<=6; j++ )
                    {
                        if ( i==11 )
                            element_spec.append( ".tree_node_content_1_without_stalk" );
                        else
                        {
                            element_spec.append( ".tree_node_content_" );
                            element_spec.append( i );
                        }
                        element_spec.append( " h" );
                        element_spec.append( j );
                        if ( i<11 || j<6 )
                            element_spec.append( "," );
                        element_spec.append( "\r\n" );
                    }
                }
                stylesheetEntry( entry.content,  element_spec.toString() );
                stylesheetProperty( entry.content, "margin-top", "0px" );
                stylesheetProperty( entry.content, "margin-bottom", "8px" );
                stylesheetProperty( entry.content, "margin-left", "0px" );
                stylesheetProperty( entry.content, "margin-right", "0px" );
                stylesheetProperty( entry.content, "padding", "0px" );
                stylesheetProperty( entry.content, "font-size", "100%" );
                stylesheetProperty( entry.content, "font_weight", "bold" );
                stylesheetEndEntry( entry.content );

                // outputs new style CSS classes.  Prefix indicates this is
                // specifically for resource menus and nothing else.  Note
                // that the old style tree classes above are still there to
                // support HTML tagging that is already used in tools (perhaps
                // some 3rd party tools I don't know about) for backwards
                // compatibility. In the future more calls may be made to this
                // method to support other tree diagrams with distinct display
                // options.
                
                stylesheetEntry( entry.content, ".res_tree_header" );
                stylesheetProperty( entry.content, "margin", "0px" );
                stylesheetProperty( entry.content, "padding", "6px" );
                if ( nav_background_colours[BACKGROUND_MENU_HEAD] != null )
                    stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND_MENU_HEAD] );
                stylesheetEndEntry( entry.content );
                stylesheetEntry( entry.content, ".res_tree_big_header" );
                stylesheetProperty( entry.content, "margin", "0px" );
                stylesheetProperty( entry.content, "padding", "6px" );
                if ( nav_background_colours[BACKGROUND_MENU_HEAD] != null )
                    stylesheetProperty( entry.content, "background-color", nav_background_colours[BACKGROUND_MENU_HEAD] );
                stylesheetEndEntry( entry.content );
                        
                // If either menu highlight colour differs from page backrgound
                // then colours are set in the tree classes. Otherwise the menus
                // are made transparent.
                if ( nav_background_colours[BACKGROUND_MENU_1]!=null && nav_background_colours[BACKGROUND_MENU_2]!=null &&
                     ( ( !nav_background_colours[BACKGROUND].equals( nav_background_colours[BACKGROUND_MENU_1] ) ) ||
                       ( !nav_background_colours[BACKGROUND].equals( nav_background_colours[BACKGROUND_MENU_2] ) ) )   )
                {
                    compileTreeStylesheet( 
                        entry.content, 
                        "res_tree", 
                        tree_line_path, 
                        nav_background_colours[BACKGROUND_MENU_1], 
                        nav_foreground_colours, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        nav_background_colours[BACKGROUND_MENU_2],
                        nav_foreground_colours, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        22,
                        res_menu_border_colour
                        );
                    compileTreeStylesheet( 
                        entry.content, 
                        "res_tree_big", 
                        tree_lines?tree_line_path:null, 
                        nav_background_colours[BACKGROUND_MENU_1], 
                        nav_foreground_colours, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        nav_background_colours[BACKGROUND_MENU_2],
                        nav_foreground_colours, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        44,
                        res_menu_border_colour
                        );
                }
                else
                {
                    compileTreeStylesheet( 
                        entry.content, 
                        "res_tree", 
                        tree_lines?tree_line_path:null, 
                        null, 
                        null, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        null,
                        null, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        22,
                        res_menu_border_colour
                        );
                    compileTreeStylesheet( 
                        entry.content, 
                        "res_tree_big", 
                        tree_lines?tree_line_path:null, 
                        null, 
                        null, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        null,
                        null, 
                        tree_lines?("?code=" + tree_line_colour_mapper.toString()):null,
                        44,
                        res_menu_border_colour
                        );
                }
                
                entry.last_modified = System.currentTimeMillis();
                author_style_sheets.put( resource_id, entry );
                return entry;
            }
        }
        
        private StyleSheetEntry compileUserStyleSheet( 
            Request req, 
            org.bodington.servlet.HttpSession http_session, StyleSheetSessionData sss_data, 
	    PrimaryKey user_id, StyleSheetEntry entry )
        throws RemoteException, BuildingServerException
        {
            int i, j, k, b, f;
            StringBuffer element_spec = new StringBuffer();
            
       	    Logger.getLogger("org.bodington").fine( "Compiling User Style Sheet" );

            NavigationSession nav_session = http_session.getServerNavigationSession();
            
            
            synchronized ( http_session )
            {
		String size=null;
		String colour_option=null;
                
                size = sss_data.getPreference( http_session, "preference.stylesheet.size" );
                colour_option = sss_data.getPreference( http_session, "preference.stylesheet.colour_option" );
                
		if ( colour_option == null ) colour_option = "normal";
                if ( size == null ) size = "normal";
		
		if ( entry == null )
		    entry = new StyleSheetEntry();
                entry.content = new StringBuffer();

                entry.content.append( "/* Bodington Virtual Style Sheet - User's */\r\n\r\n" );
                // instead of importing the author style sheet we can reference both
                // style sheets in the HTML with two LINK elements
                //entry.content.append( "@import url('bs_virtual_author.css');\r\n\r\n" );
                
                if ( "normal".equals( size ) && "normal".equals( colour_option ) )
                {
                    entry.last_modified = System.currentTimeMillis();
                    return entry;
                }

                boolean change_size=false, change_colour=false;
                String font_size = "100%";
                
                if ( "big".equals( size ) )
                {
                    change_size = true;
                    font_size = "150%";
                }
                
                // text size is always relative so needs to be incrased only at top level
                if ( change_size )
                {
                    for ( k=0; k<2; k++ )
                    {
                        stylesheetEntry( entry.content, k==0?"body":".bodington_navigation_page" );
                        stylesheetProperty( entry.content, "font-size", font_size );
                        stylesheetEndEntry( entry.content );
                    }
                }
                
		change_colour = !"normal".equals( colour_option );
		
                
                if ( change_colour )
                {
                // null value indicates that the user style sheet should not
                // change the colour.
                // starting to reform and simplify colour processing
                Color[][] foreground_colours      = new Color[2][];
                foreground_colours[0] = getForegroundColors( nav_session, "style" );
                foreground_colours[1] = getForegroundColors( nav_session, "style_navigation" );
                Color[][] background_colours      = new Color[2][];
                background_colours[0] = getBackgroundColors( nav_session, "style" );
                background_colours[1] = getBackgroundColors( nav_session, "style_navigation" );
                Color res_menu_border_colour = nav_session.getPropertyColor( "style_navigation_menu_border_colour", null );
                boolean tree_lines = "yes".equalsIgnoreCase( nav_session.getProperty( "ui_navigation_menu_lines", "yes" ) );
                
                // one colour mapper is needed for each background colour
                ColourPreferenceMapper[][] colour_mapper_list = new ColourPreferenceMapper[2][6];
                Color[][] preferred_background_colours = new Color[2][6];
                boolean[][] background_colour_changed = new boolean[2][6];
                Color[][][] preferred_foreground_colours = new Color[2][6][7];
                boolean[][][] foreground_colour_changed = new boolean[2][6][7];
                    
                for ( k=0; k<2; k++ )
                    for ( i=0; i<6; i++ )
                    // start with no-transform mappers
                        colour_mapper_list[k][i] = new ColourPreferenceMapper();
                
                    // transform each of the colour mappers so foreground colours can
                    // be mapped for each background colour they may appear against
                    for ( k=0; k<2; k++ )
                    {
                        for ( i=0; i<colour_mapper_list[k].length; i++ )
                        {
                            if ( background_colours[k][i] == null )
                            {
                                colour_mapper_list[k][i] = null;
                                continue;
                    }
                            colour_mapper_list[k][i].setReferenceColours( background_colours[k][i],  foreground_colours[k][FOREGROUND] );
                            if ( colour_option.equals( "black" ) )
                                colour_mapper_list[k][i].setType( ColourPreferenceMapper.TYPE_BLACK_ON_WHITE );
                    else if ( colour_option.equals( "white" ) )
                                colour_mapper_list[k][i].setType( ColourPreferenceMapper.TYPE_WHITE_ON_BLACK );
                            else if ( colour_option.equals( "contrast" ) )
                                colour_mapper_list[k][i].setType( ColourPreferenceMapper.TYPE_CONTRAST );
                            else if ( colour_option.equals( "soft" ) )
                                colour_mapper_list[k][i].setType( ColourPreferenceMapper.TYPE_SOFT );
                            else
                                colour_mapper_list[k][i].setType( ColourPreferenceMapper.TYPE_NORMAL );
                        }
                    }
                    
                    // now map all the colours against all backgrounds
                    for ( k=0; k<2; k++ )
                    {
                        for ( i=0; i<colour_mapper_list[k].length; i++ )
                        {
                            if ( colour_mapper_list[k][i] == null )
                            {
                                preferred_background_colours[k][i] = null;
                                background_colour_changed[k][i] = false;
                    }
                            else
                    {
                                preferred_background_colours[k][i] = 
                                    colour_mapper_list[k][i].getPreferredBackgroundColor();
                                background_colour_changed[k][i] = !preferred_background_colours[k][i].equals( 
                                   background_colours[k][i] );
                    }
                            // all perms of foreground against background
                            for ( j=0; j<foreground_colours[k].length; j++ )
                    {
                                if ( colour_mapper_list[k][i] == null )
                                {
                                    preferred_foreground_colours[k][i][j] = null;
                                    foreground_colour_changed[k][i][j] = false;
                    }
                    else
                    {
                                    preferred_foreground_colours[k][i][j] = 
                                        colour_mapper_list[k][i].getPreferredForegroundColor( 
                                            foreground_colours[k][j] );
                                    foreground_colour_changed[k][i][j] = !preferred_foreground_colours[k][i][j].equals( 
                                        foreground_colours[k][j] );
                    }
                }
                
                        }
                    }

                
                // These lines of code are about determining the colour of lines in the background 
                // of tree diagrams.  The code determined will be used to transform the colour of
                // the GIF files via a query string to the servlet that processed them.
                // Line will be black or white depending on background colour of page
                int effective_background_1, effective_background_2;
                effective_background_1 = (colour_mapper_list[1][BACKGROUND_MENU_1] != null)?BACKGROUND_MENU_1:BACKGROUND;
                effective_background_2 = (colour_mapper_list[1][BACKGROUND_MENU_2] != null)?BACKGROUND_MENU_2:BACKGROUND;
                
                ColourPreferenceMapper tree_line_colour_mapper_1=null; 
                ColourPreferenceMapper tree_line_colour_mapper_2=null; 
                if ( tree_lines )
                {
                    tree_line_colour_mapper_1 = new ColourPreferenceMapper( colour_mapper_list[1][effective_background_1].toString() );
                    tree_line_colour_mapper_2 = new ColourPreferenceMapper( colour_mapper_list[1][effective_background_2].toString() );
                    
                    Color tree_line_colour = null;
                    float[] hsb;
                    // if background is lighter than mid grey use black lines
                    // otherwise use white lines.
                    hsb = Color.RGBtoHSB( preferred_background_colours[1][effective_background_1].getRed(), 
                                          preferred_background_colours[1][effective_background_1].getGreen(), 
                                          preferred_background_colours[1][effective_background_1].getBlue(), null );
                    tree_line_colour = new Color( ( hsb[2] < 0.5 )?0xffffff:0x000000 );
                    tree_line_colour_mapper_1.setReferenceColours( preferred_background_colours[1][effective_background_1], tree_line_colour );
                    hsb = Color.RGBtoHSB( preferred_background_colours[1][effective_background_2].getRed(), 
                                          preferred_background_colours[1][effective_background_2].getGreen(), 
                                          preferred_background_colours[1][effective_background_2].getBlue(), null );
                    tree_line_colour = new Color( ( hsb[2] < 0.5 )?0xffffff:0x000000 );
                    tree_line_colour_mapper_2.setReferenceColours( preferred_background_colours[1][effective_background_2], tree_line_colour );
                }
		    
                // colours all worked out, now output stylesheet
                
                // do all doc page stuff and then nav pages
                for ( k=0; k<2; k++ )
                    {
                    for ( i=0; i<=BACKGROUND_MENU_HEAD; i++ )
			{
                        for ( b=0; b<css_back_elements[i].length; b++ )
                        {
                            // adapt all the background colours
                            if ( background_colour_changed[k][i] )
                            {
                                element_spec.setLength( 0  );
                                if ( k==1 )
                                    element_spec.append( ".bodington_navigation_page " );
                                // don't need body in navigation pages
                                if ( k==0 || !"body".equals( css_back_elements[i][b] ) )
                                    element_spec.append( css_back_elements[i][b] );

                                stylesheetEntry( entry.content, element_spec.toString() );
                                stylesheetProperty( entry.content, "background-color", preferred_background_colours[k][i] );
			    stylesheetProperty( entry.content, "background-image", "none" );
                                stylesheetEndEntry( entry.content );
			}

                            // adpet all foreground colours for all backgrounds
                            for ( j=0; j<=FOREGROUND_HOVER; j++ )
                            {
                                if ( !foreground_colour_changed[k][i][j] )
                                    continue;
                                for ( f=0; f<css_fore_elements[j].length; f++ )
                                {
                                    element_spec.setLength( 0  );
                                    if ( k==1 )
                                        element_spec.append( ".bodington_navigation_page " );
                                    // don't need body in navigation pages
                                    if ( k==0 || !"body".equals( css_back_elements[i][b] ) )
                                        element_spec.append( css_back_elements[i][b] );
                                    element_spec.append( " " );
                                    element_spec.append( css_fore_elements[j][f] );
                                    stylesheetEntry( entry.content, element_spec.toString() );
                                    stylesheetProperty( entry.content, "color", preferred_foreground_colours[k][i][j] );
                                    stylesheetEndEntry( entry.content );
                    }
                            }

                        }
                    }
                }
		    

                    // ===========================================================
                    Color preferred_colour = colour_mapper_list[0][BACKGROUND].getPreferredForegroundColor( new Color( 0x202020 ) );
                    if ( !(new Color( 0x202020 )).equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bs-logbook-command-disabled" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }
                    
                    // This is currently only needed in the user stylesheet if the
                    // user preference affects colour because the background lines
                    // need to change colour in the CSS instructions. It is assumed
                    // that resource trees are always on pages that use the 
                    // navigation colour scheme.
                    
                    // outputs new style CSS classes.  Prefix indicates this is
                    // specifically for resource menus and nothing else.  Note
                    // that the old style tree classes above are still there to
                    // support HTML tagging that is already used in tools (perhaps
                    // some 3rd party tools I don't know about) for backwards
                    // compatibility. In the future more calls may be made to this
                    // method to support other tree diagrams with distinct display
                    // options.
                    String tree_line_path = "bs_template_";  // defaults to be relative to stylesheet and with prefix
                    Resource resource = req.getResource();
                    String sample_tree_line = "tree_node_lines_snundnbc_22_22.gif";
                    Template template = Template.get( this.facilityname, resource.getImplicitHttpUIStyle(), resource.getResourceId(), sample_tree_line );
                    if ( template != null )
                    {
                        tree_line_path = req.getContextPath() + "/processedgif/templates" + template.getUrl();
                        tree_line_path = tree_line_path.substring( 0, tree_line_path.length() - sample_tree_line.length() );
                    }
                    
                    // only bother outputting tree classes if they aren't transparent in author stylesheet
                    if ( ( !background_colours[1][BACKGROUND].equals( background_colours[1][BACKGROUND_MENU_1] ) ) ||
                         ( !background_colours[1][BACKGROUND].equals( background_colours[1][BACKGROUND_MENU_2] ) )    )
			{
                        compileTreeStylesheet( 
                            entry.content, 
                            "res_tree", 
                            tree_line_path, 
                            preferred_background_colours[1][BACKGROUND_MENU_1], 
                            preferred_foreground_colours[1][BACKGROUND_MENU_1], 
                            tree_lines?("?code=" + tree_line_colour_mapper_1.toString()):null,
                            preferred_background_colours[1][BACKGROUND_MENU_2],
                            preferred_foreground_colours[1][BACKGROUND_MENU_2], 
                            tree_lines?("?code=" + tree_line_colour_mapper_2.toString()):null,
                            22,
                            res_menu_border_colour
                            );
                        compileTreeStylesheet( 
                            entry.content, 
                            "res_tree_big", 
                            tree_line_path, 
                            preferred_background_colours[1][BACKGROUND_MENU_1], 
                            preferred_foreground_colours[1][BACKGROUND_MENU_1], 
                            tree_lines?("?code=" + tree_line_colour_mapper_1.toString()):null,
                            preferred_background_colours[1][BACKGROUND_MENU_2],
                            preferred_foreground_colours[1][BACKGROUND_MENU_2], 
                            tree_lines?("?code=" + tree_line_colour_mapper_2.toString()):null,
                            44,
                            res_menu_border_colour
                            );
			}
                    }
                entry.last_modified = System.currentTimeMillis();
                return entry;
                }
        }

                
        
        
        private StringBuffer compileTreeStylesheet
            ( 
                StringBuffer buffer,               // This receives the CSS definitions
                String prefix,                     // This prefix is used on all class names
                String lines_path,                 // Used as path to GIFs
                Color background_1,               // Color for highlight 1
                Color[] foreground_1,
                String lines_colour_mapper_code_1, // Used on all references to background GIFs for colour adaptation
                Color background_2,               // Color for highlight 1
                Color[] foreground_2,
                String lines_colour_mapper_code_2,  // Used on all references to background GIFs for colour adaptation
                int icon_size,                       // dimensions of icons - affects dimenstions and background images
                Color border_colour
            )
                {
            int i, j, k, l, hl, d;
            boolean big_icons = icon_size>22;
            boolean tree_lines = (lines_colour_mapper_code_1!=null && lines_colour_mapper_code_2!=null);
            
            StringBuffer element_spec = new StringBuffer();
            StringBuffer property_spec = new StringBuffer();

            if ( foreground_1 == null ) foreground_1 = new Color[7];
            if ( foreground_2 == null ) foreground_2 = new Color[7];
            
            Color strHL, strTC;
            
            boolean highlight_branches = true;
            boolean highlight_nodes = true;
            boolean highlight_content = false;
            
            // get rid of border if no backgrounds
            if ( border_colour != null && background_1 == null && background_2 == null )
                border_colour = null;

            // get rid of border if the colour is the same as the background
            if ( border_colour != null && background_1 != null && border_colour.equals( background_1 ) )
                border_colour = null;
            
            boolean border_branches = border_colour != null;
            boolean border_nodes = border_colour != null;
            int border_width = (border_colour != null)?1:0;
            String res_menu_border_style = 
                (border_width>0)?("solid " + border_width + "px #" + 
                    Integer.toHexString( border_colour.getRGB() ).substring(2)):null;
            
            stylesheetEntry(buffer, ".clearer");
            stylesheetProperty(buffer, "clear", "left");
            stylesheetProperty(buffer, "line-height", "0");
            stylesheetProperty(buffer, "height", "0");
            stylesheetEndEntry(buffer);
            

            
            stylesheetEntry( buffer, "." + prefix );
            stylesheetProperty( buffer, "margin", "0.5em" );
            //stylesheetProperty( buffer, "padding", "0px" );
            if ( border_width>0 && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                stylesheetProperty( buffer, "border-right", res_menu_border_style );
            stylesheetEndEntry( buffer );


            // silly extra div needed for M$ ie6 because of bug in CSS handling.
            // In ie6 the background graphic on a div is misplaced if there is a div
            // (or p) inside the div with the background.  The background image origin
            // coordinate is shifted to the OUTSIDE of the border instead of the INSIDE
            // of the border which is correct.  Ie6 cannot be forced into correct behaviour
            // by use of "standards compatibility mode" but can be fooled if a width OR
            // height property is applied to the div with the background image.  However,
            // that doesn't work here because 100% width is also treated differently by
            // ie6 and others.  So only solution is to never put background images and
            // border on the same div if there may be other divs inside that need to
            // line up!
            stylesheetEntry( buffer,  "." + prefix + "_branch_border" );
            if ( border_branches )
                    {
                stylesheetProperty( buffer, "background-color", border_colour );
                stylesheetProperty( buffer, "padding", "" + border_width + "px 0px 0px " + border_width + "px"  );
                    }
            else
                stylesheetProperty( buffer, "padding", "0px"  );
            stylesheetProperty( buffer, "margin", "0px" );
            //stylesheetProperty( buffer, "border-top", res_menu_border_style );
            //stylesheetProperty( buffer, "border-left", res_menu_border_style );
            stylesheetEndEntry( buffer );
            stylesheetEntry( buffer,  "." + prefix + "_end_branch_border" );
            if ( border_branches )
                    {
                stylesheetProperty( buffer, "background-color", border_colour );
                stylesheetProperty( buffer, "padding", "" + border_width + "px 0px " + border_width + "px " + border_width + "px" );
                    }
            else
                stylesheetProperty( buffer, "padding", "0px"  );
            stylesheetProperty( buffer, "margin", "0px" );
            //stylesheetProperty( buffer, "border-top", res_menu_border_style );
            //stylesheetProperty( buffer, "border-left", res_menu_border_style );
            //stylesheetProperty( buffer, "border-bottom", res_menu_border_style );   
            stylesheetEndEntry( buffer );

            
            
            // one of these surrounds a node that has children
            // first provides a vertical line to next node and second
            // lacks that line. A branch has a node and a sibling set
            // for the children.
            for ( hl=1; hl<=2; hl++ )
                    {
                // level 1 branch must be highlighted if nodes/content are
                stylesheetEntry( buffer,  "." + prefix + "_branch_lev1_hl" + hl );
                stylesheetProperty( buffer, "margin", "0px" );
                stylesheetProperty( buffer, "padding", "0px, 0px, 0px, 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( hl==1 ) strTC = foreground_1[FOREGROUND]; else strTC = foreground_2[FOREGROUND];
                if ( (highlight_branches /*|| highlight_nodes || highlight_content*/) && strHL!=null )
                    stylesheetProperty( buffer, "background-color", strHL );

                stylesheetEndEntry( buffer );
                // other levels
                element_spec.setLength( 0 );
                for ( i=2; i<=10; i++ )
                    {
                    element_spec.append( "." + prefix + "_branch_lev" );
                    element_spec.append( i );
                    element_spec.append( "_hl" );
                    element_spec.append( hl );
                    if ( i<10 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                    }
                stylesheetEntry( buffer,  element_spec.toString() );
                stylesheetProperty( buffer, "margin", "0px" );
                stylesheetProperty( buffer, "padding", "0px, 0px, 0px, 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( hl==1 ) strTC = foreground_1[FOREGROUND]; else strTC = foreground_2[FOREGROUND];
                if ( tree_lines )
                {
                    property_spec.setLength( 0 );
                    property_spec.append( "url(" );
                    property_spec.append( lines_path );
                    property_spec.append( "tree_vline_black_" + icon_size + "_" + icon_size + ".gif" );
                    property_spec.append( (hl==1)?lines_colour_mapper_code_1:lines_colour_mapper_code_2 );
                    property_spec.append( ") " );
                    stylesheetProperty( buffer, "background-image", property_spec.toString() );
                    //stylesheetProperty( buffer, "width", "100%" );
                    stylesheetProperty( buffer, "background-repeat", "repeat-y" );
                    stylesheetProperty( buffer, "background-position", "top left" );
                }
                if ( highlight_branches  && strHL!=null )
                    stylesheetProperty( buffer, "background-color", strHL );

                //if ( border_branches && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                //{
                //    stylesheetProperty( buffer, "border-top", res_menu_border_style );
                //    stylesheetProperty( buffer, "border-left", res_menu_border_style );
                //    //stylesheetProperty( buffer, "border", strTC );
                //}
                stylesheetEndEntry( buffer );
            }

            for ( hl=1; hl<=2; hl++ )
                    {
                // level 1 branch must be highlighted if nodes/content are
                stylesheetEntry( buffer,  "." + prefix + "_end_branch_lev1_hl" + hl );
                stylesheetProperty( buffer, "margin", "0px" );
                stylesheetProperty( buffer, "padding", "0px, 0px, 0px, 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( hl==1 ) strTC = foreground_1[FOREGROUND]; else strTC = foreground_2[FOREGROUND];
                
                if ( (highlight_branches /*|| highlight_nodes || highlight_content*/) && strHL!=null )
                    stylesheetProperty( buffer, "background", strHL );
                
                //if ( border_branches && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                //{
                //    stylesheetProperty( buffer, "border-top", res_menu_border_style );
                //    stylesheetProperty( buffer, "border-bottom", res_menu_border_style );
                //    stylesheetProperty( buffer, "border-left", res_menu_border_style );
                //    //stylesheetProperty( buffer, "border", strTC );
                //}
                stylesheetEndEntry( buffer );
                // other levels
                element_spec.setLength( 0 );
                for ( i=2; i<=10; i++ )
                {
                    element_spec.append( "." + prefix + "_end_branch_lev" );
                    element_spec.append( i );
                    element_spec.append( "_hl" );
                    element_spec.append( hl );
                    if ( i<10 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                    }
                stylesheetEntry( buffer,  element_spec.toString() );
                stylesheetProperty( buffer, "margin", "0px" );
                stylesheetProperty( buffer, "padding", "0px, 0px, 0px, 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( highlight_branches && strHL!=null )
                    stylesheetProperty( buffer, "background", strHL );
                //if ( border_branches && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                //{
                //    stylesheetProperty( buffer, "border-top", res_menu_border_style );
                //    stylesheetProperty( buffer, "border-bottom", res_menu_border_style );
                //    stylesheetProperty( buffer, "border-left", res_menu_border_style );
                //    //stylesheetProperty( buffer, "border", strTC );
                //}
                stylesheetEndEntry( buffer );
            }


            // new scheme for naming tree_node classes
            // s = stalk, u = up ( i.e. to senior sibling or to parent ),
            // d = down (i.e. to junior sibling), branch (to child),
            // n = no, y = yes, c = continuation (i.e. skips siblings or child(ren).)
            //
            // some permutations don't exist - if s = n then u and d must be n
            // if u = n then d must be n
            // 
            // level and highlight variants are used so that background images
            // can have colour alterations for visibility against highlight colours.
            // tree_node classes differ only in the background image that provides lines

            // 0=n, 1=y, 2=c
            String letters[] = new String[3];
            letters[0] = "n"; letters[1] = "y"; letters[2] = "c";
            StringBuffer class_code = new StringBuffer( 10 );
            for ( i=0; i<2; i++ )
                for ( j=0; j<3; j++ )
                    for ( k=0; k<3; k++ )
                    {
                            if ( i==0 && (j>0 || k>0) )
                                continue;
                            if ( j==0 && k>0 )
                                continue;
                            for ( l=0; l<3; l++ )
                            {
                                class_code.setLength( 0 );
                                class_code.append( "s" );
                                class_code.append( letters[i] );
                                class_code.append( "u" );
                                class_code.append( letters[j] );
                                class_code.append( "d" );
                                class_code.append( letters[k] );
                                class_code.append( "b" );
                                class_code.append( letters[l] );
                                for ( hl=1; hl<=2; hl++ )
                                {
                                    element_spec.setLength( 0 );
                                    for ( d=1; d<=10; d++ )
                                    {
                                        element_spec.append( "." + prefix + "_node_" );
                                        element_spec.append( class_code.toString() );
                                        element_spec.append( "_lev" );
                                        element_spec.append( d );
                                        element_spec.append( "_hl" );
                                        element_spec.append( hl );
                                        if ( d<10 )
                                            element_spec.append( ", " );
                                        element_spec.append( "\r\n" );
                    }
                                    stylesheetEntry( buffer, element_spec.toString() );
                                    stylesheetProperty( buffer, "margin", "0px" );
                                    stylesheetProperty( buffer, "padding", "0em 0em 0em 0em" );
                                    if ( hl==1 ) strHL = background_1; else strHL = background_2;
                                    property_spec.setLength( 0 );
                                    if ( tree_lines )
                                    {
                                        property_spec.append( "url(" );
                                        property_spec.append( lines_path );
                                        property_spec.append( "tree_node_lines_" );
                                        property_spec.append( class_code.toString() );
                                        property_spec.append( "_" + icon_size + "_" + icon_size + ".gif" );
                                        property_spec.append( (hl==1)?lines_colour_mapper_code_1:lines_colour_mapper_code_2 );
                                        property_spec.append( ") " );
                                    }
                                    stylesheetProperty( buffer, "background-image", property_spec.toString() );
                                    stylesheetProperty( buffer, "background-repeat", "no-repeat" );
                                    stylesheetProperty( buffer, "background-position", "top left" );
                                    if ( highlight_nodes && strHL!=null )
                                        stylesheetProperty( buffer, "background-color", strHL );
                                    //if ( border_nodes && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                                    //{
                                        //stylesheetProperty( buffer, "border-right", res_menu_border_style );
                                        //stylesheetProperty( buffer, "border-bottom", res_menu_border_style );
                                        //stylesheetProperty( buffer, "border-left", res_menu_border_style );
                                        //stylesheetProperty( buffer, "border", strTC );
                                    //}
                                    stylesheetEndEntry( buffer );
                                }
                            }
                        }
            buffer.append(" /* Hides from IE5-mac \\*/\n");
            for ( i=0; i<2; i++ )
                for ( j=0; j<3; j++ )
                    for ( k=0; k<3; k++ )
                    {
                            if ( i==0 && (j>0 || k>0) )
                                continue;
                            if ( j==0 && k>0 )
                                continue;
                            for ( l=0; l<3; l++ )
                            {
                                class_code.setLength( 0 );
                                class_code.append( "s" );
                                class_code.append( letters[i] );
                                class_code.append( "u" );
                                class_code.append( letters[j] );
                                class_code.append( "d" );
                                class_code.append( letters[k] );
                                class_code.append( "b" );
                                class_code.append( letters[l] );
                                for ( hl=1; hl<=2; hl++ )
                                {

                                    for ( d=1; d<=10; d++ )
                                    {
                                        element_spec.setLength( 0 );
                                        element_spec.append( "." + prefix + "_node_" );
                                        element_spec.append( class_code.toString() );
                                        element_spec.append( "_lev" );
                                        element_spec.append( d );
                                        element_spec.append( "_hl" );
                                        element_spec.append( hl );
                        
                    
                                    /* Hack for the IE Peaaboo Bug
                                     * http://www.positioniseverything.net/articles/hollyhack.html#haslayout
                                     */

                                        buffer.append("* html  "+ element_spec.toString()+ ",");
                                        buffer.append("\n");
                                      
                                    }
                                }
                            }
                        }
            buffer.append("* html .doesnotexist\n");
            buffer.append(" { height: 1%; }\n");
            buffer.append("/* End hide from IE5-mac */\n");

            // The expander/collapser icon can't go in the background of the
            // node because it needs to be clicked on.  Style makes sure it
            // lines up with the background image.
            stylesheetEntry( buffer, "." + prefix + "_node_expander_icon" );
            stylesheetProperty( buffer, "margin", "0px 0px 0px 3px" );
            stylesheetProperty( buffer, "padding", "0px" );
            stylesheetProperty( buffer, "float", "left" );
            stylesheetProperty( buffer, "border", "none" );
            //stylesheetProperty( buffer, "width", "12px" );
            //stylesheetProperty( buffer, "height", "20px" );
            stylesheetEndEntry( buffer );

            // To line things up without or without stalk or expander
            // icon there are three alternate styles for the 22 by 22 icon
            // that represents the node.
            stylesheetEntry( buffer, "." + prefix + "_node_icon" );
            stylesheetProperty( buffer, "margin", "4px 6px 0px " + (6*(icon_size/22)) + "px" );
            stylesheetProperty( buffer, "padding", "0px" );
            stylesheetProperty( buffer, "float", "left" );
            stylesheetProperty( buffer, "border", "none" );
            //stylesheetProperty( buffer, "width", "22px" );
            //stylesheetProperty( buffer, "height", "22px" );
            stylesheetEndEntry( buffer );

            stylesheetEntry( buffer, "." + prefix + "_node_icon_without_stalk" );
            stylesheetProperty( buffer, "margin", "4px 6px 0px " + (3*(icon_size/22)) + "px" );
            stylesheetProperty( buffer, "padding", "0px" );
            stylesheetProperty( buffer, "float", "left" );
            stylesheetProperty( buffer, "border", "none" );
            //stylesheetProperty( buffer, "width", "22px" );
            //stylesheetProperty( buffer, "height", "22px" );
            stylesheetEndEntry( buffer );

            stylesheetEntry( buffer, "." + prefix + "_node_icon_no_expander" );
            stylesheetProperty( buffer, "margin", "4px 6px 0px " + ((tree_lines?21:6)*(icon_size/22)) + "px" );
            stylesheetProperty( buffer, "padding", "0px" );
            stylesheetProperty( buffer, "float", "left" );
            stylesheetProperty( buffer, "border", "none" );
            //stylesheetProperty( buffer, "width", "22px" );
            //stylesheetProperty( buffer, "height", "22px" );
            stylesheetEndEntry( buffer );


            // level based tree structure entries...
            // (So different style could be applied to nodes at 
            // different depths in the tree.  Actually a cycle of
            // ten levels.)

            // siblings refers to a set of sibling nodes that are in the
            // second half of a branch, after the parent node.
            for ( i=1; i<=10; i++ )
                    {
                // these could be given varying background colours...
                stylesheetEntry( buffer, "." + prefix + "_siblings_lev" + i );
                stylesheetProperty( buffer, "margin", "0px 0px 0px "+ ((tree_lines?24:6)*(icon_size/22)-border_width) + "px" );
                stylesheetProperty( buffer, "padding", "0px 0px 0px 0px" );
                //stylesheetProperty( buffer, "background", randomColour() );
                stylesheetEndEntry( buffer );
                    }

            // If level 1 lacks a stalk, level 2 siblings need less
            // indenting.
            stylesheetEntry( buffer, "." + prefix + "_siblings_without_stalk_lev2" );
            stylesheetProperty( buffer, "margin", "0px 0px 0px "+ (6*(icon_size/22)-border_width) + "px" );
            stylesheetProperty( buffer, "padding", "0px 0px 0px 0px" );
            //stylesheetProperty( buffer, "background", randomColour() );
            stylesheetEndEntry( buffer );

            // always transparent empty used after last node in siblings to
            // provide space that can have a border on right side
            stylesheetEntry( buffer, "." + prefix + "_siblings_padding" );
            stylesheetProperty( buffer, "margin", "0px 0px 0px 0px" );
            stylesheetProperty( buffer, "padding", "0px 0px 12px 0px" );
            //if ( border_nodes && res_menu_border_style!=null && res_menu_border_style.length()>0 )
                //stylesheetProperty( buffer, "border-right", res_menu_border_style );
            stylesheetEndEntry( buffer );
            
            
            // tree node content is the part of the node after the
            // expander icon and the node icon which actually describes
            // the node.  There can be more than one content block in a
            // node.
            // Here all levels are defined the same.
            for ( hl=1; hl<=2; hl++ )
                    {
                element_spec.setLength( 0 );
                for ( i=1; i<=10; i++ )
                {
                    element_spec.append( "." + prefix + "_node_content_lev" );
                    element_spec.append( i );
                    element_spec.append( "_hl" );
                    element_spec.append( hl );
                    if ( i<10 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                    }
                stylesheetEntry( buffer,  element_spec.toString() );
                stylesheetProperty( buffer, "display", "block" );
                stylesheetProperty( buffer, "margin", "0px 0px 0px "+ ((tree_lines?50:36)*(icon_size/22)) + "px" );
                stylesheetProperty( buffer, "padding", "4px 0px 4px 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( hl==1 ) strTC = foreground_1[FOREGROUND]; else strTC = foreground_2[FOREGROUND];
                if ( highlight_content && strHL!=null )
                    stylesheetProperty( buffer, "background", strHL );
//                if ( (highlight_content || highlight_nodes || highlight_branches) && strTC!=null )
//                    stylesheetProperty( buffer, "color", strTC ); // seems to prevent link colour settings to be used.
                stylesheetEndEntry( buffer );
            }


            // less indenting at root node if root node lacks stalk.
            for ( hl=1; hl<=2; hl++ )
                    {
                element_spec.setLength( 0 );
                element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl" );
                element_spec.append( hl );
                stylesheetEntry( buffer,  element_spec.toString() );
                stylesheetProperty( buffer, "display", "block" );
                stylesheetProperty( buffer, "margin", "0px 0px 0px " + (36*(icon_size/22)) + "px" );
                stylesheetProperty( buffer, "padding", "4px 0px 4px 0px" );
                if ( hl==1 ) strHL = background_1; else strHL = background_2;
                if ( hl==1 ) strTC = foreground_1[FOREGROUND]; else strTC = foreground_2[FOREGROUND];
                if ( highlight_content && strHL!=null )
                    stylesheetProperty( buffer, "background", strHL );
                if ( (highlight_content) && strTC!=null )
                    stylesheetProperty( buffer, "color", strTC );
                stylesheetEndEntry( buffer );
                    }
                


            // The following are for styling actual text within the node.


            // This is intended for styling headings that introduce the
            // the node.  Use is optional.  If required, this should enclose
            // the icons and then the text should be enclosed by span with
            // class="tree_node_content_x".
            element_spec.setLength( 0 );
            for ( i=1; i<=10; i++ )
                    {
                element_spec.append( "." + prefix + "_node_title_lev" );
                element_spec.append( i );
                if ( i<10 )
                    element_spec.append( "," );
                element_spec.append( "\r\n" );
                    }
            stylesheetEntry( buffer,  element_spec.toString() );
            stylesheetProperty( buffer, "margin", "0px 0px 0px 0px" );
            stylesheetProperty( buffer, "padding", "0px 0px 0px 0px" );
            stylesheetProperty( buffer, "vertical-align", "bottom" );
            stylesheetProperty( buffer, "font-size", "100%" );
            stylesheetProperty( buffer, "font_weight", "bold" );
            //stylesheetProperty( buffer, "height", "28px" );
            stylesheetEndEntry( buffer );


            // headings go in their
            stylesheetEntry( buffer,  "." + prefix + "_heading_node_title" );
            stylesheetProperty( buffer, "margin", "0px 0px 0px " + ((tree_lines?50:35)*(icon_size/22)) + "px" );
            stylesheetProperty( buffer, "padding", "5px 0px 0px 0px" );
            stylesheetProperty( buffer, "text-align", "left" );//uhi:awc changed text-align to left
            stylesheetProperty( buffer, "font-size", "100%" );
            stylesheetProperty( buffer, "font_weight", "bold" );
            //if ( border_nodes && res_menu_border_style!=null && res_menu_border_style.length()>0 )
            //    stylesheetProperty( buffer, "border-right", res_menu_border_style );
            stylesheetEndEntry( buffer );


            // Styles content in links and links in content to have proper
            // colours depending on highlight style
            for ( d=0; d<4; d++ )
            for ( hl=1; hl<=2; hl++ )
                    {
                element_spec.setLength( 0 );
                strTC=null;
                for ( i=1; i<=11; i++ )
                {
                    if ( i==11 )
                        element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl" );
                    else
                    {
                        element_spec.append( "." + prefix + "_node_content_lev" );
                        element_spec.append( i );
                        element_spec.append( "_hl" );
                    }
                    element_spec.append( hl );
                    switch ( d )
                    {
                        case 0:
                            element_spec.append( " a:link, a:link " );
                            if ( hl==1 ) strTC = foreground_1[FOREGROUND_LINK]; else strTC = foreground_2[FOREGROUND_LINK];
                            break;
                        case 1:
                            element_spec.append( " a:visited, a:visited " );
                            if ( hl==1 ) strTC = foreground_1[FOREGROUND_VISITED]; else strTC = foreground_2[FOREGROUND_VISITED];
                            break;
                        case 2:
                            element_spec.append( " a:active, a:active " );
                            if ( hl==1 ) strTC = foreground_1[FOREGROUND_ACTIVE]; else strTC = foreground_2[FOREGROUND_ACTIVE];
                            break;
                        case 3:
                            element_spec.append( " a:hover, a:hover " );
                            if ( hl==1 ) strTC = foreground_1[FOREGROUND_HOVER]; else strTC = foreground_2[FOREGROUND_HOVER];
                            break;
                    }
                    if ( i==11 )
                        element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl" );
                    else
                    {
                        element_spec.append( "." + prefix + "_node_content_lev" );
                        element_spec.append( i );
                        element_spec.append( "_hl" );
                    }
                    element_spec.append( hl );
                    if ( i<11 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
                }
                stylesheetEntry( buffer,  element_spec.toString() );
                if ( (highlight_content) && strTC!=null )
                    stylesheetProperty( buffer, "color", strTC );
                stylesheetEndEntry( buffer );
            }


            // Styles p elements inside all types of content div.
            // puts all paragraph spacing to avoid margin spilling out
            // of node.
            element_spec.setLength( 0 );
            for ( i=1; i<=11; i++ )
                    {
                if ( i==11 )
                    element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl1 p, " );
                else
                {
                    element_spec.append( "." + prefix + "_node_content_lev" );
                    element_spec.append( i );
                    element_spec.append( "_hl1 p, " );
                    }
                if ( i==11 )
                    element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl2 p " );
                else
                {
                    element_spec.append( "." + prefix + "_node_content_lev" );
                    element_spec.append( i );
                    element_spec.append( "_hl2 p" );
                }
                if ( i<11 )
                    element_spec.append( "," );
                element_spec.append( "\r\n" );
            }
            stylesheetEntry( buffer,  element_spec.toString() );
            stylesheetProperty( buffer, "margin", "0em 0em 0em 0em" );
            stylesheetProperty( buffer, "padding", "0.25em 0em 0em 0em" );
            stylesheetProperty( buffer, "font-size", "100%" );
            stylesheetProperty( buffer, "font_weight", "normal" );
            //stylesheetProperty( buffer, "border", "1px solid black" );
            stylesheetEndEntry( buffer );



            // Styles all heading levels to be the same.  Indenting will
            // show heading level visually but audible browser will go by
            // the heading level tag.  Without CSS the headings will revert
            // to varying size.
            element_spec.setLength( 0 );
            for ( i=1; i<=11; i++ )
                    {
                for ( j=1; j<=6; j++ )
                {
                    if ( i==11 )
                        element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl1 h" );
                    else
                    {
                        element_spec.append( "." + prefix + "_node_content_lev" );
                        element_spec.append( i );
                        element_spec.append( "_hl1 h" );
                    }
                    element_spec.append( j );
                    element_spec.append( ", " );
                    if ( i==11 )
                        element_spec.append( "." + prefix + "_node_content_without_stalk_lev1_hl2 h" );
                    else
                    {
                        element_spec.append( "." + prefix + "_node_content_lev" );
                        element_spec.append( i );
                        element_spec.append( "_hl2 h" );
                }
                    element_spec.append( j );
                
                    if ( i<11 || j<6 )
                        element_spec.append( "," );
                    element_spec.append( "\r\n" );
            }
        }
            stylesheetEntry( buffer,  element_spec.toString() );
            stylesheetProperty( buffer, "margin", "0.5em 0em 0em 0em" );
            stylesheetProperty( buffer, "padding", "0px" );
            stylesheetProperty( buffer, "font-size", "100%" );
            stylesheetProperty( buffer, "font_weight", "bold" );
            //stylesheetProperty( buffer, "border", "1px solid black" );
            stylesheetEndEntry( buffer );
        

        
            // The following will allow a branch of the tree to be
            // marked as selected and display differently.

            //stylesheetEntry( buffer, "." + prefix + "_selection .tree, ." + prefix + "_selection ." + prefix + "_without_stalk" );
            //stylesheetProperty( buffer, "margin", "0px 0px 12px 0px" );
            //stylesheetEndEntry( buffer );
            //stylesheetEntry( buffer, "." + prefix + "_selection ." + prefix + "_end_branch" );
            //stylesheetProperty( buffer, "padding-bottom", "12px" );
            //stylesheetEndEntry( buffer );

            //element_spec.setLength( 0 );
            //for ( i=1; i<=10; i++ )
            //{
            //    element_spec.append( "." + prefix + "_selection ." + prefix + "_node_content_" );
            //    element_spec.append( i );
            //    if ( i<10 )
            //        element_spec.append( "," );
            //    element_spec.append( "\r\n" );
            //}
            //stylesheetEntry( buffer,  element_spec.toString() );
            //stylesheetProperty( buffer, "margin", "0px 0px 16px 46px" );
            //stylesheetProperty( buffer, "padding", "0px 0px 16px 0px" );
            //stylesheetEndEntry( buffer );





            return buffer;
         }
        
        
        
	public void sendAuthorStyleSheet( Request req, HttpServletResponse res )
        throws IOException, RemoteException, BuildingServerException
		{
                BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
                PrimaryKey resource_id = req.getResource().getResourceId();
		StyleSheetEntry entry;
		synchronized ( author_style_sheets )
		{
		    entry = (StyleSheetEntry)author_style_sheets.get( resource_id );
		}
                
                if ( entry == null || entry.content == null )
                    entry = compileAuthorStyleSheet( req, session, resource_id );
                
                if ( session.getPropertiesLastModifiedTime() > entry.last_modified )
                    entry = compileAuthorStyleSheet( req, session, resource_id );
                
                long last_modified = (entry.last_modified/1000)*1000;
                long if_mod_since_header = req.getDateHeader( "If-Modified-Since" );
                res.setContentType( "text/css" );
                res.setDateHeader( "Last-Modified", last_modified ); 
                res.setDateHeader( "Expires", System.currentTimeMillis() + (1000) );
                if ( last_modified <= if_mod_since_header  )
                {
                    res.setStatus( res.SC_NOT_MODIFIED );
                    return;
                }
                
		PrintWriter writer = new PrintWriter( res.getWriter() );
                writer.print( entry.content );
		}

	public void sendUserStyleSheet( org.bodington.servlet.Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
                org.bodington.servlet.HttpSession http_session = 
                    (org.bodington.servlet.HttpSession)req.getSession( false );

                StyleSheetSessionData sss_data = getStyleSheetSessionData( http_session );
		
		Hashtable user_style_sheets = 
		    (Hashtable)http_session.getAttribute( "org.bodington.user_style_sheet_table" );
		if ( user_style_sheets == null )
		{
		    user_style_sheets = new Hashtable();
		    http_session.setAttribute( "org.bodington.user_style_sheet_table", user_style_sheets );
		}
		
                StyleSheetEntry entry = (StyleSheetEntry)user_style_sheets.get( req.getResource().getResourceId() );

		// compile if there isn't a style sheet entry in the table,
		// if there is any content in the entry or if the user changed
		// options since the content was last compiled
                if ( entry == null || entry.content == null || entry.last_modified < sss_data.last_changed_options )
		{
		    PrimaryKey user_id = req.getUserId();
                    entry = compileUserStyleSheet( req, http_session, sss_data, user_id, entry );
		    user_style_sheets.put( entry, req.getResource().getResourceId() );
		}
                
                long last_modified = (entry.last_modified/1000)*1000;
                long if_mod_since_header = req.getDateHeader( "If-Modified-Since" );
                res.setContentType( "text/css" );
                res.setDateHeader( "Last-Modified", last_modified ); 
                res.setDateHeader( "Expires", System.currentTimeMillis() + (1000) );

                if ( last_modified <= if_mod_since_header  )
                {
                    res.setStatus( res.SC_NOT_MODIFIED );
                    return;
                }
                
                PrintWriter writer = new PrintWriter( res.getWriter() );
                writer.print( entry.content );
		}

	public String compileAutoStyleSheet( Request req, org.bodington.servlet.HttpSession http_session )
        throws IOException, RemoteException, BuildingServerException
	{
            StringBuffer buffer = new StringBuffer( 512 );
            
	    buffer.append( "/*  This is a dynamically generated file  */\n" );

	    StyleSheetSessionData sss_data=null;

	    if ( http_session != null )
	    {
		sss_data = (StyleSheetSessionData)
		http_session.getAttribute( "org.bodington.user_style_sheet_session_data" );

		if ( sss_data!=null && !sss_data.enable_style_sheets )
		    return buffer.toString();

		// are we making a transition between unauthenticated into authenticated?
		// in which case there may be options to take into account now.
		if ( sss_data !=null && sss_data.was_unauth_style && 
			req.isAuthenticated() && !req.isAnonymous() )
		{
		    sss_data.was_unauth_style = false;
		    sss_data.number_of_changes++;
		    sss_data.last_changed_options=System.currentTimeMillis();

		    // if user chose preferences while logging in save them
		    if ( sss_data.unsaved_changes )
		    {
                        // get current values which will be from http_session if recently changed
                        // and from database if not changed
                        String size = sss_data.getPreference( http_session, "preference.stylesheet.size" );
                        String colour_option = sss_data.getPreference( http_session, "preference.stylesheet.colour_option" );
                
                        // put them back and they should be saved to DB this time
                        if ( size != null )
                            sss_data.setPreference( http_session, "preference.stylesheet.size", size ); 
                        if ( colour_option != null )
                            sss_data.setPreference( http_session, "preference.stylesheet.colour_option", colour_option ); 
		    }
		}

	    }




	    BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
	    String[] style_res_path = session.getStyleResourcePath();
	    buffer.append( "@import url(" );
	    buffer.append( req.getContextPath() );
	    buffer.append( req.getServletPath() );
	    buffer.append( "/" );
	    for ( int i=0; style_res_path!=null && i<style_res_path.length; i++ )
	    {
		buffer.append( style_res_path[i] );
		buffer.append( "/" );
	    }
	    buffer.append( "bs_virtual_author.css);\n" );

	    buffer.append( "@import url(" );
	    buffer.append( req.getContextPath() );
	    buffer.append( req.getServletPath() );
	    buffer.append( "/" );
	    for ( int i=0; style_res_path!=null && i<style_res_path.length; i++ )
	    {
		buffer.append( style_res_path[i] );
		buffer.append( "/" );
	    }
	    buffer.append( "bs_virtual_user" );
	    if ( sss_data!=null )
		buffer.append( "_" + sss_data.number_of_changes );
	    buffer.append( ".css);\n" );
		
            return buffer.toString();
	}

        
	public void sendAutoStyleSheet( Request req, HttpServletResponse res )
        throws IOException, RemoteException, BuildingServerException
	{
            org.bodington.servlet.HttpSession http_session = 
                (org.bodington.servlet.HttpSession)req.getSession( false );
            Hashtable table = (Hashtable)http_session.getAttribute( "org.bodington.user_style_sheet_auto_table" );
            if ( table == null )
            {
                table = new Hashtable();
                http_session.setAttribute( "org.bodington.user_style_sheet_auto_table", table );
            }

            String content = (String)table.get( req.getResource().getResourceId() );
            
            if ( content == null )
            {
                BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
                PrimaryKey rid = session.getStyleResourceId();
                content = (String)table.get( rid );
                if ( content == null )
                {
                    content = compileAutoStyleSheet( req, http_session );
                    table.put( rid, content );
                }
                table.put( req.getResource().getResourceId(), content );
            }

	    long last_modified = System.currentTimeMillis();
	    res.setContentType( "text/css" );
	    res.setHeader( "Cache-Control", "no-cache" );
	    res.setHeader( "Pragma", "no-cache" );
	    res.setDateHeader( "Last-Modified", last_modified ); 
	    res.setDateHeader( "Expires", last_modified );

            PrintWriter writer = new PrintWriter( res.getWriter() );
            writer.print( content );
        }
        
	
	
    public void sendProcessedGif( org.bodington.servlet.Request request, org.bodington.servlet.Response response )
    throws java.io.IOException, javax.servlet.ServletException
    {
        // this methods simply forwards to specialised servlet with appropriate query string.
        String name = request.getPageName();
        // can tell with this kind of request what type of page the GIF was
        // embedded in so make an assumption based on GIF name. 
        String html_body_class = name.startsWith( "navigation_" )?"bodington_navigation_page":"";
        String url = getTemplateGifUrl( request, html_body_class, "bs_template_" + name );
        
        // instruct client to fetch the graphic on a different URL and allow client
        // to cache this instruction for 10 seconds which should be long enough to
        // reduce hits when a page contains multiple references to the same graphic
        response.setStatus( 307, "Your browser should have forwarded you to the correct URL." );
        response.setDateHeader( "Expires", System.currentTimeMillis() + (1000*60*5) );
        response.setHeader( "Location", url );
        response.flushBuffer();
    }
	
	
	
	
	public void stylesheetField(  org.bodington.servlet.Request req, PrintWriter writer, String name )
		throws IOException, ServletException
	{
	    try
	    {
		
		org.bodington.servlet.HttpSession http_session;
		http_session = (org.bodington.servlet.HttpSession)req.getSession( false );
		if ( http_session == null )
		    return;
                StyleSheetSessionData sssd = getStyleSheetSessionData( http_session );

		NavigationSession nav_session = req.getServerNavigationSession();
		if ( nav_session == null )
		    return;

		if ( "size".equals( name ) )
		{
		    String value = sssd.getPreference( http_session, "preference.stylesheet.size" );
		    writer.println( "<select name=\"size\" size=\"2\">" );
		    writer.print( "<option " );
		    if ( "normal".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"normal\">Normal Size</option>" );
		    writer.println( "<option " );
		    if ( "big".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"big\">Big Text</option>" );
		    writer.println( "</select>" );
		}

		if ( "colour_option".equals( name ) )
		{
		    String value = sssd.getPreference( http_session, "preference.stylesheet.colour_option" );
		    writer.println( "<select name=\"colour_option\" size=\"5\">" );
		    writer.print( "<option " );
		    if ( "normal".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"normal\">Designer's colours</option>" );
		    writer.println( "<option " );
		    if ( "soft".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"soft\">Soften harsh colour contrasts</option>" );
		    writer.println( "<option " );
		    if ( "contrast".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"contrast\">Boost contrast where necessary</option>" );
		    writer.println( "<option " );
		    if ( "black".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"black\">Black on White</option>" );
		    writer.println( "<option " );
		    if ( "white".equals( value ) )
			writer.print( "selected=\"selected\" " );
		    writer.println( "value=\"white\">White on Black</option>" );
		    writer.println( "</select>" );
		}
	    }
	    catch ( BuildingServerException bsex )
	    {
		Logger.getLogger( "org.bodington" ).severe( "Unable to set stylesheet preference." );
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "stylesheetField", 
                    bsex.getMessage(), 
                    bsex );
		throw new ServletException( "Unable to display form field - technical problem." );
	    }
	}
		
        public void processStylesheetPreferences( org.bodington.servlet.Request req )
	{
	    try
	    {
		org.bodington.servlet.HttpSession http_session;
		http_session = (org.bodington.servlet.HttpSession)req.getSession( false );
		if ( http_session == null )
		    return;

		StyleSheetSessionData sss_data = this.getStyleSheetSessionData( http_session );
		
		NavigationSession nav_session = req.getServerNavigationSession();
		if ( nav_session == null )
		    return;

		String size = req.getParameter( "size" );
		String colour_option = req.getParameter( "colour_option" );

		if ( size == null && colour_option == null )
		    return;

                // store in part of http session and perhaps in database too
                if ( size != null )
                    sss_data.setPreference( http_session, "preference.stylesheet.size", size );
                if ( colour_option != null )
                    sss_data.setPreference( http_session, "preference.stylesheet.colour_option", colour_option );
		sss_data.last_changed_options = System.currentTimeMillis();
		sss_data.number_of_changes++;
                http_session.removeAttribute( "org.bodington.user_style_sheet_auto_table" );
	    }
	    catch ( Exception e )
	    {
		Logger.getLogger( "org.bodington" ).severe( "Unable to set stylesheet preference." );
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "processStylesheetPreferences", 
                    e.getMessage(), 
                    e );
	    }
        }

        public void resourcePropertyField( Request req, PrintWriter out, String name )
	throws IOException, ServletException
        {
            try
            {
                if ( name == null )
                    return;
                BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
                String val = session.getSpecifiedProperty( name );
                out.print( "<input name=\"" );
                out.print( name );
                out.print( "\" value=\"" );
                if ( val != null )
                    out.print( val );
                out.print( "\">" );
            }
            catch ( BuildingServerException bsex )
            {
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "resourcePropertyField", 
                    bsex.getMessage(), 
                    bsex );
                throw new ServletException( bsex.getMessage() );
            }
        }
        
        public void resourcePropertyConfirm( Request req, PrintWriter out, String name )
	throws IOException, ServletException
        {
            try
            {
                if ( name == null )
                    return;
                String val = req.getParameter( name );
                if ( val == null )
                    return;
                
                BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );

                if ( val == null || val.length()==0 )
                    session.unspecifyProperty( name );
                else
                    session.specifyProperty( name, val );
                out.print( "<p>Saved property.</p>" );
            }
            catch ( BuildingServerException bsex )
            {
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "resourcePropertyConfirm", 
                    bsex.getMessage(), 
                    bsex );
                throw new ServletException( bsex.getMessage() );
            }
        }
        
        public void sendMenuConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		String file = req.getParameter( "file" );
		
		PrintWriter writer = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );
		
		if ( file == null || file.length()==0 )
		    {
    		writer.println( "ERROR" );
    		writer.println( "No file was sent to the server." );
            return;    		
		    }
   		    BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
   		    if ( session==null )
   			    throw new BuildingServerException( "Unable to access the destination resource." );

    	    session.transferResourceMenu( file );
   		
   		writer.println( "OK" );
		}
		
	public void sendCreateFolderConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		String newname = req.getParameter( "folder_name" );
		
		PrintWriter writer = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );
		
		if ( newname == null || newname.length()==0 )
		    {
    		writer.println( "ERROR" );
    		writer.println( "No folder name was sent to the server." );
            return;    		
		    }

		if ( newname.length()>255 )
			{
    		writer.println( "ERROR" );
			writer.println( "Name is too long." );
			return;
			}
			
		if ( newname.indexOf( '/' ) >=0 || newname.indexOf( '\\' ) >=0 )
			{
    		writer.println( "ERROR" );
			writer.println( "Name cannot contain forward or backward slashes." );
			return;
			}
		
			
		BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		String base = fileParameter( req );
		if ( base.length()>0 && !base.endsWith( "/" ) )
		    base = base + "/";
		session.createFolder( base + newname );
		session.invalidateResourceMenu();
   		
   		writer.println( "OK" );
		}
		
	public void sendRenameConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		String newname = req.getParameter( "file_name" );
		
		PrintWriter writer = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );
		
		if ( newname == null || newname.length()==0 )
		    {
    		writer.println( "ERROR" );
    		writer.println( "No file name was sent to the server." );
            return;    		
		    }

		if ( newname.length()>255 )
			{
    		writer.println( "ERROR" );
			writer.println( "Name is too long." );
			return;
			}
			
		if ( newname.indexOf( '/' ) >=0 || newname.indexOf( '\\' ) >=0 )
			{
    		writer.println( "ERROR" );
			writer.println( "Name cannot contain forward or backward slashes." );
			return;
			}
		
			
		BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		session.renameFile( fileParameter( req ), newname );
		session.invalidateResourceMenu();
   		
   		writer.println( "OK" );
		}
		
		
	public void sendDeleteConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		PrintWriter writer = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );
		
		BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		session.deleteFile( fileParameter( req ) );
   		
   		writer.println( "OK" );
		}
		
	public void sendUndeleteConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		String recurse = req.getParameter( "recurse" );
		
		PrintWriter writer = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );
		
		BuildingSession session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		session.undeleteFile( fileParameter( req ), recurse != null && recurse.length() > 0 );
   		
   		writer.println( "OK" );
		}
		
	public void sendUploadConfirmation( Request req, HttpServletResponse res )
		throws IOException, BuildingServerException
		{
		PrintWriter out = new PrintWriter( res.getWriter() );
	    res.setContentType( "text/plain" );

		StringBuffer dest_filename=new StringBuffer();
		String file, file_name, mime_type;
		BuildingSession session;
		PrimaryKey id;
		UploadedFileSummary summary;

		file = req.getParameter( "file" );
		file_name = req.getParameterFileName( "file" );

		if ( file_name == null || file_name.length() == 0 )
			{
			out.println( "ERROR" );
			out.println( "Upload failed because no file name was supplied in the form." );
			return;
			}

		
		dest_filename.append( fileParameter( req ) );
		if ( dest_filename.length()>0 )
			dest_filename.append( "/" );
		
		
		session = BuildingSessionManagerImpl.getSession( req.getResource() );
		if ( session==null )
			throw new BuildingServerException( "Unable to access the destination resource." );

		if ( file!=null && file_name!=null )
			{
			if ( file_name.indexOf( '/' )>=0 )
				{
				out.println( "ERROR" );
				out.println( "File names may not contain any slash characters." );
				return;
				}
			dest_filename.append( file_name );

			mime_type=req.getServletConfig().getServletContext().getMimeType( file_name.toLowerCase() );
			if ( mime_type==null )
				   mime_type="application/octet-stream";

			summary = session.transferFile( file, dest_filename.toString(), mime_type );

			out.println( "OK" );

		UserFileEvent event = new UserFileEvent( 
								UserFileEvent.EVENT_UPLOAD,
								req.getResource().getResourceId(), 
								summary.getCreateUserId(), 
								null,
								new Integer( summary.getUploadedFileId().intValue() ), 
								new BigInteger( Long.toString( summary.getSize() ) ),
								file_name );
			event.save();

			session.invalidateResourceMenu();
			}
		}
		

	public void insert( Request req, PrintWriter out, String command, String insertname )
		throws ServletException, IOException
		{
		Runtime rt;

		Logger.getLogger("org.bodington").fine( getClass().getName() );
		//if ( !getClass().getName().equals( "org.bodington.servlet.facilities.Facility" ) )
		//	return "<!Error - facility insert (forgot to include insert method in facility?)>\n";


		if ( command.equalsIgnoreCase( "eatmemory" ) )
			{
			if ( bigvector==null ) bigvector=new Vector();
			bigvector.addElement( new byte[128*1024] );
			if ( out!=null )
				{
				rt=Runtime.getRuntime();
				out.println( "<PRE>Ate another 128k" );
				out.println( "Runtime Total Memory: " + rt.totalMemory() );
				out.println( "Runtime  Free Memory: " + rt.freeMemory() );
				out.println( "</PRE>" );
				}
			}

		if ( command.equalsIgnoreCase( "purgememory" ) )
			{
			bigvector=null;
			if ( out!=null )
				{
				rt=Runtime.getRuntime();
				out.println( "<PRE>Purged memory." );
				out.println( "Runtime Total Memory: " + rt.totalMemory() );
				out.println( "Runtime  Free Memory: " + rt.freeMemory() );
				out.println( "</PRE>" );
				}
			}

		if ( command.equalsIgnoreCase( "perftest" ) )
			{
			rt=Runtime.getRuntime();
			if ( out!=null )
				{
				out.println( "<PRE>Runtime Total Memory: " + rt.totalMemory() );
				out.println( "Runtime  Free Memory: " + rt.freeMemory() );
				out.print( "Start 1 million sin( rand() ): " );
				DateFormatter.outputDate( out, new java.util.Date(), 0 );
				out.println( "" );
				out.flush();
				}
			for ( int i=0; i<1000000; i++ )
				Math.cos( Math.random() );
			if ( out!=null )
				{
				out.print( "  End: " );
				DateFormatter.outputDate( out, new java.util.Date(), 0 );
				out.println( "</PRE>" );
				}
			return;
			}
		if ( command.equalsIgnoreCase( "CREATE" ) )
			{
			if ( out!=null )
				createconfirm( req, out, insertname );
			return;
			}

		if ( command.equalsIgnoreCase( "modify" ) )
			{
			if ( out!=null )
				confirmmodify( req, out );
			return;
			}
		if ( command.equalsIgnoreCase( "MOVE" ) )
			{
			if ( out!=null )
				moveconfirm( req, out );
			return;
			}
		if ( command.equalsIgnoreCase( "copy" ) )
			{
			if ( out!=null )
				copyconfirm( req, out );
			return;
			}

		if ( command.equalsIgnoreCase( "delete" ) )
			{
			if ( out!=null )
				deleteconfirm( req, out );
			return;
			}

		if ( command.equalsIgnoreCase( "VARIABLE" ) )
			{
			if ( out!=null )
				variable( req, out, insertname, false );
			return;
			}

		if ( command.equalsIgnoreCase( "VARIABLEF" ) )
			{
			if ( out!=null )
				variable( req, out, insertname, true );
			return;
			}

		if ( command.equalsIgnoreCase( "NAVIGATION" ) )
			{
			if ( out!=null )
			    {
			    navigation( req, out, insertname );
			    }
			return;
			}

		if ( command.equalsIgnoreCase( "resourcemenu" ) )
			{
			if ( out!=null )
			    {
			    resourceMenu( req, out );
				 }
			return;
			}

		if ( command.equalsIgnoreCase( "stylesheet" ) )
			{
			if ( out!=null )
				stylesheet( req, out );
			return;
			}

/*
		if ( command.equalsIgnoreCase( "NOTIFYFORM" ) )
			{
			if ( out!=null )
				notifyform( req, out );
			return;
			}
		if ( command.equalsIgnoreCase( "CONFIRMNOTIFY" ) )
			{
			if ( out!=null )
				confirmnotify( req, out );
			return;
			}
*/
		if ( command.equalsIgnoreCase( "userevent" ) )
			{
			if ( out!=null )
				userevent( req, out );
			return;
			}

		if ( command.equalsIgnoreCase( "eventlog" ) )
			{
			if ( out!=null )
				eventlog( req, out );
			return;
			}

/*
        if ( command.equalsIgnoreCase("templateeditform") )
            {
			if ( out!=null )
				templateeditform( req, out, insertname );
		    return;
            }
            

        if ( command.equalsIgnoreCase("templateeditconfirm") )
            {
			if ( out!=null )
				templateeditconfirm( req, out );
		    return;
            }
*/          

        if ( command.equalsIgnoreCase("reorder") )
            {
			if ( out!=null )
				reorder( req, out );
		    return;
            }

        if ( command.equalsIgnoreCase("reordercontrol") )
            {
			if ( out!=null )
				reordercontrol( req, out );
		    return;
            }


		if (  command.equalsIgnoreCase( "ifcanreorder" ) )
			{
			ifcanreorder( req );
			return;
			}

		if (  command.equalsIgnoreCase( "ifloggedin" ) )
			{
			ifloggedin( req );
			return;
			}

		if (  command.equalsIgnoreCase( "IFACCESS" ) )
			{
			ifaccess( req, insertname );
			return;
			}

		if (  command.equalsIgnoreCase( "ELSE" ) )
			{
			req.setSwitchedOff(  !req.isSwitchedOff() );
			return;
			}

		if (  command.equalsIgnoreCase( "ENDIF" ) )
			{
			req.setSwitchedOff( false );
			return;
			}

		if (  command.equalsIgnoreCase( "parentaclform" ) )
			{
			if ( out!=null )
				parentaclform( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "acl" ) )
			{
			if ( out!=null )
				acl( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "aclentry" ) )
			{
			if ( out!=null )
				aclentry( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "addaclentry" ) )
			{
			if ( out!=null )
				addaclentry( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "accessoperation" ) )
			{
			if ( out!=null )
				accessoperation( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "groupmenu" ) )
			{
			if ( out!=null )
				groupmenu( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "groupoperation" ) )
			{
			if ( out!=null )
				groupoperation( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "rawfileindex" ) )
			{
			if ( out!=null )
				{
				rawfileindex( req, out );
				}
			return;
			}
			
		if (  command.equalsIgnoreCase( "fileindex" ) )
			{
			if ( out!=null )
				{
				boolean show_root = req.getInsertAttribute( "root", "no" ).equalsIgnoreCase( "yes" );
				boolean hide_deleted = req.getInsertAttribute( "hidedeleted", "yes" ).equalsIgnoreCase( "yes" );
				int link_type = 0;
				if ( req.getInsertAttribute( "link", "download" ).equalsIgnoreCase( "info" ) )
					link_type=1;
				fileindex( req, out, null, show_root, hide_deleted, link_type );
				}
			return;
			}
			
		if (  command.equalsIgnoreCase( "fileinfo" ) )
			{
			if ( out!=null )
				fileinfo( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "filerename" ) )
			{
			if ( out!=null )
				filerename( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "fileisdeleted" ) )
			{
			req.setSwitchedOff(  !fileisdeleted( req ) );
			return;
			}

		if (  command.equalsIgnoreCase( "foldercreate" ) )
			{
			if ( out!=null )
				foldercreate( req, out );
			return;
			}

		if (  command.equalsIgnoreCase( "upload" ) )
			{
			if ( out!=null )
				upload( req, out, (insertname!=null && insertname.equalsIgnoreCase( "raw" ) ) );
			return;
			}
			
		if (  command.equalsIgnoreCase( "uploadzip" ) )
			{
			if ( out!=null )
				uploadzip( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "bytesuploaded" ) )
			{
			if ( out!=null )
				bytesuploaded( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "filedelete" ) )
			{
			if ( out!=null )
				filedelete( req, out, true );
			return;
			}

		if (  command.equalsIgnoreCase( "fileundelete" ) )
			{
			if ( out!=null )
				filedelete( req, out, false );
			return;
			}

		if (  command.equalsIgnoreCase( "metadata" ) )
			{
			if ( out!=null )
				metadata( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "metadataupload" ) )
			{
			if ( out!=null )
				metadataupload( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "metadatasearch" ) )
			{
			if ( out!=null )
				metadatasearch( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "importresource" ) )
			{
			if ( out!=null )
				importresource( req, out, insertname );
			return;
			}
			
		if (  command.equalsIgnoreCase( "generatemanifest" ) )
			{
			if ( out!=null )
				generatemanifest( req, out );
			return;
			}
			
			
		if (  command.equalsIgnoreCase( "zonecontrol" ) )
			{
			if ( out!=null )
				zonecontrol( req, out );
			return;
			}
			
		if (  command.equalsIgnoreCase( "zoneconfirm" ) )
			{
			if ( out!=null )
				zoneconfirm( req, out );
			return;
			}
        // uhi:awc: added insert command to return username
  		if ( command.equalsIgnoreCase( "username" ) )
			{
            if ( out!=null )
            {
                String username = getUsername(req);
                if ( username == null )
                    username = "anonymous";
                out.print( username );
            }
			return;
            }
        // uhi:awc: added insert command to return url with username appended to query - url supplied by insertname
  		if ( command.equalsIgnoreCase( "usernameloginurl" ) )
			{
            if ( out!=null )
            {
                String loginUrl = getUsernameLoginUrl(req, insertname);
                out.print( loginUrl );
            }
			return;
            }
			
                        /*
                         * WebLearn inserted code; A Corfield 02/12/2003.
                         */
                        if (command.equalsIgnoreCase("releasedate")) {
                          if (out != null)
                            releaseDate(req, out, insertname);
                          return;
                        }
                        /*
                         * WebLearn inserted code; A Corfield 02/12/2003.
                         */
                        if (  command.equalsIgnoreCase( "fileparse" ) )
                        {
//                        not yet implemented
                          if ( out!=null )
                            out.println("<CENTER><B>Sorry, parsing bodington links in html files is not yet available!</B></CENTER>");
//                            check mime type - must be html
//                            fileparse( req, out );
                          return;
                        }
		if ( out!=null )
		    out.println( "<!Unknown base facility insert>\n" );
		}

		
	private java.util.Random random = new java.util.Random();
	public boolean test( Request req, HttpServletResponse res, String op )
		throws ServletException, IOException
	{
	    //String op = req.getInsertAttribute( "command", "" );
	    if ( "random".equals( op ) )
	    {
		return random.nextBoolean();
	    }
	    
	    throw new ServletException( "Unknown test command." );
	}
	
	public void header( Request req, HttpServletResponse res )
		throws ServletException, IOException
	{
	    String op = req.getInsertAttribute( "name", "" );
	}
		

	
	public boolean isMatchingUserAgent( Request request, String regex )
	throws ServletException
	{
	    String agent = request.getHeader( "user-agent" );

	    if ( regex == null || agent == null )
		return false;
	    
	    try
	    {
		java.util.regex.Pattern p = java.util.regex.Pattern.compile( regex );
		java.util.regex.Matcher m = p.matcher( agent );
		return m.matches();
	    }
	    catch ( Exception e )
	    {
	    Logger.getLogger( "org.bodington" ).logp( 
		Level.SEVERE, 
		"Facility", 
		"isMatchingUserAgent", 
		e.getMessage(), 
		e );
	    throw new ServletException( e.getMessage() );
	    }
	    
	}
	
// Just print out the url of the original link - based on loginOriginalLink
// Weblearn: Added by Paul T 11/05/04

        public void loginOriginalLinkUrlOnly ( Request req, PrintWriter out, String label )
        {
          String original_path = loginEntryPath( req );
          out.print( original_path );
        }
// end addition by Paul T

	
	public void loginSendAuthenticationChallenge( Response response )
	{
	    response.setStatus( response.SC_UNAUTHORIZED );
	    response.setHeader( "WWW-authenticate", "Basic realm=\"Bodington Web Site\"" );
	}
	
	private String  loginEntryPath( Request request )
	{
	    // look for a form field first
	    String original_path = request.getParameter( "org_bodington_servlet_entry_path" );
	    if ( original_path!=null && original_path.length()>0 )
		return original_path;
	    
	    // then see if it is set in the session object
	    org.bodington.servlet.HttpSession session = 
		(org.bodington.servlet.HttpSession)request.getSession( false );
	    if ( session != null )
	    {
		original_path = (String)session.getAttribute( "org.bodington.servlet.entry_path" );
		if ( original_path != null )
		    return original_path;
	    }
	    
	    // otherwise use the requested URL
	    
	    StringBuffer path = new StringBuffer();
	    path.append( "http" );
	    if ( request.isSecure() )
		path.append( "s" );
	    path.append( "://" );
	    path.append( request.getServerName() );
	    if ( (request.isSecure() && request.getServerPort() != 443) || 
		 (!request.isSecure() && request.getServerPort() != 80)	       )
	    {
		path.append( ":" );
		path.append( request.getServerPort() );
	    }

	    String uri = request.getRequestURI();
	    // if someone actually tried to link to a login page 
	    // change the link to the site entrance
	    if ( uri.indexOf( "bs_template_login_" ) >=0 )
	    {
		path.append( request.getContextPath() );
		path.append( request.getServletPath() );
		path.append( "/" );
	    }
	    else
            {
		path.append( uri );
                String query = request.getQueryString();
                if ( query!=null && query.length()>0 )
                {
                    path.append( '?' );
                    path.append( query );
                }
            }
	    
	    return path.toString();
		
	}
	
	public void loginInitCookie( Request request, Response response )
	{
	    // send a cookie for a new session regardless
	    // of whether any cookie was received from user
	    // this should only be called from the first login page.

            // get a (possibly new) session
	    org.bodington.servlet.HttpSession session = (org.bodington.servlet.HttpSession)request.getSession( true );
            // make a record in it of the entry URL
	    String entry_path = loginEntryPath( request );
	    session.setAttribute( "org.bodington.servlet.entry_path", entry_path );
		
            // create a new cookie (although it may end up identical to
            // one sent a previous time.)
            Cookie session_cookie = new Cookie( Request.SESSION_ID_COOKIE_NAME, session.getId() );
            String cookie_path = request.getContextPath();
            // Mozilla and derived browsers don't like empty cookie path and will assume
            // wrongly that cookie path matches request path.  So, fix path if the Bodington
            // web app is at the root of the server
            if ( cookie_path.length() == 0 )
                cookie_path = "/";
            session_cookie.setPath( cookie_path );
	    
	    // send the cookie to the user
	    response.addCookie( session_cookie );
	    // if this cookie is returned by client it will be processed when
	    // the next page request is initialised in 
	    // org.bodington.servlet.Request.initSession
	}
	
	public boolean loginHasCookie( Request request )
	{
	    Cookie[] cookies = request.getCookies();
	    Cookie session_id_cookie = null;
	    for ( int i=0; cookies!=null && i< cookies.length; i++ )
		if ( cookies[i].getName().equals( Request.SESSION_ID_COOKIE_NAME ) )
		    session_id_cookie = cookies[i];
	    
	    return session_id_cookie != null;
	}
	
	public void loginShowPathField(  Request req, PrintWriter out )
	    throws IOException
	{
	    String original_path = loginEntryPath( req );
		
	    out.print( "<input type=\"hidden\" name=\"org_bodington_servlet_entry_path\" value=\"" );
	    if ( original_path.length()>0 )
		out.print( original_path );
	    else
	    {
		StringBuffer path = new StringBuffer();
		path.append( "http" );
		if ( req.isSecure() )
		    path.append( "s" );
		path.append( "://" );
		path.append( req.getServerName() );
		if ( (req.isSecure() && req.getServerPort() != 443) || 
		     (!req.isSecure() && req.getServerPort() != 80)	       )
		{
		    path.append( ":" );
		    path.append( req.getServerPort() );
		}

		// if someone actually tried to link to a login page or if the
		// form data was lost somehow change the link to the site entrance
		if ( req.getPageName()!=null && req.getPageName().startsWith( "login_" ) )
		{
		    path.append( req.getContextPath() );
		    path.append( req.getServletPath() );
		    path.append( "/" );
		}
		else
		    path.append( req.getRequestURI() );

		out.print( path );
	    }
	    out.println( "\">" );
	}
	
	public void loginShowFormTag( Request req, PrintWriter out, String protocol, String action )
	{
        // target="_top" ensures that following login page fills window
        // may be important if user ends up in sub frame by accident when they
        // log in.
	    out.print( "<form name=\"login\" method=\"post\" target=\"_top\" action=\"" );

	    if ( protocol!=null && protocol.equalsIgnoreCase( "https" ) )
		out.print( "https://" );
	    else
		out.print( "http://" );

	    out.print( BuildingContext.getProperty( "buildingservlet.server" ) );
	    String port;
	    if ( protocol!=null && protocol.equalsIgnoreCase( "https" ) )
	    {
		port = BuildingContext.getProperty( "buildingservlet.port.https" );
		if ( port != null && port.length()>0 && !port.equals("443") )
		{
		    out.print( ":" );
		    out.print( port );
		}
	    }
	    else
	    {
		port = BuildingContext.getProperty( "buildingservlet.port.http" );
		if ( port != null && port.length()>0 && !port.equals("80") )
		{
		    out.print( ":" );
		    out.print( port );
		}
	    }

	    out.print( BuildingContext.getProperty( "buildingservlet.secureservlet" ) );
	    if ( action!=null )
		out.print( action );
	    out.print( "\">" );
	}
	
	public boolean loginHelpRequested( Request request )
	{
	    String param = request.getParameter( "org_bodington_servlet_help" );
	    return param != null && param.length() > 0;
	}
	
	public void loginOriginalLink( Request req, PrintWriter out, String label )
	{
	    String original_path = loginEntryPath( req );
	    out.print( "<a href=\"" );
	    out.print( original_path );
	    out.print( "\">" );
	    out.print( label );
	    out.print( "</a>" );
	}

	public void loginStyleSheetPreferences( Request request )
	{
            org.bodington.servlet.HttpSession http_session = 
                (org.bodington.servlet.HttpSession)request.getSession( false );
            if ( http_session == null )
                return;
            
	    StyleSheetSessionData sss_data = this.getStyleSheetSessionData( http_session );
	    
	    String pref = request.getParameter( "org_bodington_servlet_style_sheet_pref" );
	    if ( pref == null || pref.length() == 0 )
                return;
	    String param = request.getParameter( "org_bodington_servlet_big" );
            
            if ( param != null && param.length() > 0 )
                try
                {
                    sss_data.setPreference( http_session, "preference.stylesheet.size", "big" );
                }
                catch ( Exception e )
                {
                    Logger.getLogger( "org.bodington" ).logp(
                    Level.SEVERE,
                    "Facility",
                    "loginStyleSheetPreferences",
                    e.getMessage(),
                    e );
                }
            
	    sss_data.last_changed_options = System.currentTimeMillis();
	    sss_data.number_of_changes++;
            http_session.removeAttribute( "org.bodington.user_style_sheet_auto_table" );
        }
	
     /**
     * Uses http url connection to external application for logout
     * uhi:awc
     * @param out The PrintWriter.
     * @param logoutUrl The url of external application for logout.
     */
	public void externalLogout( PrintWriter out, String logoutUrl )
	{
        int response = 0;
	    try
	    {
        URL url = new URL(logoutUrl);
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        response = connection.getResponseCode();
        //uhi:awc log response if not successful
        }
	    catch ( Exception e )
	    {
		Logger.getLogger( "org.bodington" ).logp(
		Level.INFO,
		"Facility",
		"logout",
		"External logout failed (URL: " + logoutUrl + " response: " + response + ") " + e.getMessage(),
		e );
	    }
    }

	public void logout( Request req, PrintWriter out )
	{
	    try
	    {
		NavigationSession nav_session = req.getServerNavigationSession();
		if ( nav_session == null )
		    return;
		
		nav_session.clearAuthenticationCredentials();
		// This should clear up the HttpSession and prevent preferences
		// crossing sessions.
		// XXX: Check that this really is sensible
	    org.bodington.servlet.HttpSession session = (org.bodington.servlet.HttpSession)req.getSession( false );
	    if (session != null)
	        session.invalidate();
	    
	    }
	    catch ( Exception e )
	    {
		if ( out != null )
		    out.print( "<p>It was not possible to log you out for technical reasons.</p>" );
		Logger.getLogger( "org.bodington" ).logp(
		Level.SEVERE,
		"Facility",
		"logout",
		e.getMessage(),
		e );
	    }
	    
	}
	
	
	private void parentaclform( Request breq, PrintWriter out )
		throws IOException
		{
		boolean is_owners, is_local;
		String name;
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't control access.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
		    {
			out.println( "<HR>You need manage access to control access for others.<HR>" );
			return;
		    }


        out.println( "<table CLASS=bs-table-opaque>" );

        try
            {
		    Resource resource = breq.getResource();

		    out.print( "<TR><TD CLASS=bs-cell-special><FORM NAME=parentaclform method=post ACTION=bs_template_access.html>" );
		    out.print( "<input type=hidden name=operation value=parentacl>" );
			out.print( "<INPUT TYPE=CHECKBOX NAME=parentacl VALUE=yes" );
		    if ( resource.getUseParentAcl() )
		    	out.print( " CHECKED" );
		    out.println( " ONCLICK=\"forms.parentaclform.submit()\">Access controlled by containing location " );
		    out.println( "<FONT SIZE=-1><NOBR>(Click for immediate change.)</NOBR></FORM></TD></TR>" );
		    }
		catch ( Exception ex )
		    {
		    out.println( "<PRE>" + ex + "</PRE>" );
		    return;
		    }
	    out.println( "</TABLE>" );

		}
		

	private void acl( Request breq, PrintWriter out )
		throws IOException
		{
		boolean is_owners, is_local;
		String name;
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't control access.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
		    {
			out.println( "<HR>You need manage access to control access for others.<HR>" );
			return;
		    }


        out.println( "<table border=1>" );
        out.println( "<tr>" );
        out.println( "<td><table CLASS=bs-table-acl border=0 cellpadding=4 cellspacing=0 bordercolor=#C0C0C0 bordercolordark=#808080 bordercolorlight=#FFFFFF>" );
        out.println( "<tr>" );
        out.println( "<td align=center valign=top><h3><strong>Add/<br>" );
        out.println( "Remove</strong></h3>" );
        out.println( "</td>" );
        out.println( "<td align=center valign=top><h3><strong>Group" );
        out.println( "<br>" );
        out.println( "Name</strong></h3>" );
        out.println( "</td>" );
        out.println( "<td align=center valign=top><h3><strong>Access" );
        out.println( "<br>" );
        out.println( "Rights</strong></h3>" );
        out.println( "</td>" );
        out.println( "<td align=center valign=top><h3><strong>Change<br>" );
        out.println( "Access</strong></h3>" );
        out.println( "</td>" );
        out.println( "</tr>" );

        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    //out.println( "<PRE>" + acl.toString() );
		    Enumeration enum = acl.entries();
		    AclEntry aclentry;
		    StringTokenizer tok;
		    while ( enum.hasMoreElements() )
		        {
		        aclentry = (AclEntry)enum.nextElement();
                name=aclentry.getGroup().getName();
                is_owners =  name.equals( "localgroup." + resource.getResourceId() + ".owners" );
                is_local =  name.startsWith( "localgroup." );

		        
                out.println( "<tr>" );
                if ( is_owners )
                    out.println( "<td valign=top>&nbsp;</td>");
                else
                    {
                    out.print( "<td valign=top align=right>" );
                    out.print( "<form method=post ACTION=bs_template_access.html>" );
                    out.print( "<input type=hidden name=operation value=accessremove>" );
                    out.print( "<input type=hidden name=group_id value=" );
                    out.print( aclentry.getGroup().getGroupId().toString() );
                    out.println( "><INPUT TYPE=SUBMIT VALUE=\" - \"></FORM></FONT></TD>" );
                    }
                out.println( "<td align=right valign=top><table CLASS=bs-table-opaque>" );
                out.println( "<tr>" );
                out.print( "<td valign=top><strong>" );
                if ( is_local )
                    out.print( name.substring( name.lastIndexOf('.') +1 ) );
                else
                    out.print( name );
                out.print( "</strong><br>" );
                out.print( aclentry.getGroup().getDescription() );
                out.println( "<br>" );
                out.print( "<font size=2><form method=post ACTION=bs_template_accessgroup.html target=groupwindow>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( aclentry.getGroup().getGroupId().toString() );
                out.println( "><INPUT TYPE=SUBMIT VALUE=\" Membership \" ONCLICK=\"grpwin()\"></FORM>" );
                //out.println( "<a href=membership.html><font size=2><em><strong>Membership</strong></em></font></a></td>" );
                out.println( "</font></a></td>" );
                out.println( "</tr>" );
                out.println( "</table>" );
                out.println( "</td>" );
                out.println( "<td valign=top><table CLASS=bs-table-opaque>" );
                out.println( "<tr>" );
                out.print( "<td valign=top><strong>");
                tok= new StringTokenizer( aclentry.getPermissionCoded(), "+-," );
                while ( tok.hasMoreTokens() )
                	{
                	out.print( tok.nextToken() );
                	out.print( " " );
                	}
                out.println( "</strong></td>" );
                out.println( "</tr>" );
                out.println( "</table>" );
                out.println( "</td>" );
                out.println( "<td valign=top>" );
                out.println( "<font size=2><FORM METHOD=POST ACTION=bs_template_accesschange.html>" );
                out.print( "<INPUT TYPE=HIDDEN NAME=group_id VALUE=" );
                out.print( aclentry.getGroup().getGroupId().toString() );
                out.print( "><INPUT TYPE=SUBMIT VALUE=\" * \"></FORM></FONT>" );
                //out.print( "<a href=page/" );
                //out.print( aclentry.getGroup().getName() );
                //out.print( "/" );
                //out.print( "accesschange.html" );
                //out.println( "><font size=2><em><strong>Change</strong></em></font></a>" );
                out.println( "</td></tr>" );
		        
		        
		        //out.println( aclentry.getGroup().getName() + " = " + aclentry.getPermissionCoded() );
		        }
		    }
		catch ( Exception ex )
		    {
		    out.println( "<PRE>" + ex + "</PRE>" );
		    return;
		    }

        out.println( "<tr>" );
        out.println( "<td valign=top align=right><font size=2>" );
        out.print( "<form method=post ACTION=\"*/bs_template_accessadd.html\">" );
        out.println( "<INPUT TYPE=SUBMIT VALUE=\" + \"></FORM></FONT></TD>" );
        out.println( "<td align=right valign=top><font size=2>You can list more groups here.</FONT></td>" );
        out.println( "<td valign=top>&nbsp;</td>" );
        out.println( "<td valign=top>&nbsp;</td>" );
        out.println( "</tr>" );
        out.println( "</table>" );
        out.println( "</td>" );
        out.println( "</tr>" );
        out.println( "</table>" );

		}
		

	private void aclentry( Request breq, PrintWriter out )
		throws IOException
		{
		boolean is_owners, is_local;
		String g, name;
		PrimaryKey group_id;
		
        g=breq.getParameter( "group_id" );
        if ( g==null )
			{
			out.println( "Problem: no group_id was specified." );
			return;
			}
		try
		    {
		    group_id = new PrimaryKey( Integer.parseInt( g ) );
		    }
		catch ( NumberFormatException nfex )
		    {
			out.println( "Problem: invalid group_id was specified." );
			return;
		    }
		    
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
		    {
			out.println( "<HR>You need manage access rights to view access rights.<HR>" );
			return;
		    }

        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    //out.println( "<PRE>" + acl.toString() );
		    //Enumeration enum = acl.entries();
		    AclEntry aclentry;
            out.println( "<input type=hidden name=operation value=accesschange>" );
            out.print( "<input type=hidden name=group_id value=" );
            out.print( group_id.toString() ) ;
            out.println( " >" );
            aclentry=acl.getAclEntry( group_id, false );
            if ( aclentry==null )
                {
                out.println( "The selected access control entry no longer exists." );
                return;
                }
            name=aclentry.getGroup().getName();
            is_owners =  name.equals( "localgroup." + resource.getResourceId() + ".owners" );
            is_local =  name.startsWith( "localgroup." );
            out.println( "<TR>" );
            out.println( "<td valign=top align=center><strong>" );
            if ( is_local )
                out.print( name.substring( name.lastIndexOf('.') +1 ) );
            else
                out.print( name );
            out.println( "</strong></td>" );
            out.println( "<td valign=top>" );
            out.print( aclentry.getGroup().getDescription() );
            out.println( "</td>" );
            out.println( "<td>" );
            if ( is_owners )
                {
                out.print( "<P>You cannot remove <B>see</B>, <B>view</B> or <B>manage</B> access from the owners group.</P>" );
                }
                
            Enumeration enum = Permission.permissions();
            Permission p;
            boolean first=true;
            while ( enum.hasMoreElements() )
                {
                p = (Permission)enum.nextElement();
                if ( is_owners && ( p.equals( Permission.SEE ) || 
                                    p.equals( Permission.VIEW ) || 
                                    p.equals( Permission.MANAGE ) ) )
                    continue;
                if ( p.equals( Permission.ADMINISTER ) || p.equals( Permission.SYSADMIN ) )
                    {
                    if ( !resource.checkPermission( Permission.SYSADMIN ) )
                        continue;
                    }
                if ( !first ) out.println( "<BR>" );
                first=false;
                out.print( "<input type=checkbox " );
                if ( aclentry.checkPermission( p ) )
                    out.print( "checked " );
                out.print( "name=" );
                out.print( p.toString() );
                out.print( " value=on>" );
                out.print( "<em><strong>" );
                out.print( p.toString() );
                out.println( "</strong></em>" );
                }
                
            out.println( "</td></tr>" );
                
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( "<PRE>" + ex + "</PRE>" );
		    return;
		    }

		}

	
	private void addaclentry( Request breq, PrintWriter out )
		throws IOException
		{
		boolean is_owners;
		String g, gname;
		PrimaryKey group_id;
		org.bodington.server.realm.Group group;
		int i;
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
		    {
			out.println( "<HR>You need manage access rights to view access rights.<HR>" );
			return;
		    }

		String base=null;
		if ( breq.getTemplateParameterCount()>0 )
			{
			base = (String)breq.getTemplateParameter( 0 );
			if ( !base.endsWith( "*" ) )
				base = null;
			else
				base = base.substring( 0, base.length()-1 );
			}

        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    //out.println( "<PRE>" + acl.toString() );
		    //Enumeration enum = acl.entries();
		    AclEntry aclentry;
		    
		    Vector groups = new Vector();
		    Vector headings = new Vector();

		    Enumeration enum;
		    if ( base==null || base.length()==0 )
		   	{
		   	enum = org.bodington.server.realm.Group.findGroups( 
		    								"name LIKE 'localgroup." + 
		    								resource.getResourceId() +
		    								".%'", "name" );
		   	while ( enum.hasMoreElements() )
		      	groups.addElement( enum.nextElement() );
		      }
		      
		    if ( base==null  || base.length()==0 )
		   	enum = org.bodington.server.realm.Group.findGroups( "name NOT LIKE 'localgroup.%'", "name" );
		   else
	   		enum = org.bodington.server.realm.Group.findGroups( "name LIKE '" + base + "%'", "name" );
	   
		   String name;
		   int dot_offset;
		    while ( enum.hasMoreElements() )
		   	{
		   	if ( base==null )
		        groups.addElement( enum.nextElement() );
		      else
		      	{
		      	group = (org.bodington.server.realm.Group)enum.nextElement();
		      	name = group.getName();
		      	if ( !name.startsWith( base ) )
		      		continue;
		      	dot_offset = name.indexOf( '.', base.length() );
		      	if ( dot_offset < 0 || (base.length()==0 && name.startsWith( "localgroup." ) ) )
		      		groups.addElement( group );
		      	else
		      		{
		      		name = base+name.substring( base.length(), dot_offset )+".*";
		      		if ( !headings.contains( name ) )
		      			headings.addElement( name );
		      		}
		      	}
		      }

		        
         out.print( "<form name=selectorform method=POST ACTION=\"" );
         out.print( breq.absoluteURL() );
         out.println( "bs_template_access.html\">" );
         out.println( "<TR>" );

     		out.println( "<TD valign=top align=center>" );
			if ( base!=null )
				{
           	out.print( "<INPUT TYPE=HIDDEN NAME=category_url VALUE=\"" );
           	out.print( breq.absoluteURL() );
           	out.print( "\"><INPUT TYPE=HIDDEN NAME=category_page VALUE=\"bs_template_" );
           	out.print( breq.getPageName() );
           	out.println( "\">" );
           	out.println( "<SELECT NAME=category size=10 onchange=\"browse()\">" );
           	if ( base.length() > 0 )
           		{
	      		out.print( "<OPTION VALUE=\"*\">*</OPTION>" );
	      		}
      		out.print( "<OPTION SELECTED VALUE=\"" );
      		out.print( base );
      		out.println( "*\">" );
      		out.print( base );
      		out.print( "*" );
      		out.println( "</OPTION>" );
		   	for ( i=0; i<headings.size(); i++ )
		      	{
		      	out.print( "<OPTION VALUE=\"" );
            	out.print( headings.elementAt( i ).toString() );
		      	out.print( "\">" );
            	out.print( headings.elementAt( i ).toString() );
            	out.println( "</OPTION>" );
					}              
        		out.println( "</SELECT>" );
           	}
      	else
      		out.println( "<I>All categories</I>" );
       	out.println( "</TD>" );

         out.println( "<td valign=top align=left>" );
         out.println( "<INPUT TYPE=HIDDEN NAME=operation VALUE=accessadd>" );
         out.println( "<SELECT NAME=group_id size=7 onchange=\"setdescription()\">" );
		    
		    for ( i=0; i<groups.size(); i++ )
		        {
		        group = (org.bodington.server.realm.Group)groups.elementAt( i );
		        //don't list group if current user hasn't got see access to it.
		        if ( !group.checkPermission( Permission.SEE ) )
		        	continue;
                aclentry=acl.getAclEntry( group.getGroupId(), false );
                //don't list group if it is in acl already
                if ( aclentry!=null )
                    continue;
		        out.print( "<OPTION VALUE=\"" );
		        out.print( group.getGroupId().toString() );
		        out.print( "\">" );
		        gname = group.getName();
		        if ( gname.startsWith( "localgroup." ) )
		        	out.print( gname.substring( gname.lastIndexOf( '.' )+1 ) );
		        else
		        	out.print( gname );
		        out.println( "</OPTION>" );
		        }
		    out.println( "</SELECT>" );
		    
		    out.print( "<BR>Description:<BR><SPAN CLASS=bs-textarea><TEXTAREA NAME=description rows=4 cols=25 wrap=HARD>" );
		    out.println( "Select a group to see its description.</TEXTAREA></SPAN></TD><TD>" );

            enum = Permission.permissions();
            Permission p;
            boolean first=true;
            while ( enum.hasMoreElements() )
                {
                p = (Permission)enum.nextElement();
                if ( p.equals( Permission.ADMINISTER ) || p.equals( Permission.SYSADMIN ) )
                    {
                    if ( !resource.checkPermission( Permission.SYSADMIN ) )
                        continue;
                    }
                if ( !first ) out.println( "<BR>" );
                first=false;
                out.print( "<input type=checkbox " );
                out.print( "name=" );
                out.print( p.toString() );
                out.print( " value=on>" );
                out.print( "<em><strong>" );
                out.print( p.toString() );
                out.println( "</strong></em>" );
                }

                        
                
            out.println( "</td></tr><TR><TD COLSPAN=2 VALIGN=CENTER ALIGN=CENTER>" );
            out.println( "<INPUT TYPE=SUBMIT VALUE=\"Add Selected Group\"></TD></form>" );
				out.print( "<TD VALIGN=CENTER ALIGN=CENTER><form method=POST ACTION=\"" );
				out.print( breq.absoluteURL() );
				out.print( "bs_template_access.html\"><INPUT TYPE=HIDDEN NAME=operation VALUE=noop><input type=SUBMIT value=\"Cancel\"></FORM>" );
				out.println( "<form name=describeform></TD></TR>" );
                
		    for ( i=0; i<groups.size(); i++ )
		        {
		        group = (org.bodington.server.realm.Group)groups.elementAt( i );
                aclentry=acl.getAclEntry( group.getGroupId(), false );
                if ( aclentry!=null )
                    {
                    continue;
                    }
		        out.print( "<INPUT TYPE=HIDDEN NAME=\"desc" );
		        out.print( group.getGroupId().toString() );
		        out.print( "\" Value=\"" );
                out.print( group.getDescription() );
		        out.println( "\">" );
		        }
            out.println( "</FORM>" );
            
		    for ( i=0; i<headings.size(); i++ )
		        {
		        out.print( "<!-- " );
		        out.print( headings.elementAt( i ).toString() );
		        out.println( " -->" );
         	  }
            
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( "<PRE>" + ex + "</PRE>" );
		    return;
		    }

		}

	
	private void accessoperation( Request breq, PrintWriter out )
		throws IOException
		{
        String op=breq.getParameter( "operation" );
        if ( op==null ) return;
        op=op.trim();
        if ( op.length()==0 ) return;
        
        if ( op.equalsIgnoreCase( "parentacl" ) )
        	{
            out.println( "<table CLASS=bs-table-opaque>" );
            out.println( "<tr><td align=center valign=top CLASS=bs-cell-special>" );
            out.println( "<FONT COLOR=RED>Change to use of containing location: " );
            
            String str = breq.getParameter( "parentacl" );
            try
            	{
            	breq.getResource().setUseParentAcl( str!=null && str.equalsIgnoreCase( "yes" ) );
            	breq.getResource().save();
            	out.println( "CONFIRMED" );
            	}
            catch ( BuildingServerException bsex )
            	{
            	out.println( "Technical problem trying to save option change: " + bsex.toString() );
            	}
            
            out.println( ".</FONT></TD></TR></TABLE>" );
            return;
        	}

        if ( op.equalsIgnoreCase( "accessadd" ) ||
             op.equalsIgnoreCase( "accesschange" ) ||
             op.equalsIgnoreCase( "accessremove" ) )
            {
            String g;
            PrimaryKey group_id;
            
            out.println( "<table CLASS=bs-table-opaque>" );
            out.println( "<tr><td align=center valign=top CLASS=bs-cell-special>" );
            out.println( "<FONT COLOR=RED>" );
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( " Problem: no group_id was specified.</FONT></TD></TR></TABLE>>" );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified.</FONT></TD></TR></TABLE>" );
			    return;
		        }
            if ( op.equalsIgnoreCase( "accessadd" ) )
	    	    aclentryadd( breq, out, group_id );
            if ( op.equalsIgnoreCase( "accesschange" ) )
	    	    aclentrychange( breq, out, group_id );
            if ( op.equalsIgnoreCase( "accessremove" ) )
	    	    aclentryremove( breq, out, group_id );
            return;
            }
		}
		
	private void aclentryadd( Request breq, PrintWriter out, PrimaryKey group_id )
		throws IOException
		{
		boolean is_owners;
		String box;

        out.println( "Access Change: " );
		
        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    org.bodington.server.realm.Group group = org.bodington.server.realm.Group.findGroup( group_id );
		    //out.println( "<PRE>" + acl.toString() );
		    AclEntry aclentry;
            aclentry=new AclEntry();
            aclentry.setPrincipal( group );

            Enumeration enum = Permission.permissions();
            Permission p;
            while ( enum.hasMoreElements() )
                {
                p = (Permission)enum.nextElement();
                if ( p.equals( Permission.ADMINISTER ) || p.equals( Permission.SYSADMIN ) )
                    {
                    if ( !resource.checkPermission( Permission.SYSADMIN ) )
                        continue;
                    }
                box = breq.getParameter( p.toString() );
                if ( box!=null && box.equals( "on" ) )
                    aclentry.addPermission( p );
                }
                    
            acl.addEntry( aclentry );
            acl.save();
            out.println( " CONFIRMED.</FONT></TD></TR></TABLE>" );
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( " Problem: <PRE>" + ex + "</PRE></FONT></TD></TR></TABLE>" );
		    return;
		    }
		}
		
	private void aclentrychange( Request breq, PrintWriter out, PrimaryKey group_id )
		throws IOException
		{
		boolean is_owners;
		String box;

        out.println( "Access Change: " );
		
        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    //out.println( "<PRE>" + acl.toString() );
		    AclEntry aclentry;
            aclentry=acl.getAclEntry( group_id, false );
            if ( aclentry==null )
                {
                out.println( "The selected access control entry no longer exists." );
                return;
                }
            is_owners =  aclentry.getGroup().getName().equals( 
                                "localgroup." + resource.getResourceId() + ".owners" );

            Enumeration enum = Permission.permissions();
            Permission p;
            while ( enum.hasMoreElements() )
                {
                p = (Permission)enum.nextElement();
                if ( is_owners && ( p.equals( Permission.SEE ) || 
                                    p.equals( Permission.VIEW ) || 
                                    p.equals( Permission.MANAGE ) ) )
                    continue;
                if ( p.equals( Permission.ADMINISTER ) || p.equals( Permission.SYSADMIN ) )
                    {
                    if ( !resource.checkPermission( Permission.SYSADMIN ) )
                        continue;
                    }
                box = breq.getParameter( p.toString() );
                if ( box!=null && box.equals( "on" ) )
                    aclentry.addPermission( p );
                else
                    aclentry.removePermission( p );
                }

                    
            aclentry.save();
            out.println( " CONFIRMED.</FONT></TD></TR></TABLE>" );
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( " Problem: <PRE>" + ex + "</PRE></FONT></TD></TR></TABLE>" );
		    return;
		    }
		}
		
	private void aclentryremove( Request breq, PrintWriter out, PrimaryKey group_id )
		throws IOException
		{
		boolean is_owners;
		String box;

        out.println( "Remove access : " );
		
        try
            {
		    Resource resource = breq.getResource();
		    org.bodington.server.realm.Acl acl = resource.getAcl();
		    //out.println( "<PRE>" + acl.toString() );
		    AclEntry aclentry;
            aclentry=acl.getAclEntry( group_id, false );
            if ( aclentry==null )
                {
                out.println( "The selected access control entry no longer exists.</FONT></TD></TR></TABLE>" );
                return;
                }
            is_owners =  aclentry.getGroup().getName().equals( 
                                "localgroup." + resource.getResourceId() + ".owners" );

            if ( is_owners )
                {
                out.println( "You can't remove the owners group from the access control.</FONT></TD></TR></TABLE>" );
                return;
                }

            acl.removeEntry( aclentry );
            acl.save();
                
            out.println( " CONFIRMED.</FONT></TD></TR></TABLE>" );
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( " Problem: <PRE>" + ex + "</PRE></FONT></TD></TR></TABLE>" );
		    return;
		    }
		}
		

	private void groupmenu( Request breq, PrintWriter out )
		throws IOException
		{
		boolean is_owners, is_local;
		String g, name, gname;
		PrimaryKey group_id;
		org.bodington.server.realm.Group group;
		
        g=breq.getParameter( "group_id" );
        if ( g==null )
			{
			out.println( "Problem: no group_id was specified." );
			return;
			}
		try
		    {
		    group_id = new PrimaryKey( Integer.parseInt( g ) );
		    }
		catch ( NumberFormatException nfex )
		    {
			out.println( "Problem: invalid group_id was specified." );
			return;
		    }
		    
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't work with this group.<HR>" );
			return;
			}
		
        try
            {
            group = org.bodington.server.realm.Group.findGroup( group_id );
            if ( group==null )
			    {
			    out.println( "Problem: the specified group wasn't found." );
			    return;
			    }

			//There will be more access checking on the groups when
			//the user tries to edit them.
            if ( !group.checkPermission( Permission.forName( "see" ) ) )
		    	{
				out.println( "<HR>You lack the see access right for this group.<HR>" );
				return;
		    	}


            out.println( "<table CLASS=bs-table-opaque>" );
            out.println( "<tr>" );
            out.println( "<td CLASS=bs-cell-special><strong>Name</strong></td>" );
            out.println( "<td CLASS=bs-cell-special><strong>Description</strong></td>" );
            out.println( "<td CLASS=bs-cell-special><strong>Access Rights</strong></td>" );
            out.println( "</tr>" );
            out.println( "<tr>" );
            out.print( "<td valign=\"top\"><strong>" );
		    gname = group.getName();
		    if ( gname.startsWith( "localgroup." ) )
		        out.print( gname.substring( gname.lastIndexOf( '.' )+1 ) );
		    else
		        out.print( gname );
            out.println( "</strong></td>" );
            out.print( "<td valign=\"top\">" );
            out.print( group.getDescription() );
            out.println( "</td>" );
            out.println( "<td valign=\"top\">You can select the  " );
            out.println( "group in your access control lists" );
            if ( group.checkPermission( Permission.forName( "view" ) ) )
                out.println( ", list membership of the group" );
            if ( group.checkPermission( Permission.forName( "edit" ) ) )
                out.println( ", edit membership of the group" );
            if ( group.checkPermission( Permission.forName( "manage" ) ) )
                out.println( ", control the rights of others to access the group" );
            out.println( ".</td></tr>" );

            out.println( "<tr>" );
            out.println( "<td colspan=\"3\"><div align=\"center\"><center>" );
            out.println( "<table border=\"0\"><tr>" );
            
            out.println( "<td>" );
            if ( group.checkPermission( Permission.forName( "view" ) ) )
                {
                out.println( "<form method=POST ACTION=bs_template_accessgroup.html>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                //search in current group for users to remove
                out.print( "<input type=hidden name=search_group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=list>" );
                out.println( "<INPUT TYPE=hidden NAME=in_zone VALUE=zone_any>" );
                out.println( "<input type=hidden name=identifier value=user_id>" );
                out.println( "<input type=hidden name=values value=\"*\">" );
                
                out.println( "<input type=submit value=\"List Members\">" );
                out.println( "</form>" );
                }
            out.println( "</td>" );
            
            out.println( "<td>" );
            if ( group.checkPermission( Permission.forName( "edit" ) ) )
                {
                out.println( "<form method=POST ACTION=bs_template_accessgroup.html>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=addform>" );
                out.println( "<input type=submit value=\"Add Members\">" );
                out.println( "</form>" );
                }
            out.println( "</td>" );
            
            out.println( "<td>" );
            if ( group.checkPermission( Permission.forName( "edit" ) ) )
                {
                out.println( "<form method=POST ACTION=bs_template_accessgroup.html>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                //search in current group for users to remove
                out.print( "<input type=hidden name=search_group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=remove>" );
                out.println( "<INPUT TYPE=hidden NAME=in_zone VALUE=zone_any>" );
                out.println( "<input type=hidden name=identifier value=user_id>" );
                out.println( "<input type=hidden name=values value=\"*\">" );
                
                out.println( "<input type=submit value=\"Remove Members\">" );
                out.println( "</form>" );
                }
            out.println( "</td>" );
            out.println( "<td><FORM><INPUT TYPE=BUTTON VALUE=\"Close\" ONCLICK=\"closeme()\"></FORM></TD>" );
/*            
            out.println( "<td>" );
            if ( group.checkPermission( Permission.forName( "manage" ) ) )
                {
                out.println( "<form>" );
                out.println( "<input type=button value = \"Change Access to Group\" onclick=\"alert( 'This button is not yet functional.' )\">" );
                out.println( "</form>" );
                }
            else
                out.println( "&nb;" );
            out.println( "</td>" );
*/
            out.println( "</tr></table></center></div></td></tr></table>" );

                
            return;
		    }
		catch ( Exception ex )
		    {
		    out.println( "<PRE>" + ex + "</PRE>" );
		    return;
		    }

		}


	private void groupoperation( Request breq, PrintWriter out )
		throws IOException
		{
		int i;
		Integer temp_int;
        String op=breq.getParameter( "operation" );
        if ( op==null ) return;
        op=op.trim();
        if ( op.length()==0 ) return;

        if ( op.equalsIgnoreCase( "noop" ) )
            {
            return;
            }

		out.println( "<P>Please wait for the selected operation to complete before you " );
		out.println( "select further operations or navigate away from this window.</P>" );
		out.flush();

        if ( op.equalsIgnoreCase( "list" ) )
            {
            String g;
		    PrimaryKey group_id;
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }		    
            out.println( "<h4><strong>Users in this Group</strong></h4>" );
            
            listusers( breq, out, false );
            return;
            
            /*
            String g;
		    PrimaryKey group_id;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User user;
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
    		    
		    if ( !breq.isAuthenticated() )
			    {
			    out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			    return;
			    }
    		

            try
                {
                group = org.bodington.server.realm.Group.findGroup( group_id );
                if ( group==null )
			        {
			        out.println( "Problem: the specified group wasn't found." );
			        return;
			        }
		        if ( !group.checkPermission( Permission.VIEW ) )
		            {
			        out.println( "<HR>You need view access rights to the selected group to list membership.<HR>" );
			        return;
		            }
			        
			    StringBuffer where_clause=new StringBuffer();
			    Integer special = group.getSpecialGroup();
			    if ( special == null )
			    	{
				    where_clause.append( "user_id IN (SELECT user_id FROM members where group_id = " );
			    	where_clause.append( group_id.toString() );
			    	where_clause.append( " ) " );
			    	}
			    else
			    	{
				    int mask, s = special.intValue();
				    mask = 1 << (s & 0x1f);
	    			switch ( s & 0x60 )
	        			{
	        			case 0x00:
						    where_clause.append( "(special_groups_a & (" );
	            			break;
	        			case 0x20:
						    where_clause.append( "(special_groups_b & (" );
	            			break;
	        			case 0x40:
						    where_clause.append( "(special_groups_c & (" );
	            			break;
	        			case 0x60:
						    where_clause.append( "(special_groups_d & (" );
	        			}
			    	
				    where_clause.append( Integer.toString( mask ) );
			    	where_clause.append( ") ) <> 0" );
			    	}
			    
			    Enumeration enum=org.bodington.server.realm.User.findUsers( where_clause.toString(), "surname, initials" );
			    
                out.println( "<BR><table CLASS=bs-table-opaque><tr>" );
                out.println( "<td COLSPAN=2 CLASS=bs-cell-special><strong>Users in Group</TD></tr>" );
			    while ( enum.hasMoreElements() )
			        {
			        out.println( "<tr><TD>" );
			        user = (org.bodington.server.realm.User)enum.nextElement();
			        out.println( user.getName() );
			        out.println( "</TD></TR>" );
			        }
			    out.println( "</TABLE>" );
			    }
		    catch ( Exception ex )
		        {
		        out.println( "<PRE>" + ex + "</PRE>" );
		        return;
		        }

            return;
            */
            }

        
        if ( op.equalsIgnoreCase( "remove" ) )
            {
            String g;
		    PrimaryKey group_id;
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }		    
		    out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
            out.print( "<input type=hidden name=group_id value=" );
            out.print( group_id.toString() ) ;
            out.println( " >" );
            out.println( "<INPUT type=hidden name=operation value=removeconfirm>" );
            out.println( "<h4><strong>Confirm Removal of Users</strong></h4>" );
            
            listusers( breq, out, false );
            out.println( "</form>" );
            return;
            
            /*
		    String g;
		    PrimaryKey group_id;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User current_user;
		    org.bodington.server.realm.User user;
    		
    		current_user=(org.bodington.server.realm.User)BuildingContext.getContext().getUser();
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
    		    
		    if ( !breq.isAuthenticated() )
			    {
			    out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			    return;
			    }
    		
            try
                {
                group = org.bodington.server.realm.Group.findGroup( group_id );
                if ( group==null )
			        {
			        out.println( "Problem: the specified group wasn't found." );
			        return;
			        }
		        if ( !group.checkPermission( Permission.EDIT ) )
		            {
			        out.println( "<HR>You need edit access rights to the selected group to edit membership.<HR>" );
			        return;
		            }
			    Integer special = group.getSpecialGroup();
			    if ( special != null )
			        {
			        out.println( "This is a special group and you can't remove users." );
			        return;
			        }
			        
			    StringBuffer where_clause=
			            new StringBuffer( "user_id IN (SELECT user_id FROM members where group_id = " );
			    where_clause.append( group_id.toString() );
			    where_clause.append( " ) " );
			    Enumeration enum=org.bodington.server.realm.User.findUsers( where_clause.toString(), "surname, initials" );
			    
		        out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=removeconfirm>" );
                out.println( "<table CLASS=bs-table-opaque><tr>" );
                out.println( "<td COLSPAN=2 CLASS=bs-cell-special><strong>Users to Remove</TD></tr>"	);
                out.println( "<tr><td colspan=2><INPUT TYPE=SUBMIT VALUE=\"Remove selected users\">"	);
                out.println( "<INPUT TYPE=button VALUE = \"Select All\" ONCLICK=\"checkall(true)\">"	);
                out.println( "<INPUT TYPE=button VALUE = \"Unselect All\" ONCLICK=\"checkall(false)\">" );
                out.println( "</td></tr>" );
			    while ( enum.hasMoreElements() )
			        {
			        user = (org.bodington.server.realm.User)enum.nextElement();
			        out.println( "<TR><TD>" );
			        out.println( user.getName() );
			        out.println( "</TD><TD>" );
			        if ( group.getName().endsWith( ".owners" ) && user.equals( current_user ) )
			        	out.println( "<I>Can't remove self</I>" );
			    	else
			    		{
    	            	out.print( "<INPUT NAME=\"user_id_" );
		            	out.print( user.getUserId().toString() );
		            	out.println( "\" TYPE=CHECKBOX VALUE=On>" );
		            	}
		        	out.println( "</TD></TR>" );
			        }
			    out.println( "</TABLE></FORM>" );
			    }
		    catch ( Exception ex )
		        {
		        out.println( "<PRE>" + ex + "</PRE>" );
		        return;
		        }

            return;
*/
            }


        if ( op.equalsIgnoreCase( "removeconfirm" ) )
            {
		    String g;
		    PrimaryKey group_id;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User user;
		    org.bodington.server.realm.User current_user;
    		
    		current_user=(org.bodington.server.realm.User)BuildingContext.getContext().getUser();
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
    		    
		    if ( !breq.isAuthenticated() )
			    {
			    out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			    return;
			    }
    		
            try
                {
                group = org.bodington.server.realm.Group.findGroup( group_id );
                if ( group==null )
			        {
			        out.println( "Problem: the specified group wasn't found." );
			        return;
			        }
		        if ( !group.checkPermission( Permission.EDIT ) )
		            {
			        out.println( "<HR>You need edit access rights to the selected group to edit membership.<HR>" );
			        return;
		            }
			    Enumeration plist = breq.getParameterNames();
			    String pname, remove_id;
                StringBuffer where_clause = new StringBuffer();
                where_clause.append( "user_id IN (" );
			    out.println( "<PRE>" );
			    boolean first=true;
			    while ( plist.hasMoreElements() )
			        {
			        pname = (String)plist.nextElement();
			        if ( !pname.startsWith( "user_id_" ) )
			            continue;
			        remove_id=pname.substring( 8 );
			        try
			        	{
			        	temp_int = new Integer( remove_id );
			        	}
			        catch ( NumberFormatException nfex )
			        	{
			        	continue;
			        	}
			        out.println( temp_int.toString() );
			        if ( !first )
			            where_clause.append( ", " );
			        where_clause.append( temp_int.toString() );
    	            first=false;
			        }
			    where_clause.append( " ) " );
			    out.println( "</PRE>" );
			    

			    Enumeration enum=org.bodington.server.realm.User.findUsers( where_clause.toString(), "surname, initials" );
			    int n=0;
			    while ( enum.hasMoreElements() )
			        {
			        user = (org.bodington.server.realm.User)enum.nextElement();
			        if ( group.getName().endsWith( ".owners" ) && user.equals( current_user ) )
			        	out.println( "<I>Can't remove self</I>" );
			        else
			        	{
			        	group.removeMember( user );
			        	n++;
			        	}
			        }
			    group.save();
			    out.println( "<p>Removed " + n + " user(s).</p>" );
		        }
		    catch ( Exception ex )
		        {
		        out.println( "<PRE>" + ex + "</PRE>" );
		        return;
		        }
		    }
        
        if ( op.equalsIgnoreCase( "add" ) )
            {
            String g;
		    PrimaryKey group_id;
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }		    
		    out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
            out.print( "<input type=hidden name=group_id value=" );
            out.print( group_id.toString() ) ;
            out.println( " >" );
            out.println( "<INPUT type=hidden name=operation value=addconfirm>" );
            out.println( "<h4><strong>Confirm Addition of Users</strong></h4>" );
            
            listusers( breq, out, false );
            out.println( "</form>" );
            
            return;
            /*
            boolean wildcard=false, in_zone=false;
		    String g, wildstring, z;
		    PrimaryKey group_id, search_group_id=null;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User user;
		    User currentuser = (User)BuildingContext.getContext().getUser();
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
    		    
		    if ( !breq.isAuthenticated() )
			    {
			    out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			    return;
			    }
    		
		    //ought really to access check the group not the location
		    if ( !BuildingContext.getContext().checkPermission( "manage" ) )
		        {
			    out.println( "<HR>You need manage access rights to view access rights.<HR>" );
			    return;
		        }

			z = breq.getParameter( "in_zone" );
			in_zone = z!=null && z.equalsIgnoreCase( "zone_restricted" );

		    try
		        {
	            g=breq.getParameter( "search_group_id" );
    	        if ( g!=null )
			        search_group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
		        search_group_id = null;
		        }
    		    
            String identifier=breq.getParameter( "identifier" );
            if ( identifier==null )
                {
			    out.println( "You must select a type of identifier." );
			    return;
                }
            String idlist=breq.getParameter( "values" );
            if ( idlist==null )
                idlist="";
            idlist=idlist.trim();
            if ( idlist.length()==0 )
                {
                if ( search_group_id == null )
                	{
			    	out.println( "Invalid input: you have to select a group and/or type something into the search for box." );
				    return;
				    }
				idlist = "*";
                }
            StringTokenizer tok = new StringTokenizer( idlist );
            StringBuffer where_clause = new StringBuffer( idlist.length() );

            if ( in_zone )
            	{
            	where_clause.append( "zone_id = " );
            	where_clause.append( currentuser.getZoneId() );
  				where_clause.append( " AND " );
            	}
            
            if ( search_group_id != null )
            	{
            	try
            		{
            		Group search_group = Group.findGroup( search_group_id );
            		if ( search_group!=null )
            			{
            			String w = search_group.whereMembers();
            			if ( w!=null )
            				{
            				where_clause.append( w );
            				where_clause.append( " AND " );
            				}
            			}
            		}
				catch ( BuildingServerException bsexg )
					{
					out.println( "Technical problem finding search group." + bsexg );
					return;
					}
            	}

            if ( tok.countTokens() == 1 && !identifier.equals( "user_id" ) )
            	{
            	if ( identifier.equals( "surname" ) )
                	where_clause.append( "surname LIKE " );
            	else
                	{
                	if ( identifier.equals( "user_name" ) )
                    	where_clause.append( "user_id IN ( SELECT user_id FROM pass_phrases WHERE user_name LIKE " );
                	else
                		{
			        	try
			        		{
			        		temp_int = new Integer( identifier );
			        		}
			        	catch ( NumberFormatException nfex )
			        		{
						    out.println( "Invalid identifier type." );
			    			return;
			        		}
                        where_clause.append( "user_id IN (SELECT user_id FROM alias_entries WHERE alias_id = " );
                        where_clause.append( temp_int.toString() );
                        where_clause.append( " AND user_alias LIKE " );
                    	}
                	}
                wildstring = tok.nextToken();
                wildstring=wildstring.replace( '*', '%' );
                where_clause.append( SqlDatabase.quotedSQL( wildstring ) );
            	if ( !identifier.equals( "surname" ) )
                	where_clause.append( " )" );
            	}
            else
            	{
            	if ( identifier.equals( "surname" ) )
                	where_clause.append( "surname IN ( " );
            	else
                	{
                	if ( identifier.equals( "user_name" ) )
                    	where_clause.append( "user_id IN ( SELECT user_id FROM pass_phrases WHERE user_name IN ( " );
                	else
                    	{
                    	if ( identifier.equals( "user_id" ) )
                        	where_clause.append( "user_id IN ( " );
                    	else
                        	{
			        		try
			        			{
			        			temp_int = new Integer( identifier );
			        			}
			        		catch ( NumberFormatException nfex )
			        			{
						    	out.println( "Invalid identifier type." );
			    				return;
			        			}
                        	where_clause.append( "user_id IN (SELECT user_id FROM alias_entries WHERE alias_id = " );
                        	where_clause.append( temp_int.toString() );
                        	where_clause.append( " AND user_alias IN (" );
                        	}
                    	}
                	}
	                
            	boolean first=true;
            	while ( tok.hasMoreTokens() )
                	{
                	if ( !first )
                    	where_clause.append( ", " );
                	first=false;
                	
                	if ( identifier.equals( "user_id" ) )
                		{
			        	try
			        		{
			        		temp_int = new Integer( tok.nextToken() );
			        		}
			        	catch ( NumberFormatException nfex )
			        		{
						    out.println( "Invalid user id: must be a number." );
			    			return;
			        		}
			        	where_clause.append( temp_int.toString() );
                		}
					else
	                	where_clause.append( SqlDatabase.quotedSQL( tok.nextToken() ) );
						
                	}
            	if ( !identifier.equals( "user_id" ) && !identifier.equals( "surname" ) )
                	where_clause.append( " ) " );
            	where_clause.append( " ) " );
				}
				
            try
                {
                group = org.bodington.server.realm.Group.findGroup( group_id );
                if ( group==null )
			        {
			        out.println( "Problem: the specified group wasn't found." );
			        return;
			        }
		        if ( !group.checkPermission( Permission.EDIT ) )
		            {
			        out.println( "<HR>You need edit access rights to the selected group to edit membership.<HR>" );
			        return;
		            }
			        
			    Enumeration enum=org.bodington.server.realm.User.findUsers( where_clause.toString(), "surname, initials" );
			    
		        out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
                out.print( "<input type=hidden name=group_id value=" );
                out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=addconfirm>" );
                out.println( "<table CLASS=bs-table-opaque><tr>" );
                out.println( "<td COLSPAN=2 CLASS=bs-cell-special><strong>Confirm Addition of Users</TD></tr>" );
                int n=0;
                int u;
			    for ( u=0; enum.hasMoreElements(); u++ )
			        {
			        user = (org.bodington.server.realm.User)enum.nextElement();
			        out.println( "<TR><TD>" );
			        out.println( user.getName() );
			        out.println( "</TD><TD>" );
			        if ( group.isMember( user ) )
			            out.println( "In group already." );
			        else
			            {
			            if ( user.getSurname().equals( "Anonymous" ) )
			            	out.println( "Can't add to group." );
			            else
			            	{
			            	out.print( "<INPUT NAME=\"user_id_" );
			            	out.print( user.getUserId().toString() );
			            	out.println( "\" TYPE=CHECKBOX CHECKED VALUE=\"On\">" );
			            	n++;
			            	}
			            }
			        out.println( "</TD></TR>" );
			        }
			    if ( n==0 )
			        {
			        if ( u==0 )
			            out.println( "<TR><TD COLSPAN=2>No users were found.</TD></TR>" );
			        else
			            out.println( "<TR><TD COLSPAN=2>Only users who cannot be added to the group were found.</TD></TR>" );
			        }
                else
                    {
                    out.println( "<TR><TD COLSPAN=2>These users have not yet been added to the group. " );
                    out.println( "Please use the check boxes to select the users you wish to add to the membership.</TD></TR>" );
                    out.println( "<tr><td colspan=2><INPUT TYPE=SUBMIT VALUE=\"Add selected users\">" );
                	out.println( "<INPUT TYPE=button VALUE = \"Select All\" ONCLICK=\"checkall(true)\">"	);
                	out.println( "<INPUT TYPE=button VALUE = \"Unselect All\" ONCLICK=\"checkall(false)\">" );
                    out.println( "</td></tr>" );
                    }
			    out.println( "</TABLE></FORM>" );
			    }
		    catch ( Exception ex )
		        {
		        out.println( "<PRE>" + ex + "</PRE>" );
		        return;
		        }

            return;
            */
            }

        

        if ( op.equalsIgnoreCase( "addconfirm" ) )
            {
		    String g;
		    PrimaryKey group_id;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User user;
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
    		    
		    if ( !breq.isAuthenticated() )
			    {
			    out.println( "<HR>You haven't checked in to the building so you can't change access rights.<HR>" );
			    return;
			    }
    		
            try
                {
                group = org.bodington.server.realm.Group.findGroup( group_id );
                if ( group==null )
			        {
			        out.println( "Problem: the specified group wasn't found." );
			        return;
			        }
		        if ( !group.checkPermission( Permission.EDIT ) )
		            {
			        out.println( "<HR>You need edit access rights to the selected group to edit membership.<HR>" );
			        return;
		            }
			    Enumeration plist = breq.getParameterNames();
			    
			    if ( !plist.hasMoreElements() )
			    	{
			    	out.println( "No users were selected so none were added to the group." );
			    	return;
			    	}
			    
			    String pname, remove_id;
                StringBuffer where_clause = new StringBuffer();
                where_clause.append( "user_id IN (" );
			    //out.println( "<PRE>" );
			    boolean first=true;
			    while ( plist.hasMoreElements() )
			        {
			        pname = (String)plist.nextElement();
			        if ( !pname.startsWith( "user_id_" ) )
			            continue;
			        remove_id=pname.substring( 8 );
			        try
			        	{
			        	temp_int = new Integer( remove_id );
			        	}
			        catch ( NumberFormatException nfex )
			        	{
			        	continue;
			        	}
			        //out.println( temp_int.toString() );
			        if ( !first )
			            where_clause.append( ", " );
			        where_clause.append( temp_int.toString() );
    	            first=false;
			        }
			    where_clause.append( " ) " );
			    //out.println( "</PRE>" );
			    

			    Enumeration enum=org.bodington.server.realm.User.findUsers( where_clause.toString(), "surname, initials" );
			    int n=0;
			    while ( enum.hasMoreElements() )
			        {
			        user = (org.bodington.server.realm.User)enum.nextElement();
			        group.addMember( user );
			        n++;
			        }
			    group.save();
			    
			    out.println( "<P>Added " + n + " user(s)</p>"  );
		        }
		    catch ( Exception ex )
		        {
		        out.println( "<PRE>" + ex + "</PRE>" );
		        return;
		        }
		    }
        
              /*
                * WebLearn modified code; A Corfield 02/12/2003.
                */
                if ( op.equalsIgnoreCase( "addform" ) || op.equalsIgnoreCase( "addform2" ) )
                {
                  String g;
                  PrimaryKey group_id;
                  org.bodington.server.realm.Group group;
                  org.bodington.server.realm.User current_user;

                  current_user = (org.bodington.server.realm.User) BuildingContext.getContext().getUser();

                  g = breq.getParameter("group_id");
                  if (g == null) {
                    out.println("Problem: no group_id was specified.");
                    return;
                  }
                  try {
                    group_id = new PrimaryKey(Integer.parseInt(g));
                  }
                  catch (NumberFormatException nfex) {
                    out.println("Problem: invalid group_id was specified.");
                    return;
                  }

                  if (op.equalsIgnoreCase("addform")) {
                    out.println("<FORM METHOD=POST ACTION=bs_template_accessgroup.html>");
                    out.print("<input type=hidden name=group_id value=");
                    out.print(group_id.toString());
                    out.println(" >");
                    out.println("<INPUT type=hidden name=operation value=addform2>");
                    out.println("<INPUT type=submit value=\"Advanced Search\">");
                    out.println(
                        "(Allows you to limit the search to members of a selected group).");
                    out.println("</FORM>");
                  }

                  userSearchFields(breq, out, group_id, op.equalsIgnoreCase("addform2"), false);
                }

       /*
        * WebLearn modified code; A Corfield 02/12/2003.
        */
/*
        if ( op.equalsIgnoreCase( "addform" ) || op.equalsIgnoreCase( "addform2" ) )
            {
		    String g;
		    PrimaryKey group_id;
		    org.bodington.server.realm.Group group;
		    org.bodington.server.realm.User current_user;
    		
    		current_user=(org.bodington.server.realm.User)BuildingContext.getContext().getUser();
    		
            g=breq.getParameter( "group_id" );
            if ( g==null )
			    {
			    out.println( "Problem: no group_id was specified." );
			    return;
			    }
		    try
		        {
		        group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
			    out.println( "Problem: invalid group_id was specified." );
			    return;
		        }
		        
		    if ( op.equalsIgnoreCase( "addform" ) )
		        {
    		    out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
                  out.print( "<input type=hidden name=group_id value=" );
                  out.print( group_id.toString() ) ;
                out.println( " >" );
                out.println( "<INPUT type=hidden name=operation value=addform2>" );
                out.println( "<INPUT type=submit value=\"Advanced Search\">" );
                out.println( "(Allows you to limit the search to members of a selected group)." );
                out.println( "</FORM>" );
                }
                
		    out.println( "<FORM METHOD=POST ACTION=bs_template_accessgroup.html>" );
            out.print( "<input type=hidden name=group_id value=" );
            out.print( group_id.toString() ) ;
            out.println( " >" );
            out.println( "<INPUT type=hidden name=operation value=add>" );
                
            userSearchFields( breq, out, op.equalsIgnoreCase( "addform2" ), false );
                
            out.println( "</FORM>" );
            }    		    
*/
        }


	public void listusers( Request req, PrintWriter out, boolean link_to_user )
		throws IOException
		{
	
		try
			{
            boolean wildcard=false, in_zone=false;
		    String g, gg, group_name, wildstring, z, param;
		    Integer temp_int;
		    PrimaryKey search_group_id=null, group_id = null, user_id;
		    Vector user_ids = new Vector();
		    org.bodington.server.realm.Group group=null;
		    org.bodington.server.realm.User user;
		    User currentuser = (User)BuildingContext.getContext().getUser();
           	Group search_group=null;
           	boolean xml_output, html_output;
           	int i, j, n, cols=0;
    		
		    org.bodington.server.realm.User current_user;
    		current_user=(org.bodington.server.realm.User)BuildingContext.getContext().getUser();

        	String op=req.getParameter( "operation" );
        	if ( op!=null )
        		{
        		op=op.trim();
	        	if ( op.length()==0 ) op=null;
            	}
    		    
            param=req.getParameter( "output_format" );
            xml_output = param != null && param.equalsIgnoreCase( "xml" );
            html_output = !xml_output && !(param != null && param.equalsIgnoreCase( "text" ));

			z = req.getParameter( "in_zone" );
			in_zone = z!=null && z.equalsIgnoreCase( "zone_restricted" );

            group_name=req.getParameter( "search_group_name" );
            if ( group_name!=null && group_name.length() == 0 )
            	group_name=null;

		    try
		        {
	            g=req.getParameter( "search_group_id" );
    	        if ( g!=null )
			        search_group_id = new PrimaryKey( Integer.parseInt( g ) );
		        }
		    catch ( NumberFormatException nfex )
		        {
		        search_group_id = null;
		        }
    		    
		    try
		        {
	            gg=req.getParameter( "group_id" );
    	        if ( gg!=null && gg.length()>0 )
			        group_id = new PrimaryKey( Integer.parseInt( gg ) );
		        }
		    catch ( NumberFormatException nfex2 )
		        {
				out.println( "Technical problem finding group." + nfex2 );
		        return;
		        }
    		    
            String identifier=req.getParameter( "identifier" );
            if ( identifier==null )
                {
			    out.println( "You must select a type of identifier." );
			    return;
                }
            String idlist=req.getParameter( "values" );
            if ( idlist==null )
                idlist="";
            idlist=idlist.trim();
            if ( idlist.length()==0 )
                {
                if ( search_group_id == null && group_name == null )
                	{
			    	out.println( "Invalid input: you have to select a group and/or type something into the search for box." );
				    return;
				    }
				idlist = "*";
                }
            StringTokenizer tok = new StringTokenizer( idlist );
            StringBuffer where_clause = new StringBuffer( idlist.length() );

            if ( in_zone && currentuser!=null )
            	{
            	where_clause.append( "zone_id = " );
            	where_clause.append( currentuser.getZoneId() );
  				where_clause.append( " AND " );
            	}
            
            try
            	{
            	if ( search_group_id != null )
            		{
            		search_group = Group.findGroup( search_group_id );
            		}
            	else if ( group_name != null )
            		{
            		search_group = Group.findGroup( "name = '" + group_name + "'" );
            		}
            	}
			catch ( BuildingServerException bsexg )
				{
				out.println( "Technical problem finding search group." + bsexg );
				return;
				}

            try
            	{
            	if ( group_id != null )
            		{
            		group = Group.findGroup( group_id );
            		}
            	}
			catch ( BuildingServerException bsexg )
				{
				out.println( "Technical problem finding group." + bsexg );
				return;
				}

            if ( search_group!=null )
            	{
		        if ( !search_group.checkPermission( Permission.VIEW ) )
		            {
			        out.println( "<p>You need view access rights to the 'search in' group to list it's membership.</p>" );
			        return;
		            }
            	String w = search_group.whereMembers();
            	if ( w!=null )
            		{
            		where_clause.append( w );
            		where_clause.append( " AND " );
            		}
            	}

            if ( tok.countTokens() == 1 )
            	{
                wildstring = tok.nextToken();
                wildstring=wildstring.replace( '*', '%' );
                
            	if ( identifier.equals( "user_id" ) )
            		{
            		if ( wildstring.equals( "%" ) )
            			{
            			if ( search_group != null )
            				where_clause.append( "user_id IS NOT NULL" );
            			else
            				{
            				out.println( "<p>You can only wild card bodington user IDs when you search for users within a group.</p>" );
            				return;
            				}
            			}
            		else
            			{
			        	try
			        		{
			        		Integer.parseInt( wildstring );
			        		}
			        	catch ( NumberFormatException nfex )
			        		{
						    out.println( "<p>Invalid identifier type.</p>" );
			    			return;
			        		}
			        	where_clause.append( "user_id = " + wildstring );
            			}
            		}
            	else
            		{
            		if ( identifier.equals( "surname" ) )
                		where_clause.append( "surname LIKE " );
            		else
                		{
                		if ( identifier.equals( "user_name" ) )
                    		where_clause.append( "user_id IN ( SELECT user_id FROM pass_phrases WHERE user_name LIKE " );
                		else
                			{
			        		try
			        			{
			        			temp_int = new Integer( identifier );
			        			}
			        		catch ( NumberFormatException nfex )
			        			{
						    	out.println( "Invalid identifier type." );
			    				return;
			        			}
                        	where_clause.append( "user_id IN (SELECT user_id FROM alias_entries WHERE alias_id = " );
                        	where_clause.append( temp_int.toString() );
                        	where_clause.append( " AND user_alias LIKE " );
                    		}
                		}
                	}
                	
                if ( !identifier.equals( "user_id" ) )
                	{
                	where_clause.append( SqlDatabase.quotedSQL( wildstring ) );
	            	if ( !identifier.equals( "surname" ) )
    	            	where_clause.append( " )" );
    	            }
            	}
            else
            	{
            	if ( identifier.equals( "surname" ) )
                	where_clause.append( "surname IN ( " );
            	else
                	{
                	if ( identifier.equals( "user_name" ) )
                    	where_clause.append( "user_id IN ( SELECT user_id FROM pass_phrases WHERE user_name IN ( " );
                	else
                    	{
                    	if ( identifier.equals( "user_id" ) )
                        	where_clause.append( "user_id IN ( " );
                    	else
                        	{
			        		try
			        			{
			        			temp_int = new Integer( identifier );
			        			}
			        		catch ( NumberFormatException nfex )
			        			{
						    	out.println( "Invalid identifier type - must be numeric." );
			    				return;
			        			}
                        	where_clause.append( "user_id IN (SELECT user_id FROM alias_entries WHERE alias_id = " );
                        	where_clause.append( temp_int.toString() );
                        	where_clause.append( " AND user_alias IN (" );
                        	}
                    	}
                	}
	                
            	boolean first=true;
            	while ( tok.hasMoreTokens() )
                	{
                	if ( !first )
                    	where_clause.append( ", " );
                	first=false;
                	
                	if ( identifier.equals( "user_id" ) )
                		{
			        	try
			        		{
			        		temp_int = new Integer( tok.nextToken() );
			        		}
			        	catch ( NumberFormatException nfex )
			        		{
						    out.println( "Invalid user id: must be a number." );
			    			return;
			        		}
			        	where_clause.append( temp_int.toString() );
                		}
					else
	                	where_clause.append( SqlDatabase.quotedSQL( tok.nextToken() ) );
						
                	}
            	if ( !identifier.equals( "user_id" ) && !identifier.equals( "surname" ) )
                	where_clause.append( " ) " );
            	where_clause.append( " ) " );
				}
				
				
            try
                {
                // look for aliases that could be included
                // at present narrow it down by using only primary
                // aliases that can be used to create students.
			    Enumeration enum=Alias.findAliases( "alias_id IS NOT NULL" );
			    Alias alias;
			    AliasEntry alias_entry;
			    Vector aliases = new Vector();
			    PassPhrase pass_phrase;
			    
			    while ( enum.hasMoreElements() )
			        {
			        alias = (Alias)enum.nextElement();
			        if ( alias.isPrimary() && 
			        		(alias.hasUserCategory( "student" ) || 
			        		 alias.hasUserCategory( "students" )  ) )
			        	aliases.addElement( alias );
			        }
                

			    enum=org.bodington.server.realm.User.findUserPrimaryKeys( where_clause.toString(), "surname, initials" );
			    while ( enum.hasMoreElements() )
			        {
			        user_ids.addElement( enum.nextElement() );
			        }
			    
	            if ( html_output )
	            	{
			    	out.print( "<p>" );
			    	out.print( user_ids.size() );
			    	out.print( " users found.</p>" );
	            	}
	            	
			    if ( user_ids.size() > 2000 )
			    	{
			    	out.println( "<p>It is not possible to list more than 2000 users on this page.</p>" );
			    	return;
			    	}

				if ( xml_output )
					{
					out.println( "<?xml version=\"1.0\"?>" );
					if ( search_group == null )
						out.println( "<group>" );
					else
						{
						out.print( "<group group_id=\"" );
						out.print( search_group.getGroupId().toString() );
						out.print( "\" group_name=\"" );
						out.print( search_group.getName() );
						out.println( "\">" );
						}
					}
				else
					{
					if ( html_output )
						{
            			out.println( "<table CLASS=bs-table-opaque><tr>" );
            			if ( "add".equals( op ) || "remove".equals( op ) )
            				{
	            			out.println( "<td CLASS=bs-cell-special><strong>Select</strong></td>" );
							cols=4;
	            			}
	            		else
							cols=3;
            			out.println( "<td CLASS=bs-cell-special><strong>User ID</strong></td>" );
            			out.println( "<td CLASS=bs-cell-special><strong>Name</strong></td>" );
            			out.println( "<td CLASS=bs-cell-special><strong>User Name</strong></td>" );
            			}
            		else
            			out.print( "user_id\tname\tuser_name" );

            		
					for ( j=0; j<aliases.size(); j++ )
						{
						if ( html_output )
            				out.print( "<td CLASS=bs-cell-special><strong>" );
            			else
            				out.print( "\t" );
						alias = (Alias)aliases.elementAt( j );
						out.print( alias.getZone().getPrefix() );
						if ( html_output )
							out.print( " " );
						else
							out.print( "_" );
						out.print( alias.getAliasName() );
						if ( html_output )
							{
	            			out.println( "</strong></td>" );
	            			cols++;
	            			}
						}
						
					if ( html_output )
	            		out.println( "</tr>" );
	            	else
	            		out.println();
            		}
            	

			    
			    
			    n=0;
			    for ( i=0; i<user_ids.size(); i++ )
			        {
			        user = org.bodington.server.realm.User.findUser( (PrimaryKey)user_ids.elementAt( i ) );
		            if ( user == null )
		            	continue;
		            if ( user.getSurname().equals( "Anonymous" ) )
		            	continue;
		            
		            //break up table into chunks so page display is more responsive.
					if ( html_output && i>0 && (i%50)==0 )
						{
						out.println( "</table>" );
            			out.println( "<table CLASS=bs-table-opaque><tr>" );
            			if ( "add".equals( op ) || "remove".equals( op ) )
            				out.println( "<td CLASS=bs-cell-special><strong>Select</strong></td>" );
            			out.println( "<td CLASS=bs-cell-special><strong>User ID</strong></td>" );
            			out.println( "<td CLASS=bs-cell-special><strong>Name</strong></td>" );
            			out.println( "<td CLASS=bs-cell-special><strong>User Name</strong></td>" );

	            		
						for ( j=0; j<aliases.size(); j++ )
							{
           					out.print( "<td CLASS=bs-cell-special><strong>" );
							alias = (Alias)aliases.elementAt( j );
							out.print( alias.getZone().getPrefix() );
							out.print( " " );
							out.print( alias.getAliasName() );
            				out.println( "</strong></td>" );
							}
							
            			out.println( "</tr>" );
            			}

		            
		            
		            if ( xml_output )
		            	out.print( "\t<user>\n\t\t<user_id>" );
		            else if ( html_output )
			        	out.print( "<tr><td>" );

		            if ( html_output )
		            	{
		            	if ( op!=null && op.equals( "add" ) )
		            		{
			        		if ( group.isMember( user ) )
			            		out.println( "Already member." );
			        		else
 			            		{
			            		if ( user.getSurname().equals( "Anonymous" ) )
			            			out.println( "Can't add." );
			            		else
			            			{
			            			out.print( "<INPUT NAME=\"user_id_" );
			            			out.print( user.getUserId().toString() );
			            			out.println( "\" TYPE=CHECKBOX CHECKED VALUE=\"On\">" );
			            			n++;
			            			}
			            		}
			            	out.print( "</td><td>" );
			            	}
			            	
		            	if ( op!=null && op.equals( "remove" ) )
		            		{
		            		if ( group.getName().endsWith( ".owners" ) &&
		            			 user.equals( currentuser ) )
		            			{
		            			out.println( "Can't remove." );
		            			}
		            		else
		            			{
			            		out.print( "<INPUT NAME=\"user_id_" );
			            		out.print( user.getUserId().toString() );
			            		out.println( "\" TYPE=CHECKBOX CHECKED VALUE=\"On\">" );
			            		n++;
		            			}
			            	out.print( "</td><td>" );
		            		}
		            		
		            	}

			        	
				    out.print( user.getUserId().toString() );
				    
		            if ( xml_output )
		            	out.print( "</user_id>\n\t\t<name>" );
		            else if ( html_output )
		            	{
		            	out.println( "</td><td>" );
		            	if ( link_to_user )
		            		{
		            		out.print( "<a href = \"" );
					    	out.print( user.getUserId().toString() );
				        	out.print( "/bs_template_userdata.html\">" );
				        	}
				        }
				    else
				    	out.print( "\t" );
		            	
				    out.print( user.getName() );

		            if ( xml_output )
		            	out.println( "</name>" );
		            else if ( html_output )
		            	{
		            	if ( link_to_user )
		            		out.println( "</a>" );
		            	out.println( "</td>" );
		            	}
				    
					pass_phrase = PassPhrase.findPassPhrase( "user_id = " + user.getUserId().toString() );
					if ( xml_output )
						{
						if ( pass_phrase!=null && pass_phrase.getUserName()!=null )
							{
							out.print( "\t\t<user_name>" );
							out.print( pass_phrase.getUserName() );
							out.println( "</user_name>" );
							}
						}
					else
						{
						if ( html_output )
							out.print( "<td>" );
						else
							out.print( "\t" );
						if ( pass_phrase!=null && pass_phrase.getUserName()!=null )
							out.print( pass_phrase.getUserName() );
						if ( html_output )
							out.print( "</td>" );
						}
						
					for ( j=0; j<aliases.size(); j++ )
						{
						alias = (Alias)aliases.elementAt( j );
						
						if ( !xml_output )
							{
							if ( html_output )
								out.print( "<td>" );
							else 
								out.print( "\t" );
							}

						alias_entry = AliasEntry.findAliasEntry( 
							"alias_id = " + alias.getAliasId().toString() + 
							" AND user_id = " + user.getUserId().toString()  );

						if ( alias_entry!=null )
							{
							if ( xml_output )
								{
								out.print( "\t\t<alias_entry zone_id=\"" );
								out.print( alias.getZoneId() );
								out.print( "\" prefix=\"" );
								out.print( alias.getZone().getPrefix() );
								out.print( "\" alias_id=\"" );
								out.print( alias.getAliasId() );
								out.print( "\" alias_name=\"" );
								out.print( alias.getAliasName() );
								out.print( "\">" );
								out.print( alias_entry.getUserAlias() );
								out.println( "</alias_entry>" );
								}
							else
								{
								out.print( alias_entry.getUserAlias() );
								}
							}
							
						if ( html_output )
							out.print( "</td>" );
						}

					if ( xml_output )
						out.println( "\t</user>" );
					else if ( html_output )
						out.println( "</tr>" );
					else
						out.println();

			        }
			    }
		    catch ( Exception ex )
		        {
		        out.println( "</TABLE><PRE>" + ex + "</PRE>" );
		        return;
		        }

			if ( xml_output )
			    out.println( "</group>" );
			else if ( html_output )
				{
				if ( "add".equals( op ) || "remove".equals( op ) )
					{
			    	if ( n==0 )
			        	{
			        	if ( user_ids.size()==0 )
			        		{
                    		out.print( "<TR><TD COLSPAN=" );
                    		out.print( cols );
			            	out.println( ">No users were found.</TD></TR>" );
			            	}
			        	else
			        		{
                    		out.print( "<TR><TD COLSPAN=" );
                    		out.print( cols );
			            	out.println( ">Only users who cannot be processed were found.</TD></TR>" );
			            	}
			        	}
                	else
                    	{
                    	out.print( "<TR><TD COLSPAN=" );
                    	out.print( cols );
                    	out.print( ">These users have not yet been processed. " );
                    	out.println( "Please use the check boxes to select the users you wish to process.</TD></TR>" );
                    	out.print( "<TR><TD COLSPAN=" );
                    	out.print( cols );
                    	out.println( "><INPUT TYPE=SUBMIT VALUE=\"Confirm selected users\">" );
                		out.println( "<INPUT TYPE=button VALUE = \"Select All\" ONCLICK=\"checkall(true)\">"	);
                		out.println( "<INPUT TYPE=button VALUE = \"Unselect All\" ONCLICK=\"checkall(false)\">" );
                    	out.println( "</td></tr>" );
                    	}
                    }
			    out.println( "</table>" );
			    }

            return;
			}
		catch ( Exception ex )
			{
			out.println( "<HR><H4>There was a problem finding users.</H4><HR>\n" );
			return;
			}
		}

	// Puts in a table and form input fields for searching for users.
	// Doesn't put in <FORM> tag or </FORM>
	public void userSearchFields( Request breq, PrintWriter out, boolean withGroups, boolean withOutputOpts )
		throws IOException
		{
		int i;
		Group group;
	    User user;
    		
    	user=(User)BuildingContext.getContext().getUser();
		
		try
		    {
            out.println( "<table CLASS=bs-table-opaque><tr>" );
            out.println( "<td COLSPAN=3 CLASS=bs-cell-special><strong>Find Users</TD></tr>" );

            out.println( "<TR><TD VALIGN=TOP><B>Administrative Zone</B></TD><TD>" );
            out.println( "<INPUT TYPE=RADIO NAME=in_zone VALUE=zone_any CHECKED>Search entire site.<BR>" );
            out.println( "<INPUT TYPE=RADIO NAME=in_zone VALUE=zone_restricted>Search within " );
            out.println( user.getZone().getName() );
            out.print( "</TD><TD ROWSPAN=4 VALIGN=TOP>" );
            out.print( "<input type=submit value=\"Search\">" );
            
            if ( withGroups )
                {
                out.println( "</TD></TR>" );
			    out.println( "<TR><TD VALIGN=TOP><B>Search within group:</B></TD><TD>" );
                try
                    {
		    	    Enumeration enum = org.bodington.server.realm.Group.findGroups( 
		    									    "name NOT LIKE 'localgroup.%'", "name" );

            	    out.println( "<SELECT NAME=search_group_id size=5>" );
            	    out.println( "<OPTION VALUE=null SELECTED>ignore group membership</OPTION>" );
                		
		    	    for ( i=0; enum.hasMoreElements(); i++ )
		    		    {
		        	    group = (org.bodington.server.realm.Group)enum.nextElement();
		        	    //don't list group if current user hasn't got view access to it.
		        	    if ( !group.checkPermission( Permission.VIEW ) )
		        		    continue;
		        	    out.print( "<OPTION VALUE=\"" );
		        	    out.print( group.getGroupId().toString() );
		        	    out.print( "\">" );
	        		    out.print( group.getName() );
		        	    out.println( "</OPTION>" );
		        	    }
		            if ( i==0 )
		        	    out.println( "<OPTION VALUE=null>No groups available</OPTION>" );
		    	    out.println( "</SELECT></TD></TR>" );
		    	    }
                catch ( BuildingServerException bsex )
                    {
		    logException( out, "Facility", "userSearchFields", 
			"Technical error trying to produce list of groups. ",
			    bsex );
                    }
    			out.println( "</TD></TR>" );                
                }
            else
                {
                out.println( "<INPUT TYPE=HIDDEN NAME=search_group_id VALUE==null>" );
                out.println( "</TD></TR>" );
                }
                
			out.println( "<TR><TD VALIGN=TOP>" );                
                
            out.println( "<B>Search By Name or Unique Identifier:</B></TD><TD>" );
            out.println( "<select name=identifier size=5>" );
            out.println( "<option value=surname>surname</option>" );
            out.println( "<option value=user_id>bodington user id number</option>" );
            out.println( "<option value=user_name SELECTED>bodington user name</option>" );
			Enumeration z_enum;
			if ( BuildingContext.getContext().checkPermission( "sysadmin" ) )
                z_enum = Zone.findZones( "zone_id IS NOT NULL" );
            else
                z_enum = Zone.findZones( "zone_id = " + user.getZoneId() );
                	
            Enumeration a_enum;
            Zone z;
            Alias a;
            while ( z_enum.hasMoreElements() )
                {
                z = (Zone) z_enum.nextElement();
                a_enum = Alias.findAliases( "zone_id = " + z.getZoneId() );
                while ( a_enum.hasMoreElements() )
                    {
                    a = (Alias)a_enum.nextElement();
                    out.print( "<option value=" );
                    out.print( a.getAliasId().toString() );
                    out.print( ">" );
                    out.print( z.getName() );
                    out.print( ":" );
                    out.print( a.getAliasName() );
                    out.println( "</option>" );
                    }
                }
                
            out.println( "</select></TD></TR><TR><TD VALIGN=TOP><B>Search For:</B><BR>" );
            out.println( "(Enter a list of values one per line or a single<BR>" );
            out.println( "value with or without a * wildcard.)</TD><TD>" );
            out.println( "<SPAN CLASS=bs-textarea><textarea name=values rows=10 cols=20></textarea></SPAN>" );
            out.println( "</td></tr>" );
            if ( withOutputOpts )
            	{
            	out.println( "<tr><td VALIGN=\"top\"><b>Output:</b></td><td>" );
            	out.println( "<INPUT TYPE=RADIO NAME=output_format VALUE=html CHECKED>Web Page<BR>" );
            	out.println( "<INPUT TYPE=RADIO NAME=output_format VALUE=text>TAB delimited text<br> " );
            	out.println( "<INPUT TYPE=RADIO NAME=output_format VALUE=xml>XML file " );
            	out.println( "</td></tr>" );
            	}
           	out.println( "</TABLE>" );
            }
        catch ( BuildingServerException bsex )
            {
            out.println( "Technical error trying to produce form: " );
		    logException( out, "Facility", "userSearchFields", 
			"Technical error trying to produce form: ",
			    bsex );
            }
		}


              /**
                * Creates a table and form input fields for searching for users.
                * Groups are sorted by the various nodes so that it loads quickly.
                * Method derived from {@link #addaclentry(Request, PrintWriter)}. <p>
                * <i>(WebLearn; A Corfield 02/12/2003)</i>
                */
                private void userSearchFields( Request breq, PrintWriter out, PrimaryKey group_id, boolean withGroups, boolean withOutputOpts )
                        throws IOException
                        {
                        int i;
                        Group group;
                        User user;
                        String gname;


                    user=(User)BuildingContext.getContext().getUser();
                        try
                            {
                    out.println( "<table border=0 CLASS=bs-table-opaque><tr>" );
                    out.println( "<td COLSPAN=3 CLASS=bs-cell-special><strong>Find Users</TD></tr>" );

                    if ( withGroups )
                        {

                        if (!breq.isAuthenticated()) {
                          out.println("<tr><td><HR>You haven't checked in to the building so you can't change access rights.<HR></TD></TR></table>");
                          return;
                        }

                        if (!BuildingContext.getContext().checkPermission("manage")) {
                          out.println(
                              "<tr><td><HR>You need manage access rights to view access rights.<HR></TD><TR></table>");
                          return;
                        }

                        String base = breq.getParameter("category");
                        if (base == null)
                          base = "*";
                        base = base.trim();
                        if (!base.endsWith("*"))
                          base = null;
                        else
                          base = base.substring(0, base.length() - 1);

                        try {
                          Resource resource = breq.getResource();
                          org.bodington.server.realm.Acl acl = resource.getAcl();
                          //out.println( "<PRE>" + acl.toString() );
                          //Enumeration enum = acl.entries();
                          AclEntry aclentry;

                          Vector groups = new Vector();
                          Vector headings = new Vector();

                          Enumeration enum;
                          if (base == null || base.length() == 0) {
                            enum = org.bodington.server.realm.Group.findGroups(
                                 "name LIKE 'localgroup." + resource.getResourceId() + ".%'", "name");
                            while (enum.hasMoreElements())
                              groups.addElement(enum.nextElement());
                          }

                          if (base == null || base.length() == 0)
                            enum = org.bodington.server.realm.Group.findGroups(
                                "name NOT LIKE 'localgroup.%'", "name");
                          else
                            enum = org.bodington.server.realm.Group.findGroups(
                                "name LIKE '" + base + "%'", "name");

                          String name;
                          int dot_offset;
                          while (enum.hasMoreElements()) {
                            if (base == null)
                              groups.addElement(enum.nextElement());
                            else {
                              group = (org.bodington.server.realm.Group) enum.nextElement();
                              name = group.getName();
                              if (!name.startsWith(base))
                                continue;
                              dot_offset = name.indexOf('.', base.length());
                              if (dot_offset < 0 ||
                                  (base.length() == 0 && name.startsWith("localgroup.")))
                                groups.addElement(group);
                              else {
                                name = base + name.substring(base.length(), dot_offset) + ".*";
                                if (!headings.contains(name))
                                  headings.addElement(name);
                              }
                            }
                          }

                          out.println("<TR><TD align=left VALIGN=TOP><B>Search within group:</B></TD><td align=right VALIGN=TOP>");
                          out.print("<form method=POST ACTION=\"");
                          out.print(breq.absoluteURL());
                          out.println("bs_template_accessgroup.html\">");
                          out.print("<input type=hidden name=group_id value=");
                          out.print(group_id.toString());
                          out.println(" >");
                          out.println( "<INPUT type=hidden name=operation value=addform2>" );

                          if (base != null) {
                            out.print("<INPUT TYPE=HIDDEN NAME=category_url VALUE=\"");
                            out.print(breq.absoluteURL());
                            out.print("\"><INPUT TYPE=HIDDEN NAME=category_page VALUE=\"bs_template_");
                            out.print(breq.getPageName());
                            out.println("\">");
                            out.println("<SELECT NAME=category size=6>");
                            if (base.length() > 0) {
                              out.print("<OPTION VALUE=\"*\">*</OPTION>");
                            }
                            out.print("<OPTION SELECTED VALUE=\"");
                            out.print(base);
                            out.println("*\">");
                            out.print(base);
                            out.print("*");
                            out.println("</OPTION>");
                            for (i = 0; i < headings.size(); i++) {
                              out.print("<OPTION VALUE=\"");
                              out.print(headings.elementAt(i).toString());
                              out.print("\">");
                              out.print(headings.elementAt(i).toString());
                              out.println("</OPTION>");
                            }
                            out.println("</SELECT>");
                            out.println( "<br><INPUT TYPE=SUBMIT VALUE=\"Expand\">" );
                          }
                          else
                            out.println("<I>All categories</I>");
                          out.println("</form></td>");

                          out.println("<td valign=top align=right>");
                          out.println("<FORM METHOD=POST ACTION=bs_template_accessgroup.html>");
                          out.print("<input type=hidden name=operation value=add>");
                          out.print("<input type=hidden name=group_id value=");
                          out.print(group_id.toString());
                          out.println(" >");
                          out.println("<SELECT NAME=search_group_id size=10>");

                          for (i = 0; i < groups.size(); i++) {
                            group = (org.bodington.server.realm.Group) groups.elementAt(i);
                            //don't list group if current user hasn't got see access to it.
                            if (!group.checkPermission(Permission.SEE))
                              continue;
                            aclentry = acl.getAclEntry(group.getGroupId(), false);
                            //don't list group if it is in acl already
                            if (aclentry != null)
                              continue;
                            out.print("<OPTION VALUE=\"");
                            out.print(group.getGroupId().toString());
                            out.print("\">");
                            gname = group.getName();
                            if (gname.startsWith("localgroup."))
                              out.print(gname.substring(gname.lastIndexOf('.') + 1));
                            else
                              out.print(gname);
                            out.println("</OPTION>");
                          }
                          out.println("</SELECT></td>");
                        }
                        catch (Exception ex) {
                          out.println("<PRE>" + ex + "</PRE>");
                          return;
                        }
                      }
                      else {
                        out.println("<FORM METHOD=POST ACTION=bs_template_accessgroup.html>");
                        out.print("<input type=hidden name=operation value=add>");
                        out.print("<input type=hidden name=group_id value=");
                        out.print(group_id.toString());
                        out.println(" >");
                        out.println("<INPUT TYPE=HIDDEN NAME=search_group_id VALUE=null></td><tr>");
                      }
                      out.println("<TR><TD align=left VALIGN=TOP>");
                      out.println("<B>Search By Name or Unique Identifier:</B></TD><TD colspan=2 align=right VALIGN=TOP>");
                      out.println("<select name=identifier size=5>");
                      out.println("<option value=surname>surname</option>");
                      out.println("<option value=user_id>bodington user id number</option>");
                      out.println( "<option value=user_name SELECTED>bodington user name</option>");
                      Enumeration z_enum;
                      if (BuildingContext.getContext().checkPermission("sysadmin"))
                        z_enum = Zone.findZones("zone_id IS NOT NULL");
                      else
                        z_enum = Zone.findZones("zone_id = " + user.getZoneId());

                      Enumeration a_enum;
                      Zone z;
                      Alias a;
                      while (z_enum.hasMoreElements()) {
                        z = (Zone) z_enum.nextElement();
                        a_enum = Alias.findAliases("zone_id = " + z.getZoneId());
                        while (a_enum.hasMoreElements()) {
                          a = (Alias) a_enum.nextElement();
                          out.print("<option value=");
                          out.print(a.getAliasId().toString());
                          out.print(">");
                          out.print(z.getName());
                          out.print(":");
                          out.print(a.getAliasName());
                          out.println("</option>");
                        }
                      }

                      out.println("</select></TD></TR><TR><TD VALIGN=TOP><B>Search For:</B><BR>");
                      out.println("(Enter a list of values one per line or a single<BR>");
                      out.println("value with or without a * wildcard.)</TD><TD colspan=2 align=right VALIGN=TOP>");
                      out.println("<SPAN CLASS=bs-textarea><textarea name=values rows=10 cols=20></textarea></SPAN>");
                      out.println("</td></tr>");
                      if (withOutputOpts) {
                        out.println("<tr><td VALIGN=\"top\"><b>Output:</b></td><td>");
                        out.println(
                            "<INPUT TYPE=RADIO NAME=output_format VALUE=html CHECKED>Web Page<BR>");
                        out.println(
                            "<INPUT TYPE=RADIO NAME=output_format VALUE=text>TAB delimited text<br> ");
                        out.println("<INPUT TYPE=RADIO NAME=output_format VALUE=xml>XML file ");
                        out.println("</td></tr>");
                      }

                      out.println("<TR><TD VALIGN=TOP><B>Administrative Zone</B></TD><TD colspan=2 align=left VALIGN=TOP>");
                      out.println("<INPUT TYPE=RADIO NAME=in_zone VALUE=zone_any CHECKED>Search entire site.<BR>");
                      out.println("<INPUT TYPE=RADIO NAME=in_zone VALUE=zone_restricted>Search within ");
                      out.println(user.getZone().getName());
                      out.print("</TD></tr>");
                      out.print("<tr><TD colspan=3 align=right VALIGN=TOP><input type=submit value=\"Search\"></TD></tr>");

                      out.println("</form></TABLE>");
                    }
                    catch (BuildingServerException bsex) {
                      out.println("Technical error trying to produce form: ");
                      logException(out, "Facility", "userSearchFields",
                                   "Technical error trying to produce form: ",
                                   bsex);
                    }
                  }


	public boolean createCheck( Request breq, PrintWriter out )
		{
		//default creation does nothing but other facilities can
		//check user input print errors and prevent resource creation
		//by returning false.
		return true;
		}

	public boolean create( Request breq, Connection con, Resource new_resource )
		throws Exception
		{
		//default creation routine does nothing but
		//other facilities can do more setting up
		//if it goes wrong returning false will roll
		//back all database transactions including the
		//generic ones.
		return true;  
		}


	private void createconfirm( Request breq, PrintWriter out, String name )
		throws IOException
		{
		FacilityList fl;
		Facility f;
		Connection con=null;
		Group group;
		String notify=null;
		ResourceTree tree=null;
		Resource new_resource=null;
		boolean completed=false;
		BuildingContext context = BuildingContext.getContext();
		
		if ( !BuildingContext.getContext().checkPermission( "create" ) )
			{
			out.println( "<PRE>You don't have permission to create resources here.</PRE>\n" );
			return;
			}

		
		
//		if ( !name.equalsIgnoreCase( "communication" ) )
//			{
//			out.println( "<HR>Unable to create requested type of facility.<HR>" );
//			return;
//			}

		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>Problem finding user.<HR>" );
			return;
			}


		fl=FacilityList.getFacilities();
		if ( fl==null )
			{
			out.println( "<HR>Problem finding facilities.<HR>" );
			return;
			}
		f=fl.get( name );
			
		if ( f==null )
			{
			out.println( "<HR>Unable to create this type of resource.<HR>" );
			return;
			}
	        
	        try
		{
			String url, title, description, introduction, str;
			boolean parentacl;
			
			url=breq.getParameter( "url" );
			if ( url == null || url.length()<1 )
				{
				out.println( "<HR>Unable to create new location - you must supply a name.<HR>" );
				out.println( "Please use the backtrack facility of your browser to return to the form." );
				return;
				}
			if ( url.length()>12 )
				{
				out.println( "<HR>Unable to create new location - name is more than 12 characters.<HR>" );
				out.println( "Please use the backtrack facility of your browser to return to the form." );
				return;
				}
			if (url.charAt(0) == '_')
			{
			    out.println("<HR>The first character of the resource name cannot be an underscore<HR>");
			    out.println( "Please use the backtrack facility of your browser to return to the form." );
			    return;
			}
			for ( int i=0; i<url.length(); i++ )
				{
				char c=url.charAt( i );
				if ( c>='0' && c<='9' )
					continue;
				if ( c>='a' && c<='z' )
					continue;
				if ( c != '_' )
					{
					out.println( "<HR>Unable to create new location - the name contains invalid characters.<HR>" );
					out.println( "Please use the backtrack facility of your browser to return to the form." );
					return;
					}
				}
			
			title=breq.getParameter( "title" );
			description=breq.getParameter( "description" );
			introduction=breq.getParameter( "introduction" );
			notify=breq.getParameter( "notify" );
			if ( title==null || description==null || introduction==null )
				{
				out.println( "<HR>Unable to create new location - one or more of the boxes was left blank.<HR>" );
				out.println( "Please use the backtrack facility of your browser to return to the form." );
				return;
				}
			title=title.trim();
			description=description.trim();
			introduction=introduction.trim();

			if ( title.length()==0 || description.length()==0 || introduction.length()==0 )
				{
				out.println( "<HR>Unable to create new location - one or more of the boxes was left blank.<HR>" );
				out.println( "Please use the backtrack facility of your browser to return to the form." );
				return;
				}

			str = breq.getParameter( "parentacl" );
			parentacl = str!=null && str.equalsIgnoreCase( "yes" );

			if ( !f.createCheck( breq, out ) )
				{
				out.println( "<BR>Please use the backtrack facility of your browser to return to the form." );
				return;
				}


			Enumeration enum = breq.getResource().findChildren();
			Resource child;
			while ( enum.hasMoreElements() )
				{
				child = (Resource) enum.nextElement();
				if ( child.getName().equals( url ) )
					{
					out.println( "<HR>Unable to create new location - an item already exists here with the a name the same as the one you specified for the new item.<HR>" );
					out.println( "<BR>Please use the backtrack facility of your browser to return to the form." );
					return;
					}
				}


			//do general location creation stuff
			
			tree = ResourceTree.getInstance();
			
			synchronized ( tree )
				{
      			new_resource=f.newResource();
	    		new_resource.setName( url );
	    		new_resource.setTitle( title );
	    		new_resource.setDescription( description );
	    		new_resource.setIntroduction( introduction );
	    		new_resource.setHttpFacilityNo( f.id.intValue() );
	    		new_resource.setUseParentAcl( parentacl );

				if ( !f.initResource( breq, new_resource ) )
					{
					out.println( "<HR>Unable to initialise new resource.<HR>" );
					out.println( "<BR>Please use the backtrack facility of your browser to return to the form and try again." );
					return;
					}
				
				con=context.getConnection();
				//may need to rollback after several
				//operations
				con.setAutoCommit( false );
	    		tree.addResource( breq.getResource(), new_resource );
      			//tree.updateIndices();
       			//tree.saveAll();

				//specific creation stuff
				if ( !f.create( breq, con, new_resource ) )
					{
					out.println( "<HR>Unable to create supporting data for new resource.<HR>" );
					throw new BuildingServerException( "Problem creating resource specific data in database." );
					}

				con.commit();
				completed=true;
				out.println( "<CENTER><B>New resource created O.K.</B></CENTER><HR>" );
				
				con.setAutoCommit( true );
				}
				
			
			// mustn't attempt to get a session inside the synchronized section because
			// this could cause deadlock.  
			
			// create metadata record
   		try
   			{
	   		BuildingSession session = BuildingSessionManagerImpl.getSession( new_resource );
				session.updateBasicMetadata( title, description );
				}
			catch ( BuildingServerException bsex )
				{
				logException( out, "Facility", "createConfirm", 
				    "Unable to save the associated metadata for the newly created item.",
				    bsex );
				}
			}
		catch ( Exception ex )
			{
			out.println( "<HR>Unable to create resource.<HR>" + ex );
			logException( out, "Facility", "createConfirm", 
			    "Unable to create resource.",
			    ex );
			//just drop through;
			}

		if ( !completed )
			{
			try
				{
				if ( tree!=null && new_resource!=null )
					{
					tree.removeResource( new_resource );
      				//tree.updateIndices();
       				//tree.saveAll();
       				}
				}
			catch ( Exception ex )
				{
				out.println( "<HR>A problem occured cleaning up after the failure to create the resource.  " +
							"A 'phantom' resource may appear in the list of resources.<HR>" + ex );
				//just drop through;
				}

			try
				{
				if ( con!=null )
					con.rollback();
				}
			catch ( SQLException sqlex )
				{
				out.println( "<HR>Unable to roll back database operations.<HR>" + sqlex );
				//just drop through;
				}
			}

		}


	private void confirmmodify( Request breq, PrintWriter out )
		throws IOException
		{
		int n;
		//Connection con=null;
		//Statement statement;
		Resource resource, parent, otherresource;
		ResourceTree tree;
		String serv, sql;

        if ( breq.getTemplateParameterCount() > 0 )
        {
            out.println( "<HR>The resource was NOT modified because the web address of the 'modify resource' " +
                         "page you came from is invalid.  This may have happened because you already changed " +
                         "the resource and you backtracked to an out-of-date page.  Please use the navigation " +
                         "bar to exit from here and review what changes have been made.<HR>" );
            return;
        }
        
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
			{
			out.println( "<PRE>You don't have permission to modify this location.</PRE>\n" );
			return;
			}
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>Problem finding user.<HR>" );
			return;
			}


		try
			{
			resource = BuildingContext.getContext().getResource();
			tree = ResourceTree.getInstance();

			String url, title, description, introduction;
			url=breq.getParameter( "url" );
			if ( url==null ) url="";
			else url=url.trim();
			if ( url.length()<1 )
				{
				out.println( "<HR>Unable to modify location - you must supply a name.<HR>" );
				return;
				}
			if ( url.length()>12 )
				{
				out.println( "<HR>Unable to modify location - name is more than 12 characters.<HR>" );
				return;
				}
			for ( int i=0; i<url.length(); i++ )
				{
				char c=url.charAt( i );
				if ( c>='0' && c<='9' )
					continue;
				if ( c>='a' && c<='z' )
					continue;
				if ( c != '_' )
					{
					out.println( "<HR>Unable to modify location - the name contains invalid characters.<HR>" );
					return;
					}
				}
			
			//test new url to see if it exists
			parent = resource.getParent();
			if ( parent!=null )
				{
				String new_full_name = parent.getFullName() + url + "/";
				otherresource = tree.findResource( new_full_name );
				if ( otherresource!=null && otherresource!=resource )
					{
					out.println( "<HR>Unable to modify location - the name is already in use.<HR>" );
					return;
					}
				}
			
			title=breq.getParameter( "title" ).trim();
			description=breq.getParameter( "description" ).trim();
			introduction=breq.getParameter( "introduction" ).trim();

			if ( title.length()==0 || description.length()==0 || introduction.length()==0 )
				{
				out.println( "<HR>Unable to modify location - there must be text for title, description and introduction.<HR>" );
				return;
				}
			
			resource.setName( url );
			resource.setTitle( title );
			resource.setIntroduction( introduction );
			resource.setDescription( description );
			resource.save();
			
			// modify metadata record
   		try
   			{
	   		BuildingSession session = BuildingSessionManagerImpl.getSession( breq.getResource() );
				session.updateBasicMetadata( title, description );
				}
			catch ( BuildingServerException bsex )
				{
				logException( out, "Facility", "confirmmodify", 
				    "Unable to save the metadata: " +bsex.getMessage(),
				    bsex );
				}
			
			out.print( 
				"<CENTER><B>Location modified O.K.</B><BR>The pages " +
				"you are looking at may not reflect the new URL of the " +
				" location.  To be safe select <A TARGET=_top HREF=\"" );
			out.print( breq.getContextPath() );
			out.print( breq.getServletPath() );
			out.print( resource.getFullName() );
			out.println( "\">this link</A> to reload all frames.</CENTER><HR>" );
				
			return;
			}
		catch ( BuildingServerException bex )
			{
			out.println( "<HR>Unable to modify resource due to technical problem.<HR>" );
			}
		catch ( NumberFormatException nfex )
			{
			out.println( "<HR>Unable to modify resource due to invalid ordinal.<HR>" );
			}
/*
		try
			{
			if ( con!=null )
				con.rollback();
			}
		catch ( SQLException sqlex )
			{
			out.println( "<HR>Unable to roll back edits.<HR>" + sqlex );
			//just drop through;
			}
*/
		}


              /**
               * Gets and sets release date properties and fields for this resource via the insert method. <p>
               * <i>(WebLearn; A Corfield 02/12/2003)</i>
               */
                private void releaseDate( Request breq, PrintWriter out, String name )
                        throws IOException
                    {
                      Resource resource = null;
                      java.util.Date openDate = null, closeDate = null;
                      String open_date = null, close_date = null;

                      try {
                        resource = BuildingContext.getContext().getResource();
                      } catch (BuildingServerException bex) {
                        out.println("<HR>Unable to modify resource due to technical problem - resource not found<HR>");
                        return;
                      }


                      if (name.equalsIgnoreCase("open_field")) {
                        openDate = resource.getOpenDate();
                        if (openDate == null)
                          open_date = "none";
                        else
                          open_date = org.bodington.util.DateFormatter.formatDate(openDate, 2);
                        out.print("<INPUT NAME=\"open_date\" VALUE=\"");
                        out.print(open_date);
                        out.println("\">");
                        return;
                      }

                      if (name.equalsIgnoreCase("close_field")) {
                        closeDate = resource.getCloseDate();
                        if (closeDate == null)
                          close_date = "none";
                        else
                          close_date = org.bodington.util.DateFormatter.formatDate(closeDate, 2);
                        out.print("<INPUT NAME=\"close_date\" VALUE=\"");
                        out.print(close_date);
                        out.println("\">");
                        return;
                      }



                      if (name.equalsIgnoreCase("set")) {
                        if (!BuildingContext.getContext().checkPermission("manage")) {
                          out.println(
                              "<PRE>You don't have permission to modify this location.</PRE>\n");
                          return;
                        }

                        if (!breq.isAuthenticated()) {
                          out.println("<HR>Problem finding user.<HR>");
                          return;
                        }
                        try {
                          boolean openOk = false, closeOk = false;
                          java.sql.Timestamp openTimestamp = null, closeTimestamp = null;

                          open_date = breq.getParameter("open_date");
                          if (open_date != null && open_date.length() > 0) {
                            open_date = open_date.trim();
                            if (open_date.equalsIgnoreCase("none"))
                              openOk = true;
                            else {
                              openDate = org.bodington.servlet.DateParser.parseDateAndTime(
                                  open_date);
                              if (openDate != null) {
                                openTimestamp = new java.sql.Timestamp(openDate.getTime());
                                open_date = org.bodington.util.DateFormatter.formatDate(openDate,
                                    2);
                                openOk = true;
                              }
                            }
                          }

                          close_date = breq.getParameter("close_date");
                          if (close_date != null && close_date.length() > 0) {
                            close_date = close_date.trim();
                            if (close_date.equalsIgnoreCase("none"))
                              closeOk = true;
                            else {
                              closeDate = org.bodington.servlet.DateParser.parseDateAndTime(
                                  close_date);
                              if (closeDate != null) {
                                closeTimestamp = new java.sql.Timestamp(closeDate.getTime());
                                close_date = org.bodington.util.DateFormatter.formatDate(
                                    closeDate, 2);
                                closeOk = true;
                              }
                            }
                          }

                          if (openTimestamp != null && closeTimestamp != null &&
                              closeTimestamp.compareTo(openTimestamp) < 1) {
                            openOk = false;
                            closeOk = false;
                          }

                          if (! (openOk && closeOk)) {
                            if (openTimestamp != null && closeTimestamp != null)
                              out.print("<hr>Unable to modify location - the close date and time must be later than the open date");
                            else
                              out.print("<hr>Unable to modify location - the date and time may not have been formatted corectly");
                            if (!openOk)
                              out.print("<BR>open date: " + open_date);
                            if (!closeOk)
                              out.print("<BR>close date: " + close_date);
                            out.print("<BR>Enter the date and time as <B>dd/mm/yy hh:mm</B> or \"none\" if no date is set<hr>");
                            return;
                          }

                          resource.setOpenTimestamp(openTimestamp);
                          resource.setCloseTimestamp(closeTimestamp);
                          resource.save();

                          out.print(
                              "<CENTER><B>Location modified O.K.</B> Select <A TARGET=_top HREF=\"");
                          out.print(breq.getContextPath());
                          out.print(breq.getServletPath());
                          out.print(resource.getFullName());
                          out.print("\">this link</A> to reload all frames.</CENTER>");

                          if (openTimestamp == null && closeTimestamp == null) {
                            out.print("<BR>This resource will always be available - neither an open time nor a close time has been set.");
                          }
                          else {
                            if (closeTimestamp == null)
                              out.print("<BR>This resource will be available from " + open_date +
                                        " - no close time has been set.");
                            else if (openTimestamp == null)
                              out.print("<BR>This resource is available until " + close_date +
                                        " - no open time has been set.");
                            else
                              out.print("<BR>This resource will be available from " + open_date +
                                        " until " + close_date + ".");
                            if (openTimestamp != null &&
                                openTimestamp.getTime() <= System.currentTimeMillis())
                              out.print("<BR><B>N.B.</B> The open date has already passed.");
                            if (closeTimestamp != null &&
                                closeTimestamp.getTime() <= System.currentTimeMillis())
                              out.print("<BR><B>N.B.</B> The close date has already passed.");
                          }

                        }
                        catch (BuildingServerException bex) {
                          out.println(
                              "<HR>Unable to modify resource due to technical problem.<HR>");
                        }
                        catch (NumberFormatException nfex) {
                          out.println("<HR>Unable to modify resource due to invalid ordinal.<HR>");
                        }
                      }
                        }


/*
	private void notifyform( Request breq, PrintWriter out )
		throws IOException
		{
		String sql;
		ResultSet results;
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't choose notification settings.<HR>" );
			return;
			}
		
		UserEventLocation ueloc=new UserEventLocation( breq.string_user_id, breq.getResource().getResourceId().intValue(), 0 );
		
		
		sql="SELECT id, user_id, location, detail FROM " + DBObject.schema + "user_event_locations " +
			"WHERE (user_id = '" +
			breq.string_user_id +
			"' AND location = (" +
			breq.getResource().getResourceId() +
			") )";
		try
			{
			results=db.select( sql );
			if ( results!=null )
				if ( results.next() )
					ueloc.load( results );
			
			out.println( "<FORM METHOD=POST ACTION=notifylevel.html>" );
			out.print( "<INPUT NAME=detail TYPE=RADIO VALUE=0 " );
			if ( ueloc.detail==0 )
				out.print( "CHECKED" );
			out.println( ">No Notification<BR>" );
			out.print( "<INPUT NAME=detail TYPE=RADIO VALUE=1 " );
			if ( ueloc.detail==1 )
				out.print( "CHECKED" );
			out.print( ">Notification of Important Events<BR>" );
			out.print( "<INPUT NAME=detail TYPE=RADIO VALUE=2 " );
			if ( ueloc.detail==2 )
				out.print( "CHECKED" );
			out.println( ">Detailed Notification<BR>" );
			out.println( "<INPUT TYPE=SUBMIT VALUE=Set></FORM>" );
			
			}
		catch ( Exception ex )
			{
			out.println( "<HR>There was a technical problem trying to read the current setting.<HR>" + ex );
			}
			
		}
	

	private void confirmnotify( Request breq, PrintWriter out )
		throws IOException
		{
		String sql;
		String strdetail=breq.getParameter( "detail" );
		ResultSet results;
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't view notification settings." );
			return;
			}

		UserEventLocation ueloc=new UserEventLocation( breq.string_user_id, breq.getResource().getResourceId().intValue(), 0 );
		
		sql="SELECT id, user_id, location, detail FROM " + DBObject.schema + "user_event_locations " +
			"WHERE (user_id = '" +
			breq.string_user_id +
			"' AND location = (" +
			breq.getResource().getResourceId().intValue() +
			") )";
		try
			{
			results=db.select( sql );
			if ( results!=null )
				if ( results.next() )
					ueloc.load( results );
			
			if ( strdetail==null )
				{
				out.print( "Current setting: " );
				if ( ueloc.detail==0 )
					out.print( "No Notification" );
				if ( ueloc.detail==1 )
					out.print( "Notification of Important Events" );
				if ( ueloc.detail>=2 )
					out.print( "Detailed Notification" );
				return;
				}
			
			ueloc.detail=Integer.parseInt( strdetail );
			
			Connection con=db.getConnection();
			con.setAutoCommit( true );
			
			if ( ueloc.id==0 )
				ueloc.insert( con );
			else
				ueloc.update( con );

			out.print( "Notification Setting Changed." );
			}
		catch ( Exception ex )
			{
			out.println( "<HR>There was a technical problem trying to read the current setting.<HR>" + ex );
			}
		}
*/

/*
	private void templateeditform( Request breq, PrintWriter out, String link )
		throws IOException
		{
		String sql;
		ResultSet results;
		String url=breq.getParameter( "url" );
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't choose notification settings.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "sysadmin" ) )
		    {
			out.println( "<HR>You need sysadmin access to edit templates.<HR>" );
			return;
		    }
		
		if ( url==null || url.length()==0 )
		    {
			out.println( "<HR>You need to specify the name of the template.<HR>" );
			return;
		    }
		
		    
		HtmlTemplate template;
		try
			{
			template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = " + breq.getResource().getHttpFacilityNo() +
						" AND name = '" + url +
						"' AND resource_id = " + breq.getResource().getResourceId().toString()	);
			if ( template==null )
				template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = " + breq.getResource().getHttpFacilityNo() +
						" AND name = '" + url + "'" );
			if ( template==null )
				template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = 1" +
						" AND name = '" + url + "'" );

			if ( template==null )
		    	{
		    	out.println( "The specified template wasn't found." );
		    	return;
		    	}

	    	out.println( "Facility ID: " + template.getHttpFacilityNo() + "<BR>" );
	    	out.println( "Name: " + template.getName() + "<BR>" );
			if ( template.getResourceId()!=null )
		    	out.println( "Resource ID: " + template.getResourceId() + "<BR>" );
			    
			out.print( "<FORM METHOD=POST ACTION=\"" );
			out.print( link );
			out.print( ".html\"><INPUT TYPE=HIDDEN NAME=url VALUE=\"" );
			out.print( template.getName() );
			out.println( "\">" );
			out.print( "<TEXTAREA COLS=60 ROWS=30 NAME=html>" );
			out.print( template.getString() );
			out.println( "</TEXTAREA><INPUT TYPE=SUBMIT VALUE=Save></FORM>" );
			}
		catch ( BuildingServerException bsex )
			{
			out.println( "Technical problem fetching template<HR>" + bsex.toString() );
			return;
			}
		}
		
	private void templateeditconfirm( Request breq, PrintWriter out )
		throws IOException
		{
		String sql, oldhtml;
		String url=breq.getParameter( "url" );
		String html=breq.getParameter( "html" );
		
		
		if ( !breq.isAuthenticated() )
			{
			out.println( "<HR>You haven't checked in to the building so you can't choose notification settings.<HR>" );
			return;
			}
		
		if ( !BuildingContext.getContext().checkPermission( "sysadmin" ) )
		    {
			out.println( "<HR>You need sysadmin access to edit templates.<HR>" );
			return;
		    }
		
		if ( url==null || url.length()==0 )
		    {
			out.println( "<HR>You need to specify the name of the template.<HR>" );
			return;
		    }

		if ( html==null )
		    {
			out.println( "<HR>No HTML was specified.<HR>" );
			return;
		    }

		HtmlTemplate template;
		try
			{
			template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = " + breq.getResource().getHttpFacilityNo() +
						" AND name = '" + url +
						"' AND resource_id = " + breq.getResource().getResourceId().toString()	);
			if ( template==null )
				template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = " + breq.getResource().getHttpFacilityNo() +
						" AND name = '" + url + "'" );
			if ( template==null )
				template = HtmlTemplate.findHtmlTemplate( 
						"http_facility_no = 1" +
						" AND name = '" + url + "'" );

			if ( template==null )
		    	{
		    	out.println( "The specified template wasn't found." );
		    	return;
		    	}


        	template.setString( html );
			template.save();
			out.print( "Template edits saved." );
			}
		catch ( BuildingServerException bsex )
			{
			out.println( "Technical problem fetching template<HR>" + bsex.toString() );
			return;
			}
		}
*/
	
	public boolean willAcceptFacility( Facility f )
		{
		return false;
		}
	
	
	private void moveconfirm( Request breq, PrintWriter out )
		throws IOException
		{
		String item, dst;
		Resource srcres, itemres;
		int n;
		Connection con=null;
		ResourceTree tree;
		Resource dstres;

        
        if ( breq.getTemplateParameterCount() > 0 )
        {
            out.println( "<HR>The resource was NOT moved because it seems the destination resource has been " +
                         "changed while you were filling in the form.  Please use the navigation bar to reset " +
                         "your view onto the location where you want to move resources.<HR>" );
            return;
        }        
        
		try
			{
			tree = ResourceTree.getInstance();
			dstres = BuildingContext.getContext().getResource();

			Logger.getLogger("org.bodington").fine( "moveconfirm() A" );
			

			Logger.getLogger("org.bodington").fine( "moveconfirm() A" );

			
			item=breq.getParameter( "source" );
			dst=breq.getParameter( "destination" );
			
			if ( dst!=null )
				{
				out.println( "<HR>Moving objects by pushing is no longer supported.<HR>" );
				return;
				}
			
			if ( item==null )
				{
				out.println( "<HR>Item to be moved must be specified.<HR>" );
				return;
				}

			if ( !item.endsWith( "/" ) )
				item= item + "/";
			if ( !item.startsWith( "/" ) )
				item= "/" + item;
			if ( item.length() < 3 )
				{
				out.println( "<HR>Name too short.<HR>" );
				return;
				}
				
			Logger.getLogger("org.bodington").fine( "moveconfirm() B" );
			

			itemres=tree.findResource( item );

			if ( itemres==null )
				{
				out.println( "<HR>The item you want to move wasn't found.<HR>" );
				return;
				}

			srcres=itemres.getParent();

			if ( srcres==null )
				{
				out.println( "<HR>The source location you specified wasn't found.<HR>" );
				return;
				}
			if ( dstres==null )
				{
				out.println( "<HR>The destination location you specified wasn't found.<HR>" );
				return;
				}


			// does the destination facility accept this type of facility?
			// (e.g. you can't put a discussion room inside an MCQ test paper)
			FacilityList fl = FacilityList.getFacilities();
			Facility dstfac = fl.get( new Integer( dstres.getHttpFacilityNo() ) );
			Facility itemfac = fl.get( new Integer( itemres.getHttpFacilityNo() ) );
			if ( !dstfac.willAcceptFacility( itemfac ) )
				{
				out.println( "<HR>The destination location cannot contain the type of resource you want to move.<HR>" );
				return;
				}

			if ( !itemres.checkPermission( Permission.MANAGE ) )
				{
				out.println( "<HR>You don't have management permission for the item to be moved.<HR>\n" );
				return;
				}
			if ( !dstres.checkPermission( Permission.CREATE ) )
				{
				out.println( "<HR>You don't have creation permission for the destination location.<HR>\n" );
				return;
				}

			// we have to check whether dstloc is 'inside' itemloc
			if ( dstres.isInside( itemres ) )
				{
				out.println( "<HR>The destination location you specified is inside the item being moved.<HR>" );
				return;
				}

			Enumeration enum = dstres.findChildren();
			Resource child;
			while ( enum.hasMoreElements() )
				{
				child=(Resource)enum.nextElement();
				if ( child.getName().equals( itemres.getName() ) )
					{
					out.println( "<HR>The destination location already contains an item with the same name as the item you are trying to move.<HR>" );
					return;
					}
				}


			
			tree.moveResource( dstres, itemres );
			out.println( "The requested item was moved.<HR>" );
			return;
			}
		catch ( BuildingServerException bex )
			{
			out.println( "<HR>There was an unexpected problem moving the item.<HR>\n" + bex );
			}

		return;
		}

	
    /**
     * Makes a copy of an existing Resource. 
     * It is possible to copy a resource to the same location as the original, and multiple copies can be made.<br />
     * If a resource already exists at the destination location with the same name as the resource to be copied,
     *  a number is appended to the duplicated resource name (which is truncated if necessary).<br />
     * Request parameters are used to set the number of copies to be made, and whether to copy child resources,
     *  access permissions, content and uploaded files. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i>
     * @param breq The building HTTP request, which is used to determine which type of content to copy.
     * @param out A Print writer, to display messages to the user interface.
     */
	private void copyconfirm( Request breq, PrintWriter out )
//	    throws IOException
	    {
        if ( breq.getTemplateParameterCount() > 0 )
        {
            out.println( "<HR>The resource was NOT copied because it seems the destination resource has been " +
                         "changed while you were filling in the form.  Please use the navigation bar to reset " +
                         "your view onto the location where you want to copy resources.<HR>" );
            return;
        }            
        
        
         if ( copy_in_progress )
	     {
	       out.println( "<hr /><p>A copy operation is in progress on this web site and another cannot be started until it has completed.</p><hr />" );
	       return;
	     }
            
            
	     String sourceURL;
	     Resource original, new_resource, destination;
	     ResourceTree tree;
	     FacilityList facilityList;
	     Facility facility;
	     int multiple_copies;

	     Logger.getLogger("org.bodington").fine( "starting copyconfirm()" );

	     sourceURL=breq.getParameter( "source" );

	     if ( breq.getParameter( "destination" )!=null )
	     {
	       out.println( "<HR>Moving objects by pushing is no longer supported.<HR>" );
	       return;
	     }

	     if ( sourceURL==null )
	     {
	       out.println( "<HR>Item to be copied must be specified.<HR>" );
	       return;
	     }

	     if ( !sourceURL.endsWith( "/" ) )
	       sourceURL= sourceURL + "/";
	     if ( !sourceURL.startsWith( "/" ) )
	       sourceURL= "/" + sourceURL;
	     if ( sourceURL.length() < 3 )
	     {
	       out.println( "<HR>Name too short.<HR>" );
	       return;
	     }

	     try
	     {
	       BuildingContext context = BuildingContext.getContext();
	       destination = context.getResource();

	       facilityList = FacilityList.getFacilities();
	       if ( facilityList==null )
	       {
	        out.println( "<HR>Problem finding facilities.<HR>" );
	        return;
	       }

	       tree = ResourceTree.getInstance();
	       original=tree.findResource( sourceURL );

	       if ( original==null )
	       {
	        out.println( "<HR>The item you want to copy wasn't found.<HR>" );
	        return;
	       }

	       if ( destination==null )
	       {
	        out.println( "<HR>The destination location wasn't found.<HR>" );
	        return;
	       }

	       if ( destination.isInside( original ) )
	       {
		 out.println( "<HR>The destination location you specified is inside the item being copied.<HR>" );
		 return;
	       }

	       if ( destination.equals( original ) )
	       {
		 out.println( "<HR>The destination location you specified is inside the item being copied and is not allowed.<BR>");
		 out.println( " If you have a query about this, then please contact the Administrator or Help Desk for this web site.<HR>" );
		return;
	       }

	       Facility dstfac = facilityList.get( new Integer( destination.getHttpFacilityNo() ) );
	       facility = facilityList.get( new Integer( original.getHttpFacilityNo() ) );
	       if ( !dstfac.willAcceptFacility( facility ) )
	       {
	        out.println( "<HR>The destination location cannot contain the type of resource you want to copy.<HR>" );
	        return;
	       }

           if ( !original.checkPermission( Permission.MANAGE ) )
	       {
	        out.println( "<HR>You don't have management permission for the item to be copied.<HR>\n" );
	        return;
	       }
	       if ( !destination.checkPermission( Permission.CREATE ) )
	       {
	        out.println( "<HR>You don't have creation permission for the destination location.<HR>\n" );
	        return;
	       }

           // JRM added check for resources that can't be copied.
           if ( !facility.canCopy( original ) )
           {
	        out.println( "<HR>The selected resource is of a type that cannot be copied.<HR>" );
	        return;               
           }
           if ( "true".equalsIgnoreCase( breq.getParameter("recursive") ) &&
                !facility.canCopyWithChildren( original ) )
           {
	        out.println( "<HR>The selected resource contains one or more resources that cannot be copied because you don't have manage access or they are of a type that cannot be copied.<HR>" );
	        return;               
           }
           
           // JRM added sanity check for resource to be copied
           if ( "true".equalsIgnoreCase( breq.getParameter("recursive") ) )
           {
               int descendents = tree.countDescendents( original.getResourceId() );
               if ( descendents<0 )
               {
    	        out.println( "<HR>Error determining how many resources need to be copied.<HR>" );
                return;               
               }
               if ( descendents>100 )
               {
    	        out.println( "<HR>You opted to copy resources inside the selected resource but there are too many (>100).<HR>" );
                return;               
               }
           }

           
	     }

	     catch ( BuildingServerException ex )
	     {
	       out.println( "<HR>Unable to copy resource (Copying not started)<HR>" + ex );
	       logException( out, "Facility", "copyConfirm",
			    "Unable to copy resource.", ex );
	       return;
	     }

	     try
	     {

	       Logger.getLogger("org.bodington").fine( "copyconfirm(), starting to copy resources... " );

	       Vector names = new Vector();
	       String name = original.getName();
	       String append = "";
	       int start = 2;

           // JRM - added checks to user input here in case a different template
           // form is used in the future and in case some user puts together their
           // own form to make a denial of service attack.
           try
           {
               multiple_copies=Integer.parseInt(breq.getParameter( "multiple" ));
           }
           catch ( NumberFormatException nfe )
           {
               out.println( "Unable to determine the number of copies of resource to make." );
	           logException( out, "Facility", "copyConfirm",
			        "Unable to determine the number of copies of resource to make.", nfe );
	           return;
           }
           
           if ( multiple_copies<1 )
           {
               out.println( "Unable to determine the number of copies of resource to make." );
               Logger.getLogger( "org.bodington" ).severe( "Unable to determine the number of copies of resource to make." );
	           return;               
           }
           if ( multiple_copies>20 )
           {
               out.println( "Unable to make that many copies." );
               Logger.getLogger( "org.bodington" ).severe( "Unable to make that many copies." );
	           return;               
           }
           
           
             
	       Enumeration enum = destination.findChildren();

	       while ( enum.hasMoreElements() )
	         names.add( ((Resource)enum.nextElement()).getName() );

	       for ( int i = 1; i <= multiple_copies; i++ )
	       {
	        while ( names.contains( name + append ) )
	        {
	         append = Integer.toString( start++ );
	         if ( (name+append).length() > 12 )
	           name = name.substring( 0, 12-append.length() );
	        }

            // impossible for two threads to enter this block of code
            synchronized ( copy_synch )
            {
                try
                {
                    copy_in_progress = true;
                    copyResource( original, destination, breq, name + append, out );
                }
                finally
                {
                    copy_in_progress = false;                
                }
            }

	        append = Integer.toString( start++ );
	        if ( (name+append).length() > 12 )
	          name = name.substring( 0, 12-append.length() );

            if ( multiple_copies>1 )
            {
                out.println( "<p><em>Completed " + i + (i==1?"copy":"copys") + ".</em></p>" );
                out.flush();
            }
           }

            if ( multiple_copies>1 )
                out.println( "<hr /><p><strong>All copies completed.</strong></p>" );
            else
                out.println( "<hr /><p><strong>New resource/s copied O.K.</strong></p>" );
	     }

	     catch ( BuildingServerException ex )
	     {
	       out.println( "<HR><CENTER>Error in attempting to copy resource:</CENTER>" );
	       logException( out, "Facility", "copyConfirm",
			    "Error in attempting to copy resource.", ex );
	     }
	}


    /**
     * Recursively creates a new Resource and copies required properties, 
     * children, content, etc. Used by {@link #copyconfirm(Request, PrintWriter)}. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i> <br />
     * <i>(WebLearn modification. Modified: 16/02/2004 Colin Tatham)</i>
     * @param original The resource to be copied.
     * @param destination The resource which will be the parent of the newly created resource.
     * @param breq The building HTTP request, which is used to determine which type of content to copy.
     * @param name The name to be used for the new resource (or null if the name is to be copied from the original.)
     * @param out A Print writer, to display messages to the user interface.
     * @exception BuildingServerException Thrown if there is any problem copying the resource.
     */
	private void copyResource( Resource original, Resource destination, Request breq, String name, PrintWriter out )
	        throws BuildingServerException
	        {
	         ResourceTree tree = null;
	         BuildingContext context = BuildingContext.getContext();
	         FacilityList facilityList = FacilityList.getFacilities();
	         Facility facility = facilityList.get( new Integer( original.getHttpFacilityNo() ) );
	         Resource new_resource = null;
	         Connection con = null;
	         String message;

	         try
	         {
	          tree = ResourceTree.getInstance();
	          synchronized ( tree ) // some comments copied from createconfirm() method...
	          {
	           new_resource = facility.newResource();
               new_resource.setZoneId( original.getZoneId() ); // added JRM
	           if ( name==null )
	             name = original.getName();
	           new_resource.setName( name );
	           new_resource.setTitle( original.getTitle() );
	           new_resource.setDescription( original.getDescription() );
	           new_resource.setIntroduction( original.getIntroduction() );
	           new_resource.setHttpFacilityNo( original.getHttpFacilityNo() );
               new_resource.setHttpUIStyle( original.getHttpUIStyle() );
               new_resource.setHasCustomMenu( original.getHasCustomMenu() ); // added JRM

               // initResource sets fields in subclass of Resource BEFORE saving it.
	           //new version of initResource(), takes original as arg:
	           facility.initResource( original, new_resource );

	           con = context.getConnection();
	           //may need to rollback after several operations
	           con.setAutoCommit( false );
	           tree.addResource( destination, new_resource );
	           //tree.updateIndices();
	           //tree.saveAll();

	           //specific creation stuff
	           /** @todo OK to take this out? Only used by PermissionFacility. 
                * May be needed for other facilities.  This is called after resource
                * record has been saved and is used to create other supporting records
                * that are specific to the facility subclass.
                */
	           if ( !facility.create( breq, con, new_resource ) )
	             out.println( "<HR>Unable to create supporting data for new resource.<HR>" );

	           con.commit();
	           con.setAutoCommit( true );
	          }
	         }
	         catch ( Exception ex )
	         {
	          message = "Resource creation failed, ";
	          try
	          {
	           tree.removeResource( new_resource );
	           //tree.updateIndices();
	           //tree.saveAll();
	           con.rollback();
	          }
	          catch ( Exception ex2 )
	          {
	           message += "unable to roll back database operations.";
	           Logger.getLogger( "org.bodington" ).severe( message );
	           throw new BuildingServerException(ex.getMessage(), message );
	          }
	          message += "database rolled back.";
	          Logger.getLogger( "org.bodington" ).severe( message );
	          throw new BuildingServerException(ex.getMessage(), message  );
	         }

	         if ( breq.getParameter("permissions") != null )
	           copyAccessPermissions( original, new_resource, out );

	         if ( breq.getParameter("uploaded") != null )
	           copyUploadedContent( original, new_resource, out);

             // copy authored content and user data:
	         try
	         {
	          facility.copyContent( original, new_resource, breq );
	         }
	         catch (BuildingServerException ex)
	         {
	          message = "Error copying content for: "+ new_resource.getName();
	          // using getFullName() could throw another exception...
	          out.print( "<HR>"+ message +"<BR>"+ ex.getMessage());
	          Logger.getLogger( "org.bodington" ).warning( message + ex.getMessage() );
	         }

	         // create metadata record
	         try
	         {
	          BuildingSession session = BuildingSessionManagerImpl.getSession( new_resource );
	          session.updateBasicMetadata( new_resource.getTitle(), new_resource.getDescription() );
	         }
	         catch ( Exception ex )// BuildingServerException, RemoteException
	         {
	          out.print( "<HR>Unable to save the associated metadata for the newly created item.");
	         }

	         if ( breq.getParameter("recursive").equalsIgnoreCase("true") )
	         {
	          Enumeration enum = original.findChildren();
	          while ( enum.hasMoreElements() )
	          {
	           Resource child = (Resource)enum.nextElement();
		   if ( !child.equals(new_resource) )
	           try
	           {
	            copyResource( child, new_resource, breq, null, out );
	           }
	           catch (BuildingServerException ex)
	           {
	            message = "Error copying child resource: "+ child.getName();
	            out.print( "<HR>"+ message +"<BR>"+ ex.friendlyMessage());
	            Logger.getLogger( "org.bodington" ).severe( message + ex.getMessage() );
	           }
	          }
	         }

	}


    /**
     * Copies uploaded files from one resource to another. Used by 
     * {@link #copyconfirm(Request, PrintWriter)}. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i> <br />
     * <i>(WebLearn modification. Modified: 16/02/2004 Colin Tatham)</i>
     * @param original The resource with uploaded files to be copied.
     * @param new_resource The resource to add the uploaded files to.
     * @param out A Print writer, to display messages to the user interface.
     */
	private void copyUploadedContent( Resource original, Resource new_resource, PrintWriter out )
    {
        try
        {
            BuildingSession orig_session = BuildingSessionManagerImpl.getSession( original );
            BuildingSession new_session = BuildingSessionManagerImpl.getSession( new_resource );
            UploadedFileSummary[] summaries = orig_session.getFileAndDescendentSummaries( null, true );
            UploadedFile f;
            String path_to_source_in_os, name_rel_to_res, mime_type;
            File source_filestore = original.getWebPublishFolder();
            File source;
            
            //  better to fix the fault in BuildingSessionImpl - done
            //createRootFolder( new_resource );//shouldn't be necessary, see method for notes:

            // there a simpler way to work out the paths using
            // convenient methods in UploadedFile and Resource
            for ( int i = 0; i < summaries.length; i++ )
            {
                f = UploadedFile.findUploadedFile(summaries[i].getUploadedFileId());
                // don't copy deleted files and folders!
                if ( f==null || f.isDeleted() )
                    continue;

                mime_type = f.getMimeType();
                // this is the actual file
                source = new File( source_filestore, f.getRealNameInResource() );
                path_to_source_in_os = source.getAbsolutePath();
                // Bodington style relative name is same for source and destination
                name_rel_to_res = f.getNameInResource();


                if ( f.isFolder() )
                    new_session.createFolder( name_rel_to_res );
                else
                    new_session.copyFile( path_to_source_in_os, name_rel_to_res, mime_type );
            }

            // don't forget to copy custom menu file if there is one.....
            if ( original.getHasCustomMenu() )
            {
                String source_gen_path = original.getGeneratedFileAddress();
                new_session.transferResourceMenu( source_gen_path + "menu.xml" );
            }
        
        }
        catch ( Exception ex ) // BuildingServerException and RemoteException
        {
            Logger.getLogger( "org.bodington" ).logp( 
                Level.SEVERE, 
                "Facility", 
                "copyUploadedContent", 
                ex.getMessage(), 
                ex );
            String message = "Error copying uploaded files for : "+ new_resource.getName();
            out.print( "<HR>"+ message +"<BR>"+ ex.getMessage());
        }
	}


    /**
     * Copies the access permissions from one resource to another. Used by 
     * {@link #copyconfirm(Request, PrintWriter)}. <p>
     * <i>(WebLearn modification (method added): 02/12/2003 Colin Tatham)</i>
     * @param original The resource with permissions to be copied.
     * @param new_resource The resource whose premissions are to be modified.
     * @param out A Print writer, to display messages to the user interface.
     */
	private void copyAccessPermissions( Resource original, Resource new_resource, PrintWriter out )
		{
		 try
		 {
		  Acl acl, new_acl;
		  AclEntry entry, new_entry;
		  Group group, new_group, owner_group, new_ownergroup;
          String name, local_name, new_name;
          int offset;
		  User user;
          Enumeration members;

		  new_resource.setUseParentAcl( original.getUseParentAcl() );
		  new_resource.save();

		  acl = original.getAcl();
		  new_acl = new_resource.getAcl();

          // copy local groups if not already done
          Vector copy_groups = new Vector();
          Enumeration groups = Group.findGroups( "resource_id = " + original.getResourceId() );
          while ( groups.hasMoreElements() )
          {
              group = (Group)groups.nextElement();
              name = group.getName();
              if ( !name.startsWith( "localgroup." ) ) continue;
              offset = name.indexOf( '.' );
              offset = name.indexOf( '.', offset+1 );
              local_name = name.substring( offset+1 );
              
              new_name = "localgroup." + new_resource.getResourceId() + "." + local_name;
              
              // exists already?
              new_group = Group.findGroup( "resource_id = " + new_resource.getResourceId() + " AND name = " + SqlDatabase.quotedSQL( new_name ) );
              // no, needs to be created.
              if ( new_group == null )
              {
                new_group = new Group();
                new_group.setResourceId( new_resource.getResourceId() );
                new_group.setName( new_name );
                new_group.setDescription( group.getDescription() );
                new_group.save();                  
              }
              
              if ( !"owners".equals( local_name ) )
              {
                copy_groups.addElement( group );
                copy_groups.addElement( new_group );
              }
          }
          
          // copy members of local groups but exluding owners group
          for ( int i=0; i<copy_groups.size(); i+=2 )
          {
              group = (Group)copy_groups.elementAt( i );
              new_group = (Group)copy_groups.elementAt( i+1 );
		      members = group.checkedMembers();
		      while ( members.hasMoreElements() )
		      {
		       user = (User)members.nextElement();
		       new_group.addMember( user );
		      }
		      new_group.save();
          }
          
          // now copy acl entries taking care to make localgroup
          // references point to local groups of new resource.
          
		  Enumeration entries = acl.entries();

		  while ( entries.hasMoreElements() )
		  {
		    entry = (AclEntry)entries.nextElement();
            group = entry.getGroup();
            name = group.getName();
            if ( name.startsWith( "localgroup." ) )
            {
                offset = name.indexOf( '.' );
                offset = name.indexOf( '.', offset+1 );
                local_name = name.substring( offset+1 );
                new_name = "localgroup." + new_resource.getResourceId() + "." + local_name;
                new_group = Group.findGroup( "resource_id = " + new_resource.getResourceId() + " AND name = " + SqlDatabase.quotedSQL( new_name ) );
            }
            else
                new_group = group;
            
		     new_entry = new AclEntry();
		     new_entry.setGroup( new_group );
		     new_entry.setPermissionCoded( entry.getPermissionCoded() );
		     new_entry.setAcl( new_acl );
		     new_entry.save();
		     new_acl.addEntry( new_entry );
		    
		  }
		  new_acl.save();
		 }
		 catch ( Exception ex ) //BuildingServerException and java.security.acl.NotOwnerException
		 {
		   String message = "Error copying access permissions for : "+ new_resource.getName();
		   out.print( "<HR>"+ message +"<BR>"+ ex.getMessage());
		   Logger.getLogger( "org.bodington" ).warning( message + ex.getMessage() );
		 }
	}


	private void deleteconfirm( Request breq, PrintWriter out )
		throws IOException
		{
		//String item, dst;
		Resource srcres, itemres;
		int n;
		Connection con=null;
		ResourceTree tree;
		Resource dstres;
		String confirm1, confirm2;
		
                if ( breq.getTemplateParameterCount() > 0 )
                {
                    out.println( "<HR>No resource was deleted because the web address of the 'delete resource' " +
                                 "page you came from is invalid.  This may have happened because you already deleted " +
                                 "the resource and you backtracked to an out-of-date page.  Please use the navigation " +
                                 "bar to exit from here.<HR>" );
                    return;
                }
                
		confirm1 = breq.getParameter( "confirm1" );
		confirm2 = breq.getParameter( "confirm2" );
		if ( confirm1==null || !confirm1.equalsIgnoreCase( "yes" ) ||
			(confirm2!=null && confirm2.equalsIgnoreCase( "yes" ) )   )
			{
			out.println( "<HR>Resource was not deleted because you didn't confirm without doubt your intention to delete.<HR>" );
			return;
			}
			
		out.flush();
		
		try
			{
			Enumeration enum = Resource.findResources( "http_facility_no = 30", "left_index" );
			if ( !enum.hasMoreElements() || (dstres=(Resource)enum.nextElement())==null )
				{
				out.println( "<HR>Unable to locate the recycling building.<HR>" );
				return;
				}
			itemres = breq.getResource();
			srcres = itemres.getParent();
			if ( srcres == null )
				{
				out.println( "<HR>Unable to delete resource because it is the root resource of the site.<HR>" );
				return;
				}
			
			
			tree = ResourceTree.getInstance();

			Logger.getLogger("org.bodington").fine( "moveconfirm() A" );
			

			Logger.getLogger("org.bodington").fine( "moveconfirm() B" );

			
			if ( !itemres.checkPermission( Permission.MANAGE ) )
				{
				out.println( "<HR>You don't have management permission for the item to be deleted.<HR>\n" );
				return;
				}
			if ( !dstres.checkPermission( Permission.CREATE ) )
				{
				out.println( "<HR>You don't have permission to put things in the recycle building so you can't delete resources.<HR>\n" );
				return;
				}

			// we have to check whether dstloc is 'inside' itemloc
			if ( dstres.isInside( itemres ) )
				{
				out.println( "<HR>The resource you want to delete contains the recycle building to you can't delete it..<HR>" );
				return;
				}


			//change name to avoid clashes
			itemres.setName( itemres.getResourceId().toString() );
			itemres.save();

			//To do...
			
			//remove all groups other than owners from ACL
			
			//remove all "notification" flags so noone gets events anymore?????
			
			
			//check for clashes anyway
			enum = dstres.findChildren();
			Resource child;
			while ( enum.hasMoreElements() )
				{
				child=(Resource)enum.nextElement();
				if ( child.getName().equals( itemres.getName() ) )
					{
					out.println( "<HR>The destination location already contains an item with the same name as the item you are trying to move.<HR>" );
					return;
					}
				}


			
			tree.moveResource( dstres, itemres );
			
			out.println( "The current resource was moved and so its web address has changed.<HR>" );

			out.print( 
				"<HR><CENTER><B>Location deleted O.K.</B><BR>The pages " +
				"you are looking at are now no longer valid." +
				" Select <A TARGET=_top HREF=\"" );
			out.print( breq.getContextPath() );
			out.print( breq.getServletPath() );
			out.print( srcres.getFullName() );
			out.println( "\">this link</A> to move out to the containing resource. " + 
				"Please DO NOT use the backtrack facility of your browser.</CENTER><HR>" );
			return;
			}
		catch ( BuildingServerException bex )
			{
			out.println( "<HR>There was an unexpected problem deleting the item.<HR>\n" + bex );
			}

		return;
		}


	private void ifloggedin( Request breq )
		throws IOException
		{
		breq.setSwitchedOff(  !breq.isAuthenticated() );
		return;
		}

	private void ifaccess( Request breq, String name )
		throws IOException
		{
		breq.setSwitchedOff(  !BuildingContext.getContext().checkPermission( name ) );
	}

	public boolean hasPermission( String name )
		throws IOException
            {
		return BuildingContext.getContext().checkPermission( name );
            }

	private void ifcanreorder( Request breq )
		throws IOException
		{
		BuildingContext context;
		Resource resource;
		context = BuildingContext.getContext();
		int i;
		
		if ( !BuildingContext.getContext().checkPermission( "manage" ) )
			{
			breq.setSwitchedOff( true );
			return;
			}
		
		try
			{
			resource = context.getResource();
			Enumeration enum=resource.findChildren();
			for ( i=0; enum.hasMoreElements(); i++ )
				{
				enum.nextElement();
				}
			
			breq.setSwitchedOff(  (i<2) );
			}
		catch ( BuildingServerException bsex )
			{
			breq.setSwitchedOff( true );
			}

		return;
		}


	public void variable( Request breq, PrintWriter out, String name )
		throws IOException
	    {
		variable( breq, out, name, false );
	    }   
	
	private void variable( Request breq, PrintWriter out, String name, boolean form )
		throws IOException
		{
		if ( out == null )
		    return;
		
		Resource resource;
		try
			{
			resource = BuildingContext.getContext().getResource();
		
		    TextareaWriter t_out = new TextareaWriter( out );
		
			if ( name.equalsIgnoreCase( "url" ) )
				{
				if ( resource.getName()!=null )
					out.print( resource.getName() );
				return;
				}
			if ( name.equalsIgnoreCase( "ordinal" ) )
				{
				//if ( breq.location.ordinal!=null )
				//	out.print( breq.location.ordinal.toString() );
				return;
				}
			if ( name.equalsIgnoreCase( "title" ) )
				{
				/*
				NavigationSessionImpl session = (NavigationSessionImpl)BuildingSessionManagerImpl.getSession( NavigationSessionImpl.class );
				if ( session.resourceTitle()!=null )
					{
					session.setResource( breq.getResource() );
					out.print( session.resourceTitle() );
					}
				*/
				if ( resource.getTitle()!=null )
				    {
				    if ( form )
					    t_out.print( resource.getTitle() );
					else
					    out.print( resource.getTitle() );
					}
				return;
				}
			if ( name.equalsIgnoreCase( "description" ) )
				{
				if ( resource.getDescription()!=null )
				    {
				    if ( form )
    					t_out.print( resource.getDescription() );
    			    else
    					out.print( resource.getDescription() );
					}
				return;
				}
			if ( name.equalsIgnoreCase( "introduction" ) )
				{
				if ( resource.getIntroduction()!=null )
				    {
				    if ( form )
    					t_out.print( resource.getIntroduction() );
    	            else
    					out.print( resource.getIntroduction() );
    	            }
				return;
				}
			if ( name.equalsIgnoreCase( "nameofuser" ) && breq.isAuthenticated() )
				{
				User user = (User)BuildingContext.getContext().getUser();
				if ( user!=null && user.getName()!=null )
				    {
				    out.print( user.getName() );
				    }
				return;
				}
			if ( name.equalsIgnoreCase( "resource_id" ) )
				{
				if ( breq.getResource().getResourceId()==null )
			    	out.print( "No resource id for this location." );
				else
					out.print( "Resource id = " + breq.getResource().getResourceId() );
				return;
				}
			if ( name.substring( 0, 4 ).equalsIgnoreCase( "type" ) )
				{
				
    			if ( name.equalsIgnoreCase( "typeca" ) )
    			    {
    			    out.print( getTitle( true, true ) );
    			    return;
    			    }
    			if ( name.equalsIgnoreCase( "typea" ) )
    			    {
    			    out.print( getTitle( false, true ) );
    			    return;
    			    }
    			if ( name.equalsIgnoreCase( "typec" ) )
    			    {
    			    out.print( getTitle( true, false ) );
    			    return;
    			    }

   			    out.print( getTitle( false, false ) );
				return;
				}
			if ( name.equalsIgnoreCase( "zone_name" ) )
				{
				Zone zone = breq.getResource().getEffectiveZone();
				if ( zone == null )
			    	out.print( "(<I>undefined</I>)" );
				else
					out.print( zone.getName() );
				return;
				}
			}
		catch ( BuildingServerException bsex )
			{
			return;
			}
		out.print( "<! unknown insert>" );
		}

	
	private void reordercontrol( Request breq, PrintWriter out )
		throws IOException
		{
		BuildingContext context;
		Resource resource, current;
		context = BuildingContext.getContext();
		
		try
			{
			resource = context.getResource();
		    Enumeration enum=resource.findChildren();
			for ( int i=0; enum.hasMoreElements(); i++ )
				{
				current=(Resource)enum.nextElement();

				if ( !current.checkPermission( Permission.SEE ) )
					continue;

				out.print( "<OPTION VALUE=\"" );
				out.print( current.getResourceId().toString() );
				out.print( "\"" );
				if ( i==0 )
					out.print( " SELECTED" );
				out.print( ">" );
				out.print( current.getTitle() );
				out.println( "</OPTION>" );
				}
			}
		catch ( BuildingServerException bsex )
			{
			return;
			}
		}
    	
	private void reorder( Request breq, PrintWriter out )
		throws IOException
		{
		BuildingContext context;
		Resource resource, current;
		context = BuildingContext.getContext();
		
		Vector key_list = new Vector();
		String strrid;
		int r;
		PrimaryKey key;
		String list=breq.getParameter( "thelist" );
		StringTokenizer tok = new StringTokenizer( list, "," );
		while ( tok.hasMoreTokens() )
			{
			strrid = tok.nextToken();
			try
				{
				r = Integer.parseInt( strrid );
				}
			catch ( Exception ex )
				{
				continue;
				}
			key = new PrimaryKey( r );
			key_list.addElement( key );
			}
			
		try
			{
			resource = context.getResource();
			resource.sortChildren( key_list );
			ResourceTree tree = ResourceTree.getInstance();
			//tree.updateIndices();
			//tree.saveAll();

			out.println( "<H4>Confirmation</H4>" );
			out.println( "<P>Resources have been put in the following order:</P>" );
			out.println( "<UL>" );
			for ( int i=0; i<key_list.size(); i++ )
				{
				current=Resource.findResource( (PrimaryKey)key_list.elementAt( i ) );

				if ( current==null )
					continue;

				out.print( "<LI>" );
				out.print( current.getTitle() );
				out.println( "</LI>" );
				}
			out.println( "</UL>" );
			}
		catch ( BuildingServerException bsex )
			{
			out.println( "<P>There was a technical problem attempting to reorder resources</P><HR>" );
			out.println( bsex.toString() );
			return;
			}
		}
/*
	private void reorder_old_nbb( Request breq, PrintWriter out, Resource resource )
		throws IOException
		{
		BuildingContext context;
		Resource current;
		context = BuildingContext.getContext();
		
		Vector key_list = new Vector();
		PrimaryKey key;
			
		try
			{
			Connection con = context.getConnection();
			Statement st = con.createStatement();
			ResultSet r = st.executeQuery( 
				"SELECT resource_id FROM resources r, building.dbo.locations l " +
				"WHERE r.resource_id *= (l.id + 10097637) AND parent_resource_id = " +
				resource.getResourceId().toString() +
				" ORDER BY ordinal, l.title" );

			while ( r.next() )
				{
				key = new PrimaryKey( r.getInt( 1 ) );
				key_list.addElement( key );
				}
			r.close();
			st.close();


			resource.sortChildren( key_list );
			ResourceTree tree = resource.getResourceTree();
			tree.updateIndices();
			tree.saveAll();

			out.println( "<H4>Confirmation</H4>" );
			out.println( "<P>Resources have be put in the following order:</P>" );
			out.println( "<UL>" );
			for ( int i=0; i<key_list.size(); i++ )
				{
				current=Resource.findResource( (PrimaryKey)key_list.elementAt( i ) );

				if ( current==null )
					continue;

				out.print( "<LI>" );
				out.print( current.getTitle() );
				out.println( "</LI>" );
				}
			out.println( "</UL>" );
			
			
			//now recurse into children.....
			for ( int i=0; i<key_list.size(); i++ )
				{
				current=Resource.findResource( (PrimaryKey)key_list.elementAt( i ) );
				if ( current==null )
					continue;
				
				reorder_old_nbb( breq, out, current );
				}
			}
		catch ( Exception bsex )
			{
			out.println( "<P>There was a technical problem attempting to reorder resources</P><HR>" );
			out.println( bsex.toString() );
			return;
			}
		}
*/

	public void enableStylesheets( Request breq, boolean enable )
	throws ServletException
	{
	    org.bodington.servlet.HttpSession http_session = (org.bodington.servlet.HttpSession)breq.getSession( false );
	    if ( http_session == null )
		return;

	    StyleSheetSessionData sss_data = this.getStyleSheetSessionData( http_session );
	    
	    sss_data.enable_style_sheets = enable;
	    
	}
	
	private void stylesheet( Request breq, PrintWriter out )
		throws IOException, ServletException
		{
                out.print( "<link href=\"bs_virtual_auto.css\" type=\"text/css\" rel=\"stylesheet\">" );
		}
		
			
			
    protected void resourceMenuItem( Object gen_item, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int highlight )
        throws IOException, BuildingServerException {

      if (gen_item instanceof MenuItem) {
        MenuItem item = (MenuItem) gen_item;
        resourceMenuItem(item, breq, out, state, depth, highlight);
      }
      else if (gen_item instanceof Resource) {
        Resource resource = (Resource) gen_item;
        Facility facility = state.fl.get(new Integer(resource.getHttpFacilityNo()));
        facility.resourceMenuItem(resource, breq, out, state, depth, highlight);
      }

  //          else ?
    }

    protected void resourceMenuItem(MenuItem menu_item, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int highlight)

		throws IOException, BuildingServerException
		{
//                MenuItem item=null;
//                Resource resource=null;
//                Facility facility;
//                Template template;
                String href=null, icon_src=null, title=null, target=null;
                boolean italic=false;  // should really use a redefinable style
                boolean is_heading = false;
                boolean manage = false;
                boolean deny = false;

//                if ( gen_item instanceof MenuItem )
//                    item = (MenuItem)gen_item;
//                if ( gen_item instanceof Resource )
//                    resource = (Resource)gen_item;

                // determine href
                if ( menu_item!=null )
			{
                    href = menu_item.getHRef();
                    target = state.target;
                    if ( menu_item.getType().equals( "container" ) )
                        icon_src = state.folder_url;
                    else
                        icon_src = state.file_url;
                    title = menu_item.getTitle();
                }


                // heading level for title line matches depth but there are only
                // six heading levels in HTML so stop there.
                int hlevel = (depth>6)?6:depth;
                int level = ((depth-1)%10)+1;


                // title in heading with appropriate class attribute
                out.print( "          <h" );
                out.print( hlevel );
                if ( is_heading )
                    out.print( " class=\"" + state.css_class_prefix + "_heading_node_title\">" );
                else
                {
                    out.print( " class=\"" + state.css_class_prefix + "_node_title_lev" );
                    out.print( level );
                    out.print( "\">" );
                }

		// optional link around whole title (inc. icon)
		if ( href != null && !is_heading )
                    {
                    out.print( "<a" );
			if ( target!=null )
				{
                        out.print( " target=\"" );
				out.print( target );
				out.print( "\"" );
				}
                    out.print( " href=\"" );
                    out.print( href );
			out.print( "\">" );
			}

                if ( is_heading )
                    out.print( "<strong>" );
		else
                {
					/*
					 * WebLearn modification [26/01/05] Alexis O'Connor.
					 * Renders more accurate / accessible value for alt attribute.
					 */	                
                    out.print( "<img alt=\"Icon for a ");
                    out.print( menu_item.getType().equals("container") ? "Folder" : "File" );
                    out.print( ".\" src=\"");
                    // <<<--- WebLearn modification.
                    out.print( icon_src );
                    out.print( "\" " );

                    if ( depth==1 )
                        out.print( "class=\"" + state.css_class_prefix + "_node_icon_without_stalk\" />" );
                    else
                        out.print( "class=\"" + state.css_class_prefix + "_node_icon_no_expander\" />" );

                    // span is used to get everything on one line in browsers that
                    // lack CSS but CSS redfines as block.
                    out.print( "<span class=\"" + state.css_class_prefix + "_node_content" );
                    if ( depth==1 )
                        out.print( "_without_stalk" );
                    out.print( "_lev" );
                    out.print( level );
                    out.print( "_hl" );
                    out.print( highlight );
                    out.print( "\">" );
                }


                if ( italic )
                    out.print( "<i>" );

		if ( title != null )
                    out.print( title );
		else
                    if ( href != null )
                        out.print( href );
			else
                        out.print( "{untitled item}" );

                if ( italic )
                    out.print( "</i>" );

                // headings have link after title
		if ( href != null && is_heading && manage )
                    {
                    out.print( "<a" );
                    if ( target!=null )
                        {
                        out.print( " target=\"" );
                        out.print( target );
                        out.print( "\"" );
                        }
                    out.print( " href=\"" );
                    out.print( href );
                    out.print( "\" alt=\"Manage heading.\">&gt;</a>" );
                    }

                if ( is_heading )
                    out.print( "</strong>" );
                else
                    out.print( "</span>" );

		if ( href != null && !is_heading )
                    out.print( "</a>" );

                out.print( "</h" );  // end of node_title
                out.print( hlevel );
                out.println( ">" );

                // files have no further content in the node.
                // but resources have descriptions or introductions

                // amendment - if big icons files have an empty content section
                // to take up space next to icon and prevent next (floating)
                // icon coming up next to current one.

//                if ( resource != null || state.big_icons )
                if ( state.big_icons )
                {
                    String content;
//                    if ( resource != null )
//                    {
//                        if ( !state.rootless && depth==1  )
//                            content = resource.getIntroduction();
//                        else
//                            content = resource.getDescription();
//                        if ( deny )
//                            content = "<em>You are not included on the access list for this item.</em><br />" + content;
//		}
//                    else
                        content = "&nbsp;";

                    if ( content.length()>0 )
		{
                        out.print( "<div class=\"" + state.css_class_prefix + "_node_content" );
                        if ( depth==1 )
                            out.print( "_without_stalk" );
                        out.print( "_lev" );
                        out.print( level );
                        out.print( "_hl" );
                        out.print( highlight );
                        out.print( "\">" );

                        out.print( content );

                        out.print( "</div>" );
                    }
                }
                out.print( "<div class=\"clearer\">&nbsp;</div>\n");
            }

      protected void resourceMenuItem(Resource resource, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int highlight)

                        throws IOException, BuildingServerException
                        {
                        MenuItem item=null;
//                        Resource resource=null;
                        Facility facility;
                        Template template;
                        String href=null, icon_src=null, title=null, target=null;
                        boolean italic=false;  // should really use a redefinable style
                        boolean is_heading = false;
                        boolean manage = false;
                        boolean deny = false;
                        
                        java.util.Date openDate, closeDate;
                        String available_date;


//                        if ( gen_item instanceof MenuItem )
//                            item = (MenuItem)gen_item;
//                        if ( gen_item instanceof Resource )
//                            resource = (Resource)gen_item;

                        // determine href
                        if ( item!=null )
                                {
                            href = item.getHRef();
                            target = state.target;
                            if ( item.getType().equals( "container" ) )
                                icon_src = state.folder_url;
                            else
                                icon_src = state.file_url;
                            title = item.getTitle();
                }
                        else if ( resource!=null )
                        {
                            is_heading = resource.getResourceType() == Resource.RESOURCE_HEADING;
                            if ( is_heading )
                                manage = resource.checkPermission( Permission.MANAGE );
                            href = ( !state.rootless && depth==1  )?null:
                                ( breq.getContextPath() +breq.getServletPath() + resource.getFullName() );
                            target = "_top";
                            // using getTemplateGifUrl doesn't work for descendant resources - need to
                            // reference proper resource.
                            facility = state.fl.get( new Integer( resource.getHttpFacilityNo() ) );
                            if ( facility!=null )
                            {
                                template = Template.get( facility.facilityname, resource.getImplicitHttpUIStyle(), resource.getResourceId(), state.big_icons?"icon.gif":"iconsmall.gif" );
                                if ( template != null )
                                    icon_src = breq.getContextPath() + state.gif_url + template.getUrl() + state.colour_code;
                    }
                            title = resource.getTitle();
                            if ( !resource.checkPermission( Permission.VIEW ) )
                            {
                                if ( state.anon )
                                    // anonymous users are allowed to see link because
                                    // they get a message about logging in if they enter
                                    italic=true;
                                else
                                {
                                    // logged in but no access - don't give link
                                    href=null;
                                    deny = true;
                                }
                            }
                        }
                

                        // heading level for title line matches depth but there are only
                        // six heading levels in HTML so stop there.
                        int hlevel = (depth>6)?6:depth;
                        int level = ((depth-1)%10)+1;


                        // title in heading with appropriate class attribute
                        out.print( "          <h" );
                        out.print( hlevel );
                        if ( is_heading )
                            out.print( " class=\"" + state.css_class_prefix + "_heading_node_title\">" );
                        else
                        {
                            out.print( " class=\"" + state.css_class_prefix + "_node_title_lev" );
                            out.print( level );
                            out.print( "\">" );
                }

                        // optional link around whole title (inc. icon)
                        if ( href != null && !is_heading )
                            {
                            out.print( "<a" );
                                if ( target!=null )
                                        {
                                out.print( " target=\"" );
                                        out.print( target );
                                        out.print( "\"" );
                                        }
                            out.print( " href=\"" );
                            out.print( href );
                                out.print( "\">" );
                                }

                        if ( is_heading )
                            out.print( "<strong>" );
                        else
                        {
						   /*
					 		* WebLearn modification [26/01/05] Alexis O'Connor.
					 		* Renders more accurate / accessible value for alt attribute.
					 		*/	                
                            out.print( "<img alt=\"Icon for a " + resource.getResourceTypeName() + ".\" src=\"" );
                            // <<<--- WebLearn modification.
                            out.print( icon_src );
                            out.print( "\" " );

                            if ( depth==1 )
                                out.print( "class=\"" + state.css_class_prefix + "_node_icon_without_stalk\" />" );
                            else
                                out.print( "class=\"" + state.css_class_prefix + "_node_icon_no_expander\" />" );

                            // span is used to get everything on one line in browsers that
                            // lack CSS but CSS redfines as block.
                            out.print( "<span class=\"" + state.css_class_prefix + "_node_content" );
                            if ( depth==1 )
                                out.print( "_without_stalk" );
                            out.print( "_lev" );
                            out.print( level );
                            out.print( "_hl" );
                            out.print( highlight );
                            out.print( "\">" );
                        }


                        if ( italic )
                            out.print( "<i>" );

                        if ( title != null )
                            out.print( title );
                        else
                            if ( href != null )
                                out.print( href );
                                else
                                out.print( "{untitled item}" );

                        if ( italic )
                            out.print( "</i>" );

                        // headings have link after title
                        if ( href != null && is_heading && manage )
                            {
                            out.print( "<a" );
                            if ( target!=null )
                                {
                                out.print( " target=\"" );
                                out.print( target );
                                out.print( "\"" );
                                }
                            out.print( " href=\"" );
                            out.print( href );
                            out.print( "\" alt=\"Manage heading.\">&gt;</a>" );
                            }

                        if ( is_heading )
                            out.print( "</strong>" );
                        else
                            out.print( "</span>" );

                        if ( href != null && !is_heading )
                            out.print( "</a>" );

                        out.print( "</h" );  // end of node_title
                        out.print( hlevel );
                        out.println( ">" );

                        // files have no further content in the node.
                        // but resources have descriptions or introductions

                        // amendment - if big icons files have an empty content section
                        // to take up space next to icon and prevent next (floating)
                        // icon coming up next to current one.

                        if ( resource != null || state.big_icons )
                        {
                            String content;
                            if ( resource != null )
                            {
                                if ( !state.rootless && depth==1  )
                                    content = resource.getIntroduction();
                                else
                                    content = resource.getDescription();
                                if ( deny )
                                    content = "<em>You are not included on the access list for this item.</em><br />" + content;
                        }
                            else
                                content = "&nbsp;";

                            if ( content.length()>0 ) 
                        {
                                out.print( "<div class=\"" + state.css_class_prefix + "_node_content" );
                                if ( depth==1 )
                                    out.print( "_without_stalk" );
                                out.print( "_lev" );
                                out.print( level );
                                out.print( "_hl" );
                                out.print( highlight );
                                out.print( "\">" );

                                	out.print( content );

                                openDate = resource.getOpenDate();
                                closeDate = resource.getCloseDate();
                                if (! (openDate == null && closeDate == null)) {
                                  available_date = "<br>This resource is available";
                                  if (openDate != null)
                                    available_date += " from " +
                                        org.bodington.util.DateFormatter.formatDate(openDate, 2);
                                  if (closeDate != null)
                                    available_date += " until " +
                                        org.bodington.util.DateFormatter.formatDate(closeDate, 2);

                                  out.println(available_date);
                                }
                                out.print( "</div>" );
                                out.print( "<div class=\"clearer\">&nbsp;</div>\n");
                        }
                    }
                    }

    protected void resourceMenuItemChildren( Object gen_item, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int parent_highlight )
        throws IOException, BuildingServerException {

      if (gen_item instanceof MenuItem) {
        MenuItem item = (MenuItem) gen_item;
        resourceMenuItemChildren(item, breq, out, state, depth, parent_highlight);
      }

      else if (gen_item instanceof Resource) {
        Resource resource = (Resource) gen_item;
        Facility facility = state.fl.get(new Integer(resource.getHttpFacilityNo()));
        facility.resourceMenuItemChildren(resource, breq, out, state, depth,
                                          parent_highlight);
      }

  //          else ?
    }


      protected void resourceMenuItemChildren( Resource resource, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int parent_highlight )

		throws IOException, BuildingServerException
			{
		int i, highlight, level = ((depth-1)%10)+1;
                Menu menu;
                MenuItem item=null;
//                Resource resource=null, resource_child=null;
                Resource resource_child=null;
                Object gen_child=null;
		MenuItem child; //, sibling;
                Vector children=null, grandchildren=null;
                boolean child_has_visible_child_resources = false;
                boolean is_heading = false;
			
//                if ( gen_item instanceof MenuItem )
//                    item = (MenuItem)gen_item;
//                if ( gen_item instanceof Resource )
//                    resource = (Resource)gen_item;
                
                
                // start with interactive resource children
                if ( state.full && resource != null && (level<=state.recursion_depth) )
                    children = getVisibleChildResourcesForMenu( resource );
                else
                    children = new Vector();
                
		// menuitems for root only
                if ( resource != null && (state.rootless?depth==1:depth==2) )
				{
                    menu = state.session.getResourceMenu();
                    item = (MenuItem)menu.getRoot();
                }
		for ( i=0; item!=null && i<item.getChildCount(); i++ )
                {
                    children.addElement( item.getChildAt( i ) );
                }

                // return without outputting any tags if there are no elements
                // to display.
                if ( children.size()<1 )
                    return;
                
                StringBuffer indent = new StringBuffer( depth );
                for ( i=2; i<depth; i++ )
                    indent.append( "      " );
		
		// children go in a siblings set or whole tree
                if ( state.rootless && level == 1 )
                {
                    out.println( "<div class=\"" + state.css_class_prefix + "\">" );
                    if ( state.detached_root )
                    {
                        out.println( "  <div class=\"" + state.css_class_prefix + "_branch_border\">" );
                        out.println( "  <div class=\"" + state.css_class_prefix + "_header\">" );
                        out.println( "Where you can go from here" );
                        out.println( "  </div>" );
                        out.println( "  </div>" );
                    }
                }
				else
                {
                    out.print( indent );
                    out.print( "    <div class=\"" + state.css_class_prefix + "_siblings" );
                    if ( depth==2 )
                        out.print( "_without_stalk" );
                    out.println( "_lev" + level + "\">" );
				}

			
                for ( i=0; i<children.size(); i++ )
				{
                        child_has_visible_child_resources = false;
                        is_heading = false;
                        child=null;
                        resource_child=null;
                        gen_child = children.elementAt( i );
                        if ( gen_child instanceof MenuItem )
                            child = (MenuItem)gen_child;
                        if ( gen_child instanceof Resource )
					{
                            resource_child = (Resource)gen_child;
                            is_heading = resource_child.getResourceType() == Resource.RESOURCE_HEADING;
                            if ( (depth+1)>state.recursion_depth )
                                child_has_visible_child_resources=false;
					else
                            {
                                grandchildren = getVisibleChildResourcesForMenu( resource_child );
                                child_has_visible_child_resources = grandchildren.size()>0;
					}
				}
                        
			//highlight = (((state.root_highlight-1) ^ (depth-1) ^ i) & 1) + 1;
                        highlight = (((parent_highlight-1) ^ (i+1)) & 1) + 1;
			
                        // put every child in a branch
                        // (every branch in branch border)
                        out.print( indent );
			out.print( "      <div class=\"" + state.css_class_prefix + "" );
                        if ( (i+1)==children.size() ) //|| depth==1 )
                            out.print( "_end" );
                        out.println( "_branch_border\">" );
                        
                        out.print( indent );
			out.print( "      <div class=\"" + state.css_class_prefix + "" );
                        if ( (i+1)==children.size() ) //|| depth==1 )
                            out.print( "_end" );
                        out.print( "_branch_lev" );
                        out.print( level );
                        out.print( "_hl" );
                        out.print( highlight );
                        out.println( "\">" );
                        
                        // put every child other than headings in a node too
                        if ( !is_heading )
                        {
                            out.print( indent );
                            out.print( "        <div class=\"" + state.css_class_prefix + "_node_s" );
                            out.print( ( state.rootless && level == 1 )?"n":"y" );
                            out.print( "u" );
                            out.print( ( state.rootless && level == 1 )?"n":"y" );
                            out.print( "d" );
                            if ( state.rootless && level == 1 )
                                out.print( "n" );
                            else
                                out.print( ((i+1)<children.size())?"y":"n" );
                            out.print( "b" );
                            if ( resource_child!=null )
                                out.print( child_has_visible_child_resources?"y":"n" );
                            else
                                out.print( (child.getChildCount()>0)?"y":"n" );
                            out.print( "_lev" );
                            out.print( level );
                            out.print( "_hl" );
                            out.print( highlight );
                            out.println( "\">" );
			}
				
                        out.print( indent );
			resourceMenuItem( gen_child, breq, out, state, depth, highlight );

                        if ( !is_heading )
                            out.println( "        </div>" ); // end of node		
                        if ( resource_child!=null && (depth+1)<=state.recursion_depth )
                            resourceMenuItemChildren( resource_child, breq, out, state, depth+1, highlight );
                            
			if ( child!=null && child.getChildCount()>0 )
                            resourceMenuItemChildren( child, breq, out, state, depth+1, highlight );
			
                        out.println( "      </div>" ); // end of branch
                        out.println( "      </div>" ); // end of branch border
		}

                if ( !state.rootless || level != 1 )
                    out.print( "    <div class=\"" + state.css_class_prefix + "_siblings_padding\"></div>" );
		out.println( "    </div>" );  // end siblings or tree
		}

    protected void resourceMenuItemChildren( MenuItem menu_item, Request breq, PrintWriter out, ResourceMenuOutputState state, int depth, int parent_highlight )
                          throws IOException, BuildingServerException
                                  {
                          int i, highlight, level = ((depth-1)%10)+1;
                          Menu menu;
//                          MenuItem item=null;
//                          Resource resource=null, resource_child=null;
                          Resource resource_child = null;
                          Object gen_child=null;
                          MenuItem child; //, sibling;
                          Vector children=null, grandchildren=null;
                          boolean child_has_visible_child_resources = false;
                          boolean is_heading = false;

//                if ( gen_item instanceof MenuItem )
//                    item = (MenuItem)gen_item;
//                if ( gen_item instanceof Resource )
//                    resource = (Resource)gen_item;


                          children = new Vector();

                          // menuitems for root only
//                          if ( resource != null && (state.rootless?depth==1:depth==2) )
                          if ( state.rootless?depth==1:depth==2 )
                                          {
                              menu = state.session.getResourceMenu();
                              menu_item = (MenuItem)menu.getRoot();
                          }
                          for ( i=0; menu_item!=null && i<menu_item.getChildCount(); i++ )
                          {
                              children.addElement( menu_item.getChildAt( i ) );
                          }

                          // return without outputting any tags if there are no elements
                          // to display.
                          if ( children.size()<1 )
                              return;

                          StringBuffer indent = new StringBuffer( depth );
                          for ( i=2; i<depth; i++ )
                              indent.append( "      " );

                          // children go in a siblings set or whole tree
                          if ( state.rootless && level == 1 )
                          {
                              out.println( "<div class=\"" + state.css_class_prefix + "\">" );
                              if ( state.detached_root )
                              {
                                  out.println( "  <div class=\"" + state.css_class_prefix + "_branch_border\">" );
                                  out.println( "  <div class=\"" + state.css_class_prefix + "_header\">" );
                                  out.println( "Where you can go from here" );
                                  out.println( "  </div>" );
                                  out.println( "  </div>" );
                              }
                          }
                                          else
                          {
                              out.print( indent );
                              out.print( "    <div class=\"" + state.css_class_prefix + "_siblings" );
                              if ( depth==2 )
                                  out.print( "_without_stalk" );
                              out.println( "_lev" + level + "\">" );
                                          }

                        for (i = 0; i < children.size(); i++) {
                          child_has_visible_child_resources = false;
                          is_heading = false;
                          child = null;
                          resource_child = null;
                          gen_child = children.elementAt(i);
                          if (gen_child instanceof MenuItem)
                            child = (MenuItem) gen_child;
                          if (gen_child instanceof Resource) {
                            resource_child = (Resource) gen_child;
                            is_heading = resource_child.getResourceType() ==
                                Resource.RESOURCE_HEADING;
                            if ( (depth + 1) > state.recursion_depth)
                              child_has_visible_child_resources = false;
                            else {
                              grandchildren = getVisibleChildResourcesForMenu(resource_child);
                              child_has_visible_child_resources = grandchildren.size() > 0;
                            }
                          }

                          //highlight = (((state.root_highlight-1) ^ (depth-1) ^ i) & 1) + 1;
                          highlight = ( ( (parent_highlight - 1) ^ (i + 1)) & 1) + 1;

                          // put every child in a branch
                          // (every branch in branch border)
                          out.print(indent);
                          out.print("      <div class=\"" + state.css_class_prefix + "");
                          if ( (i + 1) == children.size()) //|| depth==1 )
                            out.print("_end");
                          out.println("_branch_border\">");

                          out.print(indent);
                          out.print("      <div class=\"" + state.css_class_prefix + "");
                          if ( (i + 1) == children.size()) //|| depth==1 )
                            out.print("_end");
                          out.print("_branch_lev");
                          out.print(level);
                          out.print("_hl");
                          out.print(highlight);
                          out.println("\">");

                          // put every child other than headings in a node too
                          if (!is_heading) {
                            out.print(indent);
                            out.print("        <div class=\"" + state.css_class_prefix + "_node_s");
                            out.print( (state.rootless && level == 1) ? "n" : "y");
                            out.print("u");
                            out.print( (state.rootless && level == 1) ? "n" : "y");
                            out.print("d");
                            if (state.rootless && level == 1)
                              out.print("n");
                            else
                              out.print( ( (i + 1) < children.size()) ? "y" : "n");
                            out.print("b");
                            if (resource_child != null)
                              out.print(child_has_visible_child_resources ? "y" : "n");
                            else
                              out.print( (child.getChildCount() > 0) ? "y" : "n");
                            out.print("_lev");
                            out.print(level);
                            out.print("_hl");
                            out.print(highlight);
                            out.println("\">");
                          }

                          out.print(indent);
                          resourceMenuItem(gen_child, breq, out, state, depth, highlight);

                          if (!is_heading)
                            out.println("        </div>"); // end of node

                          if (resource_child != null && (depth + 1) <= state.recursion_depth)
                            resourceMenuItemChildren(resource_child, breq, out, state, depth + 1,
                                                     highlight);

                          if (child != null && child.getChildCount() > 0)
                            resourceMenuItemChildren(child, breq, out, state, depth + 1, highlight);

                          out.println("      </div>"); // end of branch
                          out.println("      </div>"); // end of branch border
                        }

                          if ( !state.rootless || level != 1 )
                              out.print( "    <div class=\"" + state.css_class_prefix + "_siblings_padding\"></div>" );
                          out.println( "    </div>" );  // end siblings or tree
                          }

    // inner class used to pass some state information through recursive methods
    class ResourceMenuOutputState
    {
        int root_highlight;
        boolean rootless;
        boolean detached_root;
        boolean full;
        boolean anon;
        boolean big_icons;
        String css_class_prefix;
        int recursion_depth;
        String target;
        String gif_url;
        String file_url;
        String folder_url;
        String colour_code;
        NavigationSession session;
        FacilityList fl;
    }

    private Vector getVisibleChildResourcesForMenu( Resource resource )
        throws BuildingServerException
    {
        Vector children = new Vector();
        // can't see children if can't enter parent
        if ( !resource.checkPermission( Permission.VIEW ) )
            return children;
        
        Enumeration enum = resource.findChildren();
        while ( enum.hasMoreElements() )
        {
            resource = (Resource)enum.nextElement();
            if ( resource.checkPermission( Permission.SEE ) )
                children.addElement( resource );
        }
        return children;
    }
    
    public void fullResourceMenu(  Request breq, PrintWriter out )
		throws IOException
		{
            fullResourceMenu( breq, out, null );
    }
    // outputs integrated menu of interactive resources and uploaded files
    // including introductory text of requested resource
    public void fullResourceMenu(  Request breq, PrintWriter out, String target )
        throws IOException
    {
        try
        {
            resourceMenu( breq, out, true, target );
        }
        catch ( BuildingServerException e )
        {
            Logger.getLogger( "org.bodington" ).logp( 
                Level.SEVERE, 
                "Facility", 
                "resourceMenu", 
                e.getMessage(), 
                e );
            throw new IOException( e.getMessage() );
        }
    }

    // For compatibility with old templates this outputs just uploaded files.
    public void resourceMenu( Request breq, PrintWriter out )
        throws IOException
    {
        try
        {
            resourceMenu( breq, out, false,  null );
        }
        catch ( BuildingServerException e )
        {
            Logger.getLogger( "org.bodington" ).logp( 
                Level.SEVERE, 
                "Facility", 
                "resourceMenu", 
                e.getMessage(), 
                e );
            throw new IOException( e.getMessage() );
        }
    }
    

    // outputs menu of uploaded files and optionally interactive resources
    // so far output of interactive resources isn't implemented so full is
    // ignored.
    public void resourceMenu( Request breq, PrintWriter out, boolean full, String target )
        throws IOException, BuildingServerException
    {
        int i, max_depth=1;
		Menu menu;
		MenuItem item, child;
        Vector visible_children;
		
        try
        {
            ResourceMenuOutputState state = new ResourceMenuOutputState();
            state.full = full;
            state.root_highlight = 1;
            state.target = target;
            state.colour_code = this.getTemplateGifColourMapperCode( breq, "bodington_navigation_page" );
            state.gif_url = "/processedgif/templates";
            state.session = breq.getServerNavigationSession();
            String big_icons = state.session.getProperty( "ui_navigation_menu_big_icons", "no" );
            String prefered_big_icons = getAutomaticPreferenceByScreenSize( 
                                        breq, "preference.navigation.menu.big_icons", "no", big_icons );
            state.big_icons =  "yes".equalsIgnoreCase( prefered_big_icons );
            state.file_url = this.getTemplateGifUrl( breq, "bodington_navigation_page", state.big_icons?"bs_template_file.gif":"bs_template_file-small.gif", false );
            state.folder_url = this.getTemplateGifUrl( breq, "bodington_navigation_page", state.big_icons?"bs_template_folder.gif":"bs_template_folder-small.gif", false );
            state.css_class_prefix = state.big_icons?"res_tree_big":"res_tree";
            state.fl = FacilityList.getFacilities();
            state.anon = state.session.isAnonymous();

            String type = state.session.getProperty( "ui_navigation_menu_type", "plain" );
            String prefered_type = getPreference( breq, "preference.navigation.menu.type" );
            if ( "plain".equalsIgnoreCase( prefered_type ) || 
                 "attached".equalsIgnoreCase( prefered_type ) || 
                 "detached".equalsIgnoreCase( prefered_type )    )
                type = prefered_type;

            
            //boolean tree = "tree".equalsIgnoreCase( getPreference( breq, "preference.navigation.menu.tree" ) );
            boolean tree = "attached".equals( type );
            state.detached_root = "detached".equals( type );
            
            // resource property switches on recursion
            max_depth=1;
		try
			{
                String prop = state.session.getProperty( "ui_navigation_menu_ancestors", "1" );
                max_depth = Integer.parseInt( prop );
                if ( max_depth<1 ) max_depth = 1;
                if ( max_depth>5 ) max_depth = 5;
            }
            catch ( NumberFormatException nfe )
            {
                max_depth=1;
            }
            // but user can switch off
            if ( "suppress".equalsIgnoreCase( getPreference( breq, "preference.navigation.menu.ancestors" ) ) )
                max_depth=1;
			
            // suppress tree if old style files only menu
            if ( !full ) {tree = false; max_depth=1;}
			
            // actually this is just the uploaded files in the form of an
            // IMS style contents page or full file listing
            // it doesn't include interactive resources - should be integrated
            // some time.
            menu = state.session.getResourceMenu();
			item = (MenuItem)menu.getRoot();
            visible_children = getVisibleChildResourcesForMenu( breq.getResource() );

            // in tree mode the node representing the resource itself is shown.
            if ( tree )
            {
                state.recursion_depth = max_depth+1;  // add 1 to include root
                state.rootless = false;
                out.println( "<div class=\"" + state.css_class_prefix + "\">" );
                out.println( "  <div class=\"" + state.css_class_prefix + "_end_branch_border\">" );
                out.print( "  <div class=\"" + state.css_class_prefix + "_header\">" );
                out.print( "Where you are" );
                if ( item.getChildCount() > 0 || visible_children.size() > 0 )
                    out.print( " and where you can go from here" );
                out.println( "  </div>" );
                out.println( "  </div>" );
                out.println( "  <div class=\"" + state.css_class_prefix + "_end_branch_border\">" );
                out.println( "  <div class=\"" + state.css_class_prefix + "_end_branch_lev1_hl1\">" );
                out.println( "    <div class=\"" + state.css_class_prefix + "_node_snundnb" + 
                        ((item.getChildCount()>0 || !visible_children.isEmpty())?"y":"n") +
                        "_lev1_hl1\">" );
                resourceMenuItem( breq.getResource(), breq, out, state, 1, 1 );
                out.println( "    </div>" );
                // method will only output div elements if there is at least
                // one node to display
                resourceMenuItemChildren( breq.getResource(), breq, out, state, 2, 1 );
                out.println( "  </div>" );
                out.println( "  </div>" );
                out.println( "</div>" );
			}
            else
            // otherwise each top level item is output in its own tree.
            {
                state.recursion_depth = max_depth;
                if ( full )
                {
                    if ( state.detached_root )
                    {
                        out.println( "<div class=\"" + state.css_class_prefix + "\">" );
                        out.println( "  <div class=\"" + state.css_class_prefix + "_branch_border\">" );
                        out.println( "  <div class=\"" + state.css_class_prefix + "_header\">" );
                        out.println( "Where you are" );
                        out.println( "  </div>" );
                        out.println( "  </div>" );
                        out.println( "  <div class=\"" + state.css_class_prefix + "_end_branch_border\">" );
                        out.println( "  <div class=\"" + state.css_class_prefix + "_end_branch_lev1_hl1\">" );
                        out.println( "    <div class=\"" + state.css_class_prefix + "_node_snundnbn_lev1_hl1\">" );
                        resourceMenuItem( breq.getResource(), breq, out, state, 1, 1 );
                        out.println( "    </div>" );
                        // method will only output div elements if there is at least
                        // one node to display
                        out.println( "  </div>" );
                        out.println( "  </div>" );
                        out.println( "</div>" );
                        out.println( "<div style=\"height: 1em\"></div>" );
                    }
                    else
                    {
                        out.print( "<div class=\"bs-introduction\">" );
                        out.print( breq.getResource().getIntroduction() );
                        out.println( "</div>" );
                    }
                }
                state.rootless = true;
                // method will only output div elements if there is at least
                // one node to display
                resourceMenuItemChildren( breq.getResource(), breq, out, state, 1, 2 );
            }

        }
		catch ( BuildingServerException bsex )
			{
			logException( out, "Facility", "resourceMenu", 
			    "A technical problem occured.",
			    bsex );
			return;
			}

		}

         /**
         * Writes html anchor tag with href attribute that has username appended to query part of URL.
         * uhi:awc
         * @param breq The Building HTTP request.
         * @param out The PrintWriter.
         * @param url The url used by href attribute.
         * @param text The link text.
         */
        public void writeTemplateUsernameLoginTag( Request breq, PrintWriter out, String target, String url, String text)
                throws IOException
        {

            String loginUrl = getUsernameLoginUrl(breq, url);
            if (target != null && (target.length() == 0 || target.equalsIgnoreCase("null")))
                target = null;

            out.print( "<a ");

            if (target != null)
                out.print("target=\"" + target + "\" ");

            out.print("href=");
            out.print( "\"" + loginUrl + "\"" );
            out.print( ">" );
            out.print(text);
            out.print( "</a>" );
        }

	public void writeTemplateGifUrl( Request breq, PrintWriter out, String html_body_class, String name )
            throws IOException
        {
            String url = getTemplateGifUrl( breq, html_body_class, name );
            out.print( url );
        }

        public void writeTemplateGifTag( Request breq, PrintWriter out, String html_body_class, String tag, String name, String attributes )
            throws IOException
        {
            String url = getTemplateGifUrl( breq, html_body_class, name );
            out.print( "<" );
            out.print( tag );
            out.print( " " );
            out.print( attributes );
            out.print( " src=\"" );
            out.print( url );
            out.print( "\" />" );
        }
        
        public String getTemplateGifColourMapperCode( Request breq, String html_body_class )
        {
            String colour_mapper_code="";
        
            // style sheet data stored in http session has user's colour preferences
            org.bodington.servlet.HttpSession http_session = 
                (org.bodington.servlet.HttpSession)breq.getSession( false );
            NavigationSession nav_session = http_session.getServerNavigationSession();
                
            try
            {
                StyleSheetSessionData sss_data = this.getStyleSheetSessionData( http_session );
                ColourPreferenceMapper colour_mapper = sss_data.getUserColourPreferenceMapper( http_session );
                
                // get the id of the resource for which style is defined
                // (i.e. current resource or ancestor of current resource)
                PrimaryKey style_resource_id = nav_session.getStyleResourceId();
                Resource style_resource = nav_session.findResource( style_resource_id );
                Color f;
                Color b;
                if ( "bodington_navigation_page".equals( html_body_class ) )
                {
                    f = nav_session.getPropertyColor( style_resource, "style_navigation_graphic_foreground_colour", new Color( 0xeeeeee ) );
                    b = nav_session.getPropertyColor( style_resource, "style_navigation_graphic_background_colour", new Color( 0x111111 ) );
                }
                else
                {
                    f = nav_session.getPropertyColor( style_resource, "style_graphic_foreground_colour", new Color( 0xeeeeee ) );
                    b = nav_session.getPropertyColor( style_resource, "style_graphic_background_colour", new Color( 0x111111 ) );
                }
                colour_mapper.setReferenceColours( b, f );
                colour_mapper_code = "?code=" + colour_mapper.toString();
            }
            catch ( Exception ex )
            {
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "getTemplateGifColourMapperCode", 
                    ex.getMessage(), 
                    ex );
            }
                
            return colour_mapper_code;
        }
        
        public String getTemplateGifUrl( Request breq, String html_body_class, String name )
        {
            return getTemplateGifUrl( breq, html_body_class, name, false );
        }
        
        public String getTemplateGifUrl( Request breq, String html_body_class, String name, boolean rel_to_context )
        {
            if ( !name.startsWith( "bs_template_" ) )
                return name;

            
            BuildingContext context = BuildingContext.getContext();
            Resource resource = null;
            
            String colour_mapper_code="";
            Template template = null;
            
            try
            {
                // get colour mapper for resource properties and user prefs.
                colour_mapper_code = this.getTemplateGifColourMapperCode( breq, html_body_class );
                // get current resource
                resource = context.getResource();
                
                if ( resource == null )
                    return name;

                // template from current resource, not style root resource
                template = Template.get( 
                    this.facilityname, 
                    resource.getImplicitHttpUIStyle(), 
                    resource.getResourceId(), 
                    name.substring( "bs_template_".length() ) );
            }
            catch ( Exception ex )
            {
                Logger.getLogger( "org.bodington" ).logp( 
                    Level.SEVERE, 
                    "Facility", 
                    "getTemplateGifUrl", 
                    ex.getMessage(), 
                    ex );
            }
            
            if ( template == null )
                return name;
            
                
            StringBuffer rname = new StringBuffer( 128 );
            if ( !rel_to_context )
                rname.append( breq.getContextPath() );
            rname.append( "/processedgif/templates" );
            rname.append( template.getUrl() );
            rname.append( colour_mapper_code );
            
            return rname.toString();
        }
		
		
	private void navigation( Request breq, PrintWriter out, String name )
		throws IOException
		{
                    // this method is only called from legacy templates and we
                    // have to assume that the html page class has been given
                    // us in an attribuate to the BUILDING tag but we expect
                    // the default to be a navigation page.
                    String html_body_class = breq.getInsertAttribute( "html_body_class", "bodington_navigation_page" );
                    navigation( breq, out, html_body_class, name );
                }
            
	public void navigation( Request breq, Response response, String name )
		throws IOException
		{
                    // this method is only called from legacy templates and we
                    // have to assume that the html page class has been given
                    // us in an attribuate to the BUILDING tag but we expect
                    // the default to be a navigation page.
                    String html_body_class = response.getHtmlBodyClass();
                    PrintWriter out = response.getWriter();
                    navigation( breq, out, html_body_class, name );
                }
	
    /* @todo Create a Link superclass or Interface in order to simplify the way
     *  links are handled here... */
    /**
     * The navigation method. <br />
     * <i>(Weblearn modification 02/12/2003 A Corfield: Modified to handle QuickLink resources.)</i> <br />
     * <i>(Weblearn modification 18/06/2004 Colin Tatham: Merged with changes to method in v2.1.1Stable1)</i> <br />
     * <i>(Weblearn modification 14/05/2004 Colin Tatham: Added Sentient Link handling.)</i> <br />
     * <i>(Weblearn modification 12/2004 Colin Tatham: Added TextBlock, NewsFeed and Blog handling.)</i> 
     */
        public void navigation( Request breq, PrintWriter out, String html_body_class, String name )
		throws IOException
		{
		    
		if ( out == null )
		    return;
		    
                String icon, smliconurl, iconurl, spacerurl, parentsmliconurl, description, target, available_date;
                boolean range, link, italic, heading, quicklink, sentientlink, newWindow, isDescription;

                boolean textblock, newsfeed, blog;

		int n;
		BuildingContext context;
		Resource resource, parent, current, next;
		context = BuildingContext.getContext();
		FacilityList fl = FacilityList.getFacilities();
		Facility facility;
		Template template;
                String colour_mapper_code="";

                java.util.Date openDate, closeDate;

		org.bodington.servlet.HttpSession http_session = (org.bodington.servlet.HttpSession)breq.getSession( false );
		NavigationSession nav_session = breq.getServerNavigationSession();
                
                try
                {
                    StyleSheetSessionData sssd = getStyleSheetSessionData( http_session );
                    ColourPreferenceMapper colour_mapper = sssd.getUserColourPreferenceMapper( http_session );
                    
                    BuildingSession session = nav_session.getSession();
                    Color f;
                    Color b;
                    if ( "bodington_navigation_page".equals( html_body_class ) )
                    {
                        f = session.getPropertyColor( "style_navigation_graphic_foreground_colour", new Color( 0xeeeeee ) );
                        b = session.getPropertyColor( "style_navigation_graphic_background_colour", new Color( 0x111111 ) );
                    }
                    else
                    {
                        f = session.getPropertyColor( "style_graphic_foreground_colour", new Color( 0xeeeeee ) );
                        b = session.getPropertyColor( "style_graphic_background_colour", new Color( 0x111111 ) );
                    }
                    colour_mapper.setReferenceColours( b, f );
                    colour_mapper_code = "?code=" + colour_mapper.toString();
                }
                catch ( BuildingServerException bsex )
                {
                    logException( out, "Facility", "navigation", 
                        "A technical problem occured.",
                        bsex );
                    colour_mapper_code = "";
                }
                
                
        String tree_attribute = (String)breq.getInsertAttribute( "tree", null );
        boolean tree =  tree_attribute == null                      || 
                        tree_attribute.equalsIgnoreCase( "yes" )    || 
                        tree_attribute.equalsIgnoreCase( "true" )           ;

		try
			{
			resource = context.getResource();
                        parent = resource.getParent();

			if ( name.substring( 0, 5 ).equalsIgnoreCase( "links" ) )
				{
		    parentsmliconurl = "bs_template_navigation_iconsmall.gif";
                template = Template.get( this.facilityname, resource.getImplicitHttpUIStyle(), resource.getResourceId(), "iconsmall.gif" );
                if ( template != null )
                    parentsmliconurl = breq.getContextPath() + "/processedgif/templates" + template.getUrl() + colour_mapper_code;

				Enumeration enum=resource.findChildren();
				n=0;

				current=null;
				while ( enum.hasMoreElements() )
					{
					current = (Resource)enum.nextElement();
					if ( current.checkPermission( Permission.SEE ) )
						break;
					current=null;
					}

				while( current!=null )
					{
					next=null;
					while ( enum.hasMoreElements() )
						{
						next = (Resource)enum.nextElement();
						if ( next.checkPermission( Permission.SEE ) )
							break;
						next=null;
						}

                    // find url of small icon for current resource
                    smliconurl = current.getName() + "/bs_template_navigation_iconsmall.gif";
        			facility = fl.get( new Integer( current.getHttpFacilityNo() ) );
        			if ( facility!=null )
        			    {
                        template = Template.get( facility.facilityname, current.getImplicitHttpUIStyle(), current.getResourceId(), "iconsmall.gif" );
                        if ( template != null )
                            smliconurl = breq.getContextPath() + "/processedgif/templates" + template.getUrl() + colour_mapper_code;
                        }
                    
					if ( n==0 )
						{
						// if we have found a resource to list start off the table
						out.print( "<TABLE border=0 cellpadding=0 cellspacing=0>" );
						if ( tree )
						    {
						    // first display
						    // icon for containing resource
						    out.print( "<TR><TD VALIGN=TOP COLSPAN=2>" );
                            /*
                             * WebLearn modification [26/01/05] Alexis O'Connor.
                             * Renders more accurate / accessible value for alt
                             * attribute.
                             */                 
						    out.print( "<IMG alt=\"Icon for a " + resource.getResourceTypeName() + ".\" BORDER=0 SRC=\"" );
                            // <<<--- WebLearn modification.
						    out.print( parentsmliconurl );
						    out.print( "\">" );
						    //out.print( "</TD><TD>" );
						    out.println( "</TD></TR>" );
						    out.println( "<TR><TD VALIGN=TOP BACKGROUND=" + breq.getContextPath() + "/icons/thread-line.gif>" );
						    out.print( "<IMG BORDER=0 SRC=\"" + breq.getContextPath() + "/icons/thread-filler.gif\">" );
						    out.println( "</TD><TD></TD></TR>" );
						    }
						}
					n++;

					if ( current.checkPermission( Permission.VIEW ) )
				    	{
				    	link=true;
				    	italic=false;
				    	}
					else
				    	if ( nav_session.isAnonymous() )
				        	{
				    		link=true;
				    		italic=true;
				    		}
				    	else
				        	{
				    		link=false;
				    		italic=false;
				    		}

                                        description = current.getDescription().trim();
                                        if (description==null || description.length()==0)
                                          isDescription = false;
                                        else
                                          isDescription = true;

                                        heading = (current.getResourceType() == Resource.RESOURCE_HEADING);

                                        textblock = (current.getResourceType() == Resource.RESOURCE_TEXTBLOCK);
                                        newsfeed = (current.getResourceType() == Resource.RESOURCE_NEWSFEED);
                                        blog = (current.getResourceType() == Resource.RESOURCE_BLOG);
                                        
                                        sentientlink = (current.getResourceType() == Resource.RESOURCE_SENTIENTLINK);

                                        quicklink = (current.getResourceType() == Resource.RESOURCE_LINK);

                                        if (quicklink)
                                          newWindow = ((QuickLink)current).isNewWindow();
					else if (sentientlink)
                                          newWindow = ((SentientLink)current).isNewWindow();
                                        else
                                          newWindow = false;

                                        openDate = current.getOpenDate();
                                        closeDate = current.getCloseDate();
                                        if (!(openDate == null && closeDate == null)) {
                                          available_date = "<br>This resource is available";
                                          if (openDate != null)
                                            available_date += " from " + org.bodington.util.DateFormatter.formatDate(openDate, 2);
                                          if (closeDate != null)
                                            available_date += " until " + org.bodington.util.DateFormatter.formatDate(closeDate, 2);
                                        } else
                                          available_date = null;

					out.println( "<TR>" );
					
					if ( tree )
					    {
					    if ( next==null )
						    out.println( "<TD VALIGN=TOP>" );
					    else
						    out.println( "<TD VALIGN=TOP BACKGROUND=" + breq.getContextPath() + "/icons/thread-line.gif>" );
    	
					    if ( current.getResourceType() != Resource.RESOURCE_HEADING )
					    out.println( "<IMG SRC=" + breq.getContextPath() + "/icons/resource-arrow.gif>" );
					    else
						    out.println( "<IMG BORDER=0 SRC=" + breq.getContextPath() + "/icons/thread-filler.gif>" );
					    
					    out.println( "</TD>" );
                        }

					if ( current.getResourceType() == Resource.RESOURCE_HEADING )
						{
						out.print( "<TD VALIGN=TOP COLSPAN=2>" );
						out.print( "<H4 CLASS=bs-links-heading>" );
						out.print( current.getTitle() );
                                                out.print( "</H4>" );

                                                target = " <A TARGET=_top HREF=\"" + current.getName() + "/\" alt=\"Manage heading\">&gt;</A>";
						
                                                if (isDescription) {
                                                  out.println("<DIV CLASS=bs-links-heading-description>");
                                                  out.print(description);
                                                  if (current.checkPermission(Permission.MANAGE)) {
                                                    out.print(target);
                                                  if (available_date != null)
                                                      out.println(available_date);
								}
    						out.println( "</DIV>" );
    					    }

                                                if ( !isDescription && current.checkPermission( Permission.MANAGE ) ) {
                                                  out.print( target );
                                                  if (available_date != null)
                                                    out.println(available_date);
                                                }

						//if ( next!=null && next.getResourceType() != Resource.RESOURCE_HEADING )
						out.println( "</TD>" );
						}

                                                else if ( blog || newsfeed ) /** @todo add textblock.... */
                                                {
//                                                  out.println( current.getMenuItemDisplay( current, smliconurl ) );/** @todo make method static? */
                                                }



					else
						{

						out.print( "<TD VALIGN=TOP>" );
						//out.println( "<IMG SRC=" + breq.getContextPath() + "/icons/thread-filler.gif><BR>" );

                                                /*
                                                 * WebLearn inserted code; A Corfield 10/12/03
                                                 * Handles QuickLink newWindow property
                                                 */
                                                if ( link ) {
                                                  if ( quicklink ) {
                                                    String href = ((QuickLink)current).getLink(true);
                                                    if (href.equals("") || !newWindow)
                                                      target = "<A TARGET=_top HREF=\"" + href + "\">";
                                                    else
                                                      target = "<A TARGET=_new HREF=\"" + href + "\">";
                                                  } else if ( sentientlink ) {
						    String href = ((SentientLink)current).getUrl();
						    if (href.equals("") || !newWindow)
						      target = "<A TARGET=\"menu\" HREF=\"" + href + "\">";
						    else
                                                      target = "<A TARGET=_blank HREF=\"" + href + "\">";
                                                  } else
                                                    target = "<A TARGET=_top HREF=\"" + current.getName() + "/\">";
                                                  out.print( target );
                                                } else
                                                  target = null;

                        /*
                         * WebLearn modification [26/01/05] Alexis O'Connor.
                         * Renders more accurate / accessible value for alt
                         * attribute.
                         */                 
						out.print( "<IMG alt=\"Icon for a " + current.getResourceTypeName() + ".\" CLASS=bs-links-icon BORDER=0 SRC=\"" );
                        // <<<--- WebLearn modification.
						out.print( smliconurl );
						out.print( "\">" );
						if ( link )
							out.print( "</A>" );
						out.println( "</TD>" );

						out.print( "<TD VALIGN=TOP>" );
						//out.println( "<IMG SRC=" + breq.getContextPath() + "/icons/thread-filler.gif><BR>" );

						if ( link )
   							out.print( "<A TARGET=_top HREF=\"" + current.getName() + "/\">" );
	    				//out.print( "<NOBR>" );
						out.print( "<SPAN CLASS=bs-links-title>" );
						if ( italic )
							out.print( "<I>" );

						out.print( current.getTitle() );

						if ( italic )
							out.print( "</I>" );
	    				//out.println( "</NOBR>" );
						out.println( "</SPAN>" );
						if ( link )
							out.print( "</A>" );
						else
	    					out.println( "<BR><SPAN CLASS=bs-links-no-access><I>You are not included on the access list for this item.</SPAN>" );

                                                if (quicklink || sentientlink)/* @todo link directly to manage.html? */
                                                  target = " <A TARGET=_top HREF=\"" + current.getName() + "/\" alt=\"Manage link\">&gt;</A>";

                                                if (isDescription) {
							out.print( "<DIV CLASS=bs-links-description>" );
							out.print( current.getDescription()  );
                                                  if (current.checkPermission(Permission.MANAGE)) {
                                                    if (quicklink || sentientlink)
                                                      out.print(target);
                                                    if (available_date != null)
                                                      out.println(available_date);
                                                  }
							out.print( "</DIV>" );
							}

                                                if (!isDescription && current.checkPermission(Permission.MANAGE)) {
                                                  if (quicklink || sentientlink)
                                                    out.println(target);
                                                  if (available_date != null)
                                                    out.println(available_date);
                                                }

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


					current = next;
					}
				if ( n>0 )
					out.println( "</TABLE>" );
				return;
				}

			if ( name.equalsIgnoreCase( "linkout" ) )
				{
                                String nav_bar_height = getAutomaticPreferenceByScreenSize( 
                                        breq, "preference.navigation.nav_bar_height", "small", "big" );
                                boolean small_bar = "small".equalsIgnoreCase( nav_bar_height );
                                String nav_bar_icons = getAutomaticPreferenceByScreenSize( 
                                        breq, "preference.navigation.nav_bar_icon_list", "reduced", "full" );
                                boolean reduced_icons = "reduced".equalsIgnoreCase( nav_bar_icons );
				String absurl= breq.getContextPath() +
						breq.getServletPath() + "/";
				Enumeration branch;
				try
					{
					branch = resource.findAncestors();
					}
				catch ( BuildingServerException bsex )
					{
					out.println( bsex.toString() );
					return;
					}


				//make sure there is no white space between tags
				//to prevent line breaks.
				//iterate the location tree adding icons to backtrack out
				//include the current location and put a link on it (which
				//will reload current location)
                template = Template.get( this.facilityname, resource.getImplicitHttpUIStyle(), resource.getResourceId(), "spacer.gif" );
                if ( template != null )
                    spacerurl = breq.getContextPath() + "/processedgif/templates" + template.getUrl() + colour_mapper_code;
                else
                    spacerurl = "bs_template_navigation_spacer.gif";
                    
				out.print( "<NOBR>"   );
				for ( int i=0; branch.hasMoreElements(); i++ )
					{
					current=(Resource)branch.nextElement();
					if ( current.getParentResourceId() != null )
				    	absurl=absurl+current.getName()+"/";

                                        // skip if reduced list of icons option on
                                        // and this is neither selected resource or parent
                                        if ( reduced_icons && current!=resource && current != parent )
                                            continue;

                    iconurl = absurl + (small_bar?"bs_template_navigation_iconsmall.gif":"bs_template_navigation_icon.gif");

        			facility = fl.get( new Integer( current.getHttpFacilityNo() ) );
        			if ( facility!=null )
        			    {
                        template = Template.get( facility.facilityname, current.getImplicitHttpUIStyle(), current.getResourceId(), 
                                (small_bar?"iconsmall.gif":"icon.gif") );
                        if ( template != null )
                            iconurl = breq.getContextPath() + "/processedgif/templates" + template.getUrl() + colour_mapper_code;
                        }
                                if ( !small_bar )
                                {
					out.print( "<IMG ALIGN=LEFT HSPACE=0 VSPACE=0 BORDER=0 SRC=\"" );
    				out.print( spacerurl );
					out.print( "\">" );
                                }
					out.print( "<A TARGET=_top HREF=\"" + absurl + "\">" );
					out.print( "<IMG ALIGN=LEFT HSPACE=0 VSPACE=0 BORDER=0 SRC=\"" );
					out.print( iconurl );
					out.print( "\" " );
					/*
					 * WebLearn modification [26/01/05] Alexis O'Connor.
					 * Renders more accurate / accessible value for alt attribute.
					 * Value of title attribute taken from alt.
					 */	                
					out.print( "ALT=\"" );
                    out.print( "Icon for a " + current.getResourceTypeName() + "." );
					out.print( "\" " );
                    out.print( "TITLE=\"" );
                    if ( branch.hasMoreElements() )
                        out.print( "Jump out to: " );
                    else
                        out.print( "Refresh view onto: " );
                    out.print( current.getTitle() );
                    out.print( "\">" );
					// <<<--- WebLearn modifications.
					out.print( "</A>" );
					}
                                if ( !small_bar )
                                {
				out.print( "<IMG ALIGN=LEFT HSPACE=0 VSPACE=0 BORDER=0 SRC=\"" );
				out.print( spacerurl );
				out.print( "\">" );
                                }
				out.println( "</NOBR>"   );
				return;
				}




			if ( name.equalsIgnoreCase( "MANAGELINK" ) )
				{
				out.println( "<A TARGET=buildmain HREF=\"" +
						breq.absoluteURL() +
						"bs_template_manage.html\">Manage</A> this resource." );
				}

			if ( name.equalsIgnoreCase( "notifyswitch" ) )
				{
				User user = (User)context.getUser();
				if ( nav_session.isAnonymous() )
					return;

                String nav_bar_height = getAutomaticPreferenceByScreenSize( 
                        breq, "preference.navigation.nav_bar_height", "small", "big" );
                boolean small_bar = "small".equalsIgnoreCase( nav_bar_height );
                
				UserEventSetup ues=null;
				try
					{
       				ues = UserEventSetup.findUserEventSetupByUserId( user.getUserId() );
       				if ( ues == null )
       					{
       					ues = new UserEventSetup();
       					ues.setUser( user );
       					ues.save();
       					}

					//check input to see if it is switched
					String str=breq.getParameter( "switch.x" );
					if ( str!=null )
						{
						if ( ues.containsResource( breq.getResource() ) )
							{
							ues.removeResource( breq.getResource() );
							out.println( "<SCRIPT LANGUAGE=JavaScript>" );
							out.println( "alert( \"From now on you will not be notified of events in this location.\" );" );
							out.println( "</SCRIPT>" );
							}
						else
							{
							ues.addResource( breq.getResource() );
							out.println( "<SCRIPT LANGUAGE=JavaScript>" );
							out.println( "alert( \"From now on you will be notified of events in this location.\" );" );
							out.println( "</SCRIPT>" );
							}
						}

                    //uhi:awc - start: modified so switch is done without need for gif graphic
                    out.print("<a href=\"bs_template_top.html?switch.x=0\">");
                    if ( ues.containsResource( breq.getResource() ) )
                        out.print("Notify is on");
                    else
                        out.print("Notify is off");
                    out.print( "</a>" );
                    /*
					out.print( "<form method=\"POST\" action=\"bs_template_top.html\">" );
					if ( ues.containsResource( breq.getResource() ) )
                                            writeTemplateGifTag(breq, out, html_body_class, "input", 
                                                small_bar?"bs_template_navigation_bin-onsmall.gif":"bs_template_navigation_bin-on.gif", 
                                                "name=\"switch\" type=\"image\" border=\"0\" alt=\"Icon: Notification currently switched on here. Click to switch off.\"" );
					else
                                            writeTemplateGifTag(breq, out, html_body_class, "input", 
                                                small_bar?"bs_template_navigation_bin-offsmall.gif":"bs_template_navigation_bin-off.gif", 
                                                "name=\"switch\" type=\"image\" border=\"0\" alt=\"Icon: Notification currently switched off here. Click to switch on.\"" );
					out.print( "</from>" );
                    */
                    //uhi:awc - end

					}
				catch ( Exception ex )
					{
					//do nowt
					return;
					}
				}
			}
		catch ( BuildingServerException bsex )
			{
			return;
			}

		out.print( "<! navigation HTML inserted here>" );
		}



    public String fileParameter( Request req )
        {
	String url;
	StringBuffer dest_filename = new StringBuffer();

	for ( int i=0; i<req.getTemplateParameterCount(); i++ )
	    {
	    dest_filename.append( "/" );
	    url = (String)req.getTemplateParameter( i );
	    dest_filename.append( url );
	    }

	return dest_filename.toString();
        }


	private void upload( Request req, PrintWriter out, boolean rawconfirmation )
		throws ServletException, IOException
		{
		StringBuffer dest_filename=new StringBuffer();
		String file, file_name, mime_type;
		BuildingSession session;
		PrimaryKey id;
		UploadedFileSummary summary;

		if ( rawconfirmation )
			out.println( "<PRE>" );
		
		file = req.getParameter( "file" );
		file_name = req.getParameterFileName( "file" );

		if ( file_name == null || file_name.length() == 0 )
			{
			if ( rawconfirmation )
				out.print( "ERROR:\t" );
			out.println( "Upload failed because no file name was supplied in the form." );
			if ( rawconfirmation )
				out.println( "</PRE>" );
			return;
			}

		
		dest_filename.append( fileParameter( req ) );
		if ( dest_filename.length()>0 )
			dest_filename.append( "/" );
		
		
		try
			{
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );

			if ( file!=null && file_name!=null )
				{
				if ( file_name.indexOf( '/' )>=0 || file_name.indexOf( '\\' )>=0 )
					{
					if ( rawconfirmation )
						out.print( "ERROR:\t" );
					out.println( "File names may not contain any slash or backslash characters." );
					if ( rawconfirmation )
						out.println( "</PRE>" );
					return;
					}
				dest_filename.append( file_name );
				
				mime_type=req.getServletConfig().getServletContext().getMimeType( file_name.toLowerCase() );
				if ( mime_type==null )
					   mime_type="application/octet-stream";

				summary = session.transferFile( file, dest_filename.toString(), mime_type );
				
				if ( rawconfirmation )
					out.println( "OK" );
				else
					out.println( "<HR>File upload succeeded.<HR>" );

	       		UserFileEvent event = new UserFileEvent( 
        								UserFileEvent.EVENT_UPLOAD,
        								req.getResource().getResourceId(), 
        								summary.getCreateUserId(), 
        								null,
        								new Integer( summary.getUploadedFileId().intValue() ), 
        								new BigInteger( Long.toString( summary.getSize() ) ),
        								file_name );
				event.save();

				session.invalidateResourceMenu();
				}
			}
		catch ( Exception ex )
			{
			if ( rawconfirmation )
			    {
			    out.println( "ERROR: Exception: " + ex.getMessage() );
			    logException( null, "Facility", "upload", 
				    "A technical problem occured.",
				    ex );
			    }
			else
			    logException( out, "Facility", "upload", 
				    "A technical problem occured.",
				    ex );
			}
		if ( rawconfirmation )
			out.println( "</PRE>" );
		}
		

	private static int inc=0x1000;
	private void uploadzip( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		String dest_filename;
		String zipfile, file, file_name, mime_type, startfilename;
		BuildingSession session;
		PrimaryKey id;
		UploadedFileSummary summary;
		ZipFile archive=null;
		ZipEntry zipentry;
		InputStream zipinput;
		FileOutputStream fout;
		int b;

		zipfile = req.getParameter( "file" );
		
		startfilename = fileParameter( req );
		if ( startfilename.length()>0 )
			startfilename = startfilename + "/";

		try
			{
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );
   			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "uploadzip", 
			    "A technical problem occured.",
			    ex );
			return;
			}
			
	out.println( "<p>Zip file uploaded, started to unpack.<br>" );

        archive = new ZipFile( zipfile );
        for ( Enumeration enum=archive.entries(); enum.hasMoreElements(); )
            {
            zipentry = (ZipEntry)enum.nextElement();
            Logger.getLogger( "org.bodington" ).fine( "ZIP Entry = [" + zipentry + "]" );

            //ignore directories - don't create empty folders
			file_name = zipentry.getName();
            if ( zipentry.isDirectory() || file_name==null )
            	continue;

            Logger.getLogger( "org.bodington" ).fine( "ZIP file = [" + file_name + "]" );

	    if ( file_name.indexOf( '\\' ) >=0 )
		{
		out.print( "<P>Skipped ZIP file entry \"" );
		out.print( file_name );
		out.print( "\" because the name contained a back slash.</P><HR>" );
		continue;
		}
	    
	    if ( file_name.startsWith( "/" ) )
		dest_filename = startfilename + file_name.substring( 1 );
	    else
		dest_filename = startfilename + file_name;
	    
			zipinput = archive.getInputStream( zipentry );
			if ( zipinput==null )
			    {
			    out.println( "<P>Unreadable ZIP file entry: " );
			    out.println( zipentry.toString() );
			    out.println( "</P><HR>" );
			    continue;
			    }
			    
			file = BuildingContext.createTempFile( "zipentry", ".zbin" ).getAbsolutePath();
			fout = new FileOutputStream( file );
			while ( (b=zipinput.read()) >= 0 )
				fout.write( b );
			fout.close();
			zipinput.close();

           
			try
				{
				mime_type=req.getServletConfig().getServletContext().getMimeType( file_name );
				if ( mime_type==null )
				    mime_type="application/octet-stream";
				summary = session.transferFile( file, dest_filename, mime_type );
					
				out.println( "Unpacked another file, looking for next....<br>" );
				out.flush();

	       		UserFileEvent event = new UserFileEvent( 
        								UserFileEvent.EVENT_UPLOAD,
        								req.getResource().getResourceId(), 
        								summary.getCreateUserId(), 
        								null,
        								new Integer( summary.getUploadedFileId().intValue() ), 
        								new BigInteger( Long.toString( summary.getSize() ) ),
        								file_name );
				event.save();
				}
			catch ( Exception ex )
				{
				logException( out, "Facility", "uploadzip", 
				    "A technical problem occured.",
				    ex );
				return;
				}
			}

		out.println( "Finished unpacking the ZIP file.<p>" );
		out.println( "<SCRIPT LANGUAGE=JavaScript>" );
		out.println( "window.parent.frames[\"managefileindex\"].location.reload()" );
		out.println( "</SCRIPT>" );
		out.flush();

		try
			{
			session.invalidateResourceMenu();
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "uploadzip", 
			    "A technical problem occured.",
			    ex );
			return;
			}
			
		archive.close();
		(new File( zipfile )).delete();
		}
		
	private void fileinfo( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		String dest_filename=null;
		String dest_url=null;
		String property, url;
		BuildingSession session;
		Object attribute;
		PrimaryKey id;
		UploadedFileSummary summary;
		
		
		property = req.getInsertAttribute( "property", null );
		if ( property==null )
			return;
			
		try
			{
			session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
			session.setResource( req.getResource().getResourceId() );


			summary = (UploadedFileSummary)req.getRequestProperty( "uploadedfilesummary" );
			if ( summary==null )
				{
				dest_filename = fileParameter( req );
				
				Logger.getLogger( "org.bodington" ).fine( "File url is " + dest_filename.toString()  );
				
				BuildingContext.trace( "File url is " + dest_filename.toString() );
				summary = session.getFileSummary( dest_filename.toString() );

				// pretend there's a root folder even if there isn't one.
				if ( summary==null && dest_filename.length()==0 )
					{
					BuildingContext.trace( "making pretend root folder" );
					summary = new UploadedFileSummary();
					summary.setFlags( UploadedFileSummary.FLAG_FOLDER );
					}
					
				if ( summary==null )
					{
					if ( property.equalsIgnoreCase( "name" ) )
						out.print( "<I>file not found</I>" );
					BuildingContext.dumpTrace();
					return;
					}
				
				// if its a made up root folder the url is blank
				// otherwise the session can provide the url
				if ( summary.getUploadedFileId() == null )
				    dest_url = "";
				else
				    dest_url = session.getPublishedURL( summary.getUploadedFileId() );

				req.setRequestProperty( "uploadedfilepath", dest_url );
				req.setRequestProperty( "uploadedfilesummary", summary );
				}
			else
				dest_url = (String)req.getRequestProperty( "uploadedfilepath" );
			    
			BuildingContext.trace( "Got file summary..." );
                        /*
                         * WebLearn inserted code; A Corfield 02/12/2003
                         * Prints UploadedFileId
                         */
                        if ( property.equalsIgnoreCase( "id" ) )
                                {
                                if ( summary.getParentUploadedFileId()==null )
                                        out.print( "<I>Root folder for this resource</I>" );
                                else
                                        out.print( summary.getUploadedFileId() );
                                }
				
			if ( property.equalsIgnoreCase( "name" ) )
				{
				if ( summary.getParentUploadedFileId()==null )
					out.print( "<I>Root folder for this resource</I>" );
				else
					out.print( summary.getName() );
				}
			
			if ( property.equalsIgnoreCase( "url" ) )
				{
				if ( summary.getParentUploadedFileId()==null )
					out.print( "<I>Root folder for this resource</I>" );
				else
					out.print( summary.getUrl() );
				}
			
			if ( property.equalsIgnoreCase( "webaddress" ) )
				{
				StringBuffer address= new StringBuffer();
				
				address.append( "http://" );
				address.append( req.getServerName() );
				if ( req.getServerPort()!=80 )
					{
					address.append( ":" );
					address.append( req.getServerPort() );
					}

				address.append( req.absoluteURL() );
				
				out.print( address.toString() );
				out.print( dest_url.toString() );
				}
			
			if ( property.equalsIgnoreCase( "size" ) )
				out.print( summary.getSize() );
			
			if ( property.equalsIgnoreCase( "updatedtime" ) )
				{
				if ( summary.getUpdatedTime() != null )
					/* WebLearn (Bug-fix) A O'Connor [13/12/04]
					 * Displays date in more user-oriented way */
					out.print( DateFormatter.formatDate( summary.getUpdatedTime(), 2) );
				else
					out.print( "<CENTER>~</CENTER>" );
				}

			if ( property.equalsIgnoreCase( "updateuser" ) )
				{
				PrimaryKey uid = summary.getUpdateUserId();
				if ( uid!=null )
					out.print( session.getNameOfUser( uid ) );
				else
					out.print( "<CENTER>~</CENTER>" );
				}
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "fileinfo", 
			    "A technical problem occured.",
			    ex );
			}
		}

	private void filerename( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		StringBuffer dest_filename=null;
		String newname;
		BuildingSession session;
		Object attribute;
		PrimaryKey id;
		UploadedFileSummary summary;
		
		newname = req.getParameter( "name" );
		if ( newname==null || newname.length()==0 )
			{
			out.println( "<P>You have to supply a name</P>" );
			return;
			}
		
		if ( newname.length()>255 )
			{
			out.println( "<P>Name is too long</P>" );
			return;
			}
			
		if ( newname.indexOf( '/' ) >=0 || newname.indexOf( '\\' ) >=0 )
			{
			out.println( "<P>Name cannot contain forward or backward slashes.</P>" );
			return;
			}
		
			
		try
			{
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );

   			dest_filename=new StringBuffer();
			dest_filename.append( fileParameter( req ) );

			session.renameFile( dest_filename.toString(), newname );
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "filerename", 
			    "A technical problem occured.",
			    ex );
			}
		}



	private boolean fileisdeleted( Request req )
		throws ServletException, IOException
		{
		StringBuffer dest_filename=null;
		String property;
		BuildingSession session;
		Object attribute;
		PrimaryKey id;
		UploadedFileSummary summary;
		
		
		try
			{
   		session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
   		session.setResource( req.getResource().getResourceId() );

			summary = (UploadedFileSummary)req.getRequestProperty( "uploadedfilesummary" );
			if ( summary==null )
				{
   				dest_filename=new StringBuffer();
        		dest_filename.append( fileParameter( req ) );
					
				summary = session.getFileSummary( dest_filename.toString() );

				// pretend there's a root folder even if there isn't one.
				if ( summary==null && dest_filename.length()==0 )
					{
					summary = new UploadedFileSummary();
					summary.setFlags( UploadedFileSummary.FLAG_FOLDER );
					}
					
				if ( summary==null )
					{
					return false;
					}
				
				if ( summary.isFolder() )
					dest_filename.append( "/" );
				req.setRequestProperty( "uploadedfilepath", dest_filename.toString() );
				req.setRequestProperty( "uploadedfilesummary", summary );
				}

			if ( dest_filename==null )
				{
				dest_filename = new StringBuffer();
				dest_filename.append( req.getRequestProperty( "uploadedfilepath" ) );
				}
				
			return summary.isDeleted();
			}
		catch ( Exception ex )
			{
			logException( null, "Facility", "fileisdeleted", 
			    "A technical problem occured.",
			    ex );
			}
		return false;
		}


	private void foldercreate( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		StringBuffer dest_filename=new StringBuffer();
		String folder;
		BuildingSession session;
		PrimaryKey id;
		UploadedFileSummary summary;
		
		folder = req.getParameter( "subfolder" );
		if ( folder==null || folder.length()<=0 )
			{
			out.println( "<P>Folder name must have one or more characters.</P>" );
			return;
			}

		if ( folder.length()>255 )
			{
			out.println( "<P>Name is too long</P>" );
			return;
			}
			
		
		dest_filename.append( fileParameter( req ) );
		if ( dest_filename.length()>0 )
			dest_filename.append( "/" );
		dest_filename.append( folder );		
		
		try
			{
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );

			summary = session.createFolder( dest_filename.toString() );

				/*
	       		UserFileEvent event = new UserFileEvent( 
        								UserFileEvent.EVENT_UPLOAD,
        								req.getResource().getResourceId(), 
        								summary.getCreateUserId(), 
        								null,
        								new Integer( summary.getUploadedFileId().intValue() ), 
        								new BigInteger( Long.toString( summary.getSize() ) ),
        								file_name );
        		*/
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "foldercreate", 
			    "A technical problem occured.",
			    ex );
			}
		}


	protected void rawfileproperties( PrintWriter out, Vector path )
		throws IOException
		{
		UploadedFileSummary ufs=null;
		
		if ( path.size()<2 )
			{
			return;
			}
			
		for ( int i=1; i< path.size(); i++ )
			{
			ufs = (UploadedFileSummary)path.elementAt( i );
			out.print( "/" );
			out.print( ufs.getUrl() );
			}
		
		if ( ufs.isFolder() )
			out.print( "/" );
			
		out.print( "\t" );

		out.print( ufs.getSize() );

		out.print( "\t" );

		out.print( ufs.getUpdatedTime().toGMTString() );

		out.print( "\n" );
		}

	protected void rawfileindex( Request req, PrintWriter out )
		throws IOException, ServletException
		{
		int i, j, k, n;
		StringBuffer address= new StringBuffer();
		BuildingSession session;
		UploadedFileSummary[] summaries;
		UploadedFileSummary parent;

		Vector path = new Vector();


		out.println( "<PRE>" );
		try
			{
  				session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
  				session.setResource( req.getResource().getResourceId() );
   			if ( session==null )
   				{
   				out.println( "ERROR:\tUnable to connect to bodington system server." );
   				out.println( "</PRE>" );
   				return;
   				}
   			//get ALL files including those marked as deleted.
			summaries = session.getFileAndDescendentSummaries( "/", false );
			}
		catch ( Exception ex )
			{
			out.println( "ERROR:\tTechnical Problem finding file list " + ex );
			out.println( "</PRE>" );
			return;
			}

		if ( summaries.length == 0 )
			{
			summaries = new UploadedFileSummary[1];
			summaries[0] = new UploadedFileSummary();
			summaries[0].setFlags( UploadedFileSummary.FLAG_FOLDER );
			}

		path.addElement( summaries[0] );
		
		for ( i=1; i<summaries.length; i++ )
			{
			// remove unwanted parts from path
			// work down path until reach a parent of current node
			for ( j=path.size()-1; j>=0; j-- )
				{
				parent = (UploadedFileSummary)path.elementAt(j);
				if ( summaries[i].getLeftIndex() > parent.getLeftIndex() &&
					 summaries[i].getRightIndex() < parent.getRightIndex()  )
					break;
				}
			// j indexes parent or is -1
			path.setSize( j+1 );
			path.addElement( summaries[i] );
			
			rawfileproperties( out, path );
			}
		out.println( "</PRE>" );
		}


	/**
	 * Outputs a tree diagram of files in the resource.
	 * 
	 * @param req The building HTTP request.
	 * @param out The output stream.
	 * @exception java.io.IOException Thrown if there is a problem outputting the HTML.
	 */
	protected void fileindextitle( Request req, PrintWriter out, String basepath )
		throws IOException, ServletException
		{
		//out.print( "Filespace for this location." );
		}






	/**
	 * Outputs a tree diagram of files in the resource.
	 *
	 * @param req The building HTTP request.
	 * @param out The output stream.
	 * @exception java.io.IOException Thrown if there is a problem outputting the HTML.
	 */
	protected void fileindex( Request req, PrintWriter out, String basepath, boolean show_root, boolean hide_deleted, int link_type )
		throws IOException, ServletException
		{
		Enumeration enum;
		//PrimaryKey mid, jump_mid=null, pmid, selected_mid;
		int i, j, k, n, old_level, top_level;
		StringBuffer address= new StringBuffer();
		BuildingSession session;
		UploadedFileSummary[] summaries;
		UploadedFileSummary parent;

		Vector path = new Vector();

		if ( basepath==null )
			basepath = "/";
		if ( !basepath.endsWith( "/" ) )
			basepath = basepath + "/";
		if ( !basepath.startsWith( "/" ) )
			basepath = "/" + basepath;

		try
			{
  				session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
   			if ( session==null )
   				{
   				out.println( "Unable to connect to bodington system server." );
   				return;
   				}
  				session.setResource( req.getResource().getResourceId() );
			summaries = session.getFileAndDescendentSummaries( basepath, hide_deleted );
			}
		catch ( Exception ex )
			{
			out.println( "<P>Technical Problem finding file list<BR>" + ex );
			return;
			}

		if ( summaries.length == 0 )
			{
			summaries = new UploadedFileSummary[1];
			summaries[0] = new UploadedFileSummary();
			summaries[0].setFlags( UploadedFileSummary.FLAG_FOLDER );
			}

		out.print( "<TABLE border=0 cellpadding=0 cellspacing=4>" );

		if ( show_root )
			{
			out.println( "<TR><TD VALIGN=TOP></TD><TD VALIGN=TOP>" );
			if ( link_type==1 )
				out.print( "<A TARGET=managefileinfo HREF=bs_template_managefolder.html>" );
			out.print( "<NOBR><IMG BORDER=0 SRC=bs_template_folder-small.gif> <B>/</B></NOBR>" );
			if ( link_type==1 )
				out.println( "</A>" );
			out.println( "</TD></TR>" );
			top_level=1;
			
			if ( summaries.length<2 )
				{
				out.println( "<TR><TD VALIGN=TOP></TD><TD><IMG SRC=" + req.getContextPath() + "/icons/thread-empty.gif> " );
				out.println( "This resource contains no uploaded files.</TD></TR>" );
				out.println( "</TABLE>" );
				return;
				}
			}
		else
			top_level=2;

		path.addElement( summaries[0] );
		old_level=1;
		for ( i=1; i<summaries.length; i++ )
			{
			// remove unwanted parts from path
			// work down path until reach a parent of current node
			for ( j=path.size()-1; j>=0; j-- )
				{
				parent = (UploadedFileSummary)path.elementAt(j);
				if ( summaries[i].getLeftIndex() > parent.getLeftIndex() &&
					 summaries[i].getRightIndex() < parent.getRightIndex()  )
					break;
				}
			// j indexes parent or is -1
			path.setSize( j+1 );
			path.addElement( summaries[i] );


			//work out first whether we need a continuation line from previous
			//node onto a later sibling of that node.
			for ( j=i+1; j<summaries.length; j++ )
				if ( i>1 && summaries[i-1].getParentUploadedFileId().equals(
								summaries[j].getParentUploadedFileId() ) )
					break;

			// make a new row with continuation bar in first cell and
			// put table in second cell if this file within previous
			// (except first top level node)
			if ( path.size()>old_level && path.size()>top_level )
				{
				out.print( "<TR>" );
				if ( j == summaries.length || old_level<=top_level )
					{
					out.println( "<TD VALIGN=TOP>" );
					}
				else
					{
					out.println( "<TD VALIGN=TOP BACKGROUND=" + req.getContextPath() + "/icons/thread-line.gif>" );
					out.println( "<IMG SRC=" + req.getContextPath() + "/icons/thread-blank.gif>" );
					}
				out.println( "</TD><TD><TABLE border=0 cellpadding=0 cellspacing=0>" );
				}
			//close tables until back to level of this message
			for ( k=path.size(); k<old_level; k++ )
				{
				out.print( "</TABLE></TD></TR>" );
				}

			old_level = path.size();

			out.println( "<TR>" );

			//work out first whether we need a continuation line from
			//node onto a later sibling.
			for ( j=i+1; j<summaries.length; j++ )
				if ( summaries[i].getParentUploadedFileId().equals(
								summaries[j].getParentUploadedFileId() ) )
					break;
			if ( j == summaries.length || path.size()<=top_level )
				out.println( "<TD VALIGN=TOP>" );
			else
				out.println( "<TD VALIGN=TOP BACKGROUND=" + req.getContextPath() + "/icons/thread-line.gif>" );


			//choose icon depending on whether node has children
			//later we will need to cope with nodes that are closed and
			//need a plus icon.
			//if ( (summaries[i].getLeftIndex()+1) == summaries[i].getRightIndex() )
			if ( path.size()>top_level )
				out.println( "<IMG SRC=" + req.getContextPath() + "/icons/thread-empty.gif>" );
			//else
			//	out.print( "<IMG BORDER=0 SRC=" + breq.getContextPath() + "/icons/thread-minus.gif>" );
			out.print( "</TD><TD>" );


			out.println( "<IMG SRC=" + req.getContextPath() + "/icons/thread-filler.gif><BR>" );

			if ( !summaries[i].isFolder() || link_type==1 )
				{
				address.setLength( 0 );
				address.append( req.absoluteURL() );
				address.setLength( address.length()-1 );  //to trim off last slash
				address.append( basepath );
				for ( j=1; j<path.size(); j++ )
					{
					parent = (UploadedFileSummary)path.elementAt(j);
					if ( j>1 )
						address.append( "/" );
					address.append( parent.getUrl() );
					}
				if ( link_type==1 )
					{
					if ( summaries[i].isFolder() )
						address.append( "/bs_template_managefolder.html" );
					else
						address.append( "/bs_template_managefileinfo.html" );
					out.print( "<A TARGET=managefileinfo HREF=\"" );
					}
				else
					out.print( "<A HREF=\"" );
				out.print( address.toString() );
				out.print( "\">" );
				}
			out.print( "<NOBR>" );
			if ( summaries[i].isFolder() )
				out.print( "<IMG BORDER=0 SRC=bs_template_folder-small.gif>" );
			else
				out.print( "<IMG BORDER=0 SRC=bs_template_file-small.gif>" );


			if ( summaries[i].isDeleted() )
				out.print( "<FONT COLOR=GRAY>" );

			out.print( summaries[i].getName() );

			if ( summaries[i].isDeleted() )
				out.print( "</FONT>" );
				
			out.print( "</NOBR>" );

			if ( !summaries[i].isFolder() || link_type==1 )
				out.print( "</A>" );


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

		//close tables
		for ( i=top_level; i<old_level; i++ )
			{
			out.print( "</TABLE></TD></TR>" );
			}

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


	private void bytesuploaded( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		String strstyle;
		int style;
		BuildingSession session;
		Object attribute;
		
		
		strstyle = req.getInsertAttribute( "style", "grandtotal" );
			
		try
			{
  				session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
  				session.setResource( req.getResource().getResourceId() );

			style = BuildingSession.BYTES_UPLOADED_GRAND_TOTAL;
			if ( strstyle.equalsIgnoreCase( "resource" ) )
				style = BuildingSession.BYTES_UPLOADED_RESOURCE;
			if ( strstyle.equalsIgnoreCase( "user" ) )
				style = BuildingSession.BYTES_UPLOADED_USER;
			if ( strstyle.equalsIgnoreCase( "usertoresource" ) )
				style = BuildingSession.BYTES_UPLOADED_USER_TO_RESOURCE;
				

			long l = session.bytesUploaded( style );
			
			out.print( l );
			out.print( " bytes" );
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "bytesuploaded", 
			    "A technical problem occured.",
			    ex );
			}
		}


	private void filedelete( Request req, PrintWriter out, boolean delete )
		throws ServletException, IOException
		{
		StringBuffer dest_filename=null;
		BuildingSession session;
		Object attribute;
		PrimaryKey id;
		UploadedFileSummary summary;
		
		
		try
			{
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );
					
   			dest_filename=new StringBuffer();
    		dest_filename.append( fileParameter( req ) );
			if ( delete )
				session.deleteFile( dest_filename.toString() );
			else
				session.undeleteFile( 
						dest_filename.toString(), 
						req.getInsertAttribute( "recurse", "no" ).equalsIgnoreCase( "yes" ) );
			session.invalidateResourceMenu();
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "filedelete", 
			    "A technical problem occured.",
			    ex );
			}
		}



	private void metadataupload(  Request req, PrintWriter out )
		throws IOException
		{
		BuildingSession session;

		String file = req.getParameter( "file" );
		if ( file == null || file.length() == 0 )
		    {
		    out.println( "<P>Import failed: no file was supplied.</P>" );
		    return;
		    }

		try
		    {
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );



		    session.importMetadata( file );
    		out.println( "DONE" );
		    }
		catch ( BuildingServerException bsex )
		    {
    		out.println( "<PRE>" );
    		out.println( bsex.getMessage() );
    		out.println( "</PRE>" );
		    }
		
		
		return;
		}


	private void metadata(  Request req, PrintWriter out )
		throws IOException
		{
		BuildingSession session;

		try
		    {
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );

			String file_name = session.exportMetadata();
			if ( file_name == null )
				{
				out.println( "<P>There is currently no metadata defined for this resource.</P>" );
				return;
				}
			
			InputStreamReader in = new InputStreamReader( new FileInputStream ( file_name ), "UTF8" );
			out.print( "<FORM><SPAN CLASS=bs-textarea><TEXTAREA COLS=40 ROWS=20>" );
			int b;
			while ( (b = in.read()) >= 0 )
				out.print( (char)b );
			out.println( "</TEXTAREA></SPAN></FORM>" );
			in.close();
			File f = new File( file_name );
			f.delete();
			
		    }
		catch ( BuildingServerException bsex )
		    {
    		out.println( "<PRE>" );
    		out.println( bsex.getMessage() );
    		out.println( "</PRE>" );
		    }
		
		
		return;
		}


	private void metadatasearch(  Request req, PrintWriter out )
		throws IOException
		{
		BuildingSession session;
		
		try
		    {
  				session = BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
  				session.setResource( req.getResource().getResourceId() );


				String general_elements = req.getParameter( "general_elements" );
				String general_title = req.getParameter( "general_title" );
				String general_title_opt = req.getParameter( "general_title_opt" );
				String general_strength = req.getParameter( "general_strength" );
                                int strength;

				if ( general_title_opt == null )
					general_title_opt = "a";
				if ( general_elements == null )
					general_elements = "a";
				if ( general_strength == null )
					general_strength = "primary";
				
                                if ( "primary".equalsIgnoreCase( general_strength ) )
                                    strength = java.text.Collator.PRIMARY;
                                else if ( "secondary".equalsIgnoreCase( general_strength ) )
                                    strength = java.text.Collator.SECONDARY;
                                else if ( "tertiary".equalsIgnoreCase( general_strength ) )
                                    strength = java.text.Collator.TERTIARY;
                                else
                                    strength = java.text.Collator.IDENTICAL;
                                
				XMLRepository rep = BuildingContext.getContext().getXMLRepository();
				XMLQuery q_top = rep.getQueryInstance();
				XMLQuery q_general = rep.getQueryInstance();
				XMLQuery q_generald = rep.getQueryInstance();
				XMLQuery q_title = rep.getQueryInstance();
				XMLQuery q_langstring = rep.getQueryInstance();
				XMLQuery q_string = rep.getQueryInstance();
				XMLQuery q_description = rep.getQueryInstance();
				XMLQuery q_langstringd = rep.getQueryInstance();
				XMLQuery q_stringd = rep.getQueryInstance();
				
				q_top.combination = XMLQuery.COMBINE_UNION;
				
				if ( general_title_opt.equals( "a" ) )
				    {
					q_string.combination = XMLQuery.COMBINE_UNION;
					q_stringd.combination = XMLQuery.COMBINE_UNION;
					}
				else
				    {
					q_string.combination = XMLQuery.COMBINE_INTERCEPT;
					q_stringd.combination = XMLQuery.COMBINE_INTERCEPT;
					}

				StringTokenizer tok = new StringTokenizer( general_title );
				String token;
				while ( tok.hasMoreTokens() )
					{
					token = tok.nextToken();
    				q_string.words.addElement( token );
    				q_stringd.words.addElement( token );
    				}
				q_string.word_strength = strength;
				q_stringd.word_strength = strength;
				
				q_string.title_criterion = "? = 'resource_id'";		//search only for metadata attached to resources
            q_string.relationship = XMLQuery.RELATE_CHILD;
				q_stringd.title_criterion = "? = 'resource_id'";		//search only for metadata attached to resources
            q_stringd.relationship = XMLQuery.RELATE_CHILD;
				
				// ..in a langstring 
				q_langstring.element_name = "langstring";
            q_langstring.relationship = XMLQuery.RELATE_CHILD;
				q_langstringd.element_name = "langstring";
            q_langstringd.relationship = XMLQuery.RELATE_CHILD;


				// ...in a title
				q_title.element_name = "title";
            q_title.relationship = XMLQuery.RELATE_CHILD;

				q_description.element_name = "description";
            q_description.relationship = XMLQuery.RELATE_CHILD;
                
                
				//...in general section
				q_general.element_name = "general";
				q_generald.element_name = "general";

				q_string.addElement( q_langstring	);
				q_langstring.addElement( q_title	);
				q_title.addElement( q_general 		);

				q_stringd.addElement( q_langstringd	);
				q_langstringd.addElement( q_description	);
				q_description.addElement( q_generald 		);


			
			Vector list;
			
			if ( general_elements.equals( "a" ) )
				list = session.searchMetadata( q_string );
			else if ( general_elements.equals( "b" ) )
				list = session.searchMetadata( q_stringd );
			else
				{
				q_top.addElement( q_string );
				q_top.addElement( q_stringd );
				list = session.searchMetadata( q_top );
				}

			if ( list == null || list.size()<1 )
				{
				out.println( "<P>No records were found.</P>" );
				return;
				}

			
			if ( list.size()>100 )
				out.println( "<P>More than one hundred resources were found, the first one hundred are listed here but you should refine your search.</P>" );
			else
				out.println( "<P>Number of resources found: " + list.size() + "</P>" );
	
	
				XMLObjectRecord record;
				Resource found_resource;
				boolean viewable;
				for ( int i=0; i<list.size(); i++ )
					{
					record = (XMLObjectRecord)list.elementAt( i );
					found_resource = Resource.findResource( new PrimaryKey( record.getReference().intValue() ) );
					if ( found_resource!=null )
						{
						viewable = found_resource.checkPermission( Permission.VIEW );
						
						out.print( "<HR>" );
						out.print( "<H4>" );
						if ( viewable )
							{
							out.print( "<A TARGET=_top HREF=\"" );
							out.print( req.getContextPath() );
							out.print( req.getServletPath() );
							out.print( found_resource.getFullName() );
							out.print( "\">" );
							}
						out.print( found_resource.getTitle() );
						if ( viewable )
							out.println( "</A>" );

						out.print( "</H4>" );

						if ( !viewable )
							out.println( "<P><I>You are not on the access list for this item.</I></P>" );
						out.print( "<P>" );
						out.print( found_resource.getDescription() );
						out.println( "</P>" );
						}
					}
					
			
		    }
		catch ( BuildingServerException bsex )
		    {
    		out.println( "<PRE>" );
    		out.println( bsex.getMessage() );
    		out.println( "</PRE>" );
		    }
		
		
		return;
		}

	private void importresource( Request req, PrintWriter out, String name )
		throws ServletException, IOException
		{
		if ( name.equals( "imspackage" ) )
			{
			importimspackage( req, out );
			return;
			}
			
		out.println( "<P>Unknown resource import option.</P>" );
		}
		
	private void importimspackage( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		String zipfile, str;
		boolean parentacl;
		BuildingSession session;

		String url=req.getParameter( "url" );
		

		zipfile = req.getParameter( "file" );
		if ( zipfile==null || zipfile.length()<1 )
			{
			out.println( "No package was uploaded for import." );
			return;
			}

		str = req.getParameter( "parentacl" );
		parentacl = str!=null && str.equalsIgnoreCase( "yes" );

		
		try
			{
			session = BuildingSessionManagerImpl.getSession( req.getResource() );
			if ( session==null )
  				throw new BuildingServerException( "Unable to access the destination resource." );
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "importimspackage", 
			    "A technical problem occured.",
			    ex );
			return;
			}


		        
		try
			{
			session.importImsPackage( url, parentacl, zipfile );
								
			out.println( "<HR>Package import succeeded.<HR>" );
			out.flush();
			}
		catch ( Exception ex )
			{
			logException( out, "Facility", "importimspackage", 
			    "A technical problem occured.",
			    ex );
			return;
			}
		}
		
	private void zonecontrol( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		Zone z;
		PrimaryKey zid = req.getResource().getZoneId();
		Enumeration zones=null;

		try
			{
			zones = Zone.findZones( "zone_id IS NOT NULL" );
			}
		catch ( BuildingServerException bsex )
			{
			logException( out, "Facility", "zonecontrol", 
			    "Technical problem finding zone list.",
			    bsex );
			return;
			}
		
		out.println( "<SELECT NAME=zone_id>" );
		out.print( "<OPTION VALUE=\"null\"" );
		if ( zid == null )
			out.print( " SELECTED" );
		out.print( ">" );
		out.println( "Zone Inherited</OPTION>" );

		
		while ( zones.hasMoreElements() )
			{
			z = (Zone)zones.nextElement();
			out.print( "<OPTION VALUE=\"" );
			out.print( z.getZoneId().toString() );
			out.print( "\"" );
			if ( zid != null && zid.equals( z.getZoneId() ) )
				out.print( " SELECTED" );
			out.print( ">" );
			out.print( z.getName() );
			out.println( "</OPTION>" );
			}
			
		out.print( "</SELECT>" );
		}
		
	private void zoneconfirm( Request req, PrintWriter out )
		throws ServletException, IOException
		{
		PrimaryKey old = req.getResource().getZoneId();
		
		try
			{
			String str_zid = req.getParameter( "zone_id" );
			
			if ( str_zid == null || str_zid.length()==0 )
				return;
			
			if ( str_zid.equals( "null" ) )
				{
				req.getResource().setZoneId( null );
				req.getResource().save();
				out.println( "Specific zone cleared - zone will be inherited from container." );
				return;
				}

			
			PrimaryKey zid;
			Zone z;
			
			zid = new PrimaryKey( Integer.parseInt( str_zid ) );
			z = Zone.findZone( zid );
			
			if ( z== null )
				{
				out.println( "Unknown zone - changes not saved." );
				return;
				}
				
			req.getResource().setZoneId( zid );
			req.getResource().save();
			out.println( "Zone selection saved." );
			}
		catch ( BuildingServerException bsex )
			{
			logException( out, "Facility", "zonecontrol", 
			    "Technical problem finding zone list.",
			    bsex );
			req.getResource().setZoneId( old );
			return;
			}
		}
		
	/**
	 * Returns a url with the current authenticated username appended to query
	 * uhi:awc
	 *
	 * @param req The Building HTTP request.
	 * @param loginUrl the url (with query)
	 * @return the current authenticated username appended to url query
	 */
    private String getUsernameLoginUrl(Request req, String loginUrl)
        {

        String username = getUsername(req);
        if (username == null)
            return loginUrl;

        int i = loginUrl.indexOf('=');
        int j = loginUrl.indexOf('?');

        if (i > 0 && j > 0 && i > j)
        {
            loginUrl = loginUrl.substring(0, i + 1);
            loginUrl += username;
        }
        else
        {
            Logger.getLogger( "org.bodington" ).logp(
            Level.INFO,
            "Facility",
            "getUsernameLoginUrl",
            "Bad url query syntax");
        }

        return loginUrl;
        }

    /**
	 * Rturns the current authenticated username
	 * uhi:awc
	 *
	 * @param req The Building HTTP request.
	 * @return the current authenticated username or NULL if user is anonymous or has not been authenticated
	 */
    public String getUsername(Request req)
		{
        String msg;

        try {
            NavigationSession nav_session = req.getServerNavigationSession();
            if ( nav_session.isAnonymous() )
                return null;

            if (!nav_session.isAuthenticated() )
                msg = "Session is not authenticated - username unknown.";
            else
            {
                User user = (User)BuildingContext.getContext().getUser();
                if ( user==null || user.getUserId()==null )
                    msg = "User object or Userid is null - username not found.";
                else
                {
                    PassPhrase phrase = (PassPhrase)PersistentObject.findPersistentObject(
                            "user_id = " + user.getUserId(), "org.bodington.server.realm.PassPhrase" );
                    if (phrase == null || phrase.getUserName() == null)
                        msg ="PassPhrase object or UserName is null - username not found.";
                    else
                        return phrase.getUserName();
                }
            }
        } catch (Exception ex) {
            msg = "username not found: " + ex.toString();
            // just log exception
        }
         Logger.getLogger( "org.bodington" ).logp(
            Level.INFO,
            "Facility",
            "getUsername",
            msg);

        return null;
        }

	private void generatemanifest(  Request req, PrintWriter out )
		throws IOException
		{
		BuildingSession session;

		try
		    {
   			session = BuildingSessionManagerImpl.getSession( req.getResource() );
   			if ( session==null )
   				throw new BuildingServerException( "Unable to access the destination resource." );

			session.generateImsManifest();
			out.println( "<P>Manifest generated OK.</P>" );
		    }
		catch ( BuildingServerException bsex )
		    {
		    out.println( "<P>An error occurred trying to generate the manifest.</P>" );
    		out.println( "<PRE>" );
    		out.println( bsex.getMessage() );
    		out.println( "</PRE>" );
		    }
		
		
		return;
		}


        public String getHttpSessionCount()
        {
            return Integer.toString( org.bodington.servlet.HttpSession.getSessionCount() );
        }
    //uhi:awc get size and colour preferences
    /**
	 * Rturns  size and colour preferences
	 * uhi:awc
	 *
	 * @param req The Building HTTP request.
     * @param key The
	 * @return the current authenticated username or NULL if user is anonymous or has not been authenticated
	 */
    public String getSessionDataPreference( Request req, String key )
    {
		String value;
        StyleSheetSessionData sss_data;
        org.bodington.servlet.HttpSession http_session;
        
		http_session = (org.bodington.servlet.HttpSession)req.getSession( false );
		if ( http_session == null )
		    return null;

		sss_data = this.getStyleSheetSessionData( http_session );
        try {
            value =  sss_data.getPreference(http_session, key);
        } catch (Exception e) {
            return null;
        }
        return value;
    }

    public String getPreference( Request req, String key )
    {
        org.bodington.servlet.HttpSession http_session = 
            (org.bodington.servlet.HttpSession)req.getSession( false );
        if ( http_session == null )
            return null;
        return http_session.getPreference( key );
    }
    
    public String getAutomaticPreferenceByScreenSize( 
        Request req, 
        String key, 
        String small_default, 
        String big_default )
    {
        org.bodington.servlet.HttpSession http_session = 
            (org.bodington.servlet.HttpSession)req.getSession( false );
        if ( http_session == null )
            return null;
        return http_session.getAutomaticPreferenceByScreenSize( key, small_default, big_default );
    }
    
    
    /** This method is for development and test use since
     * it processes form data where user directly enters
     * string values for user preferences.
     * @param req The Bodington Servlet request from which
     * form data will be fetched.
     * @param key The name of the user preference.
     */    
    public void processPreference( org.bodington.servlet.Request req, String key )
	{
            org.bodington.servlet.HttpSession http_session;
            http_session = (org.bodington.servlet.HttpSession)req.getSession( false );
            if ( http_session == null )
                return;

            String value = req.getParameter( key );
            if ( value == null )
                return;

            http_session.setPreference( key, value );
        }
       
        public Locale getLocale( Request req )
        {
            ResourceBundleHelper resource_bundle_helper;
            resource_bundle_helper = 
             ResourceBundleHelper.getResourceBundleHelper( "", req.getHeader( "Accept-Language" ) );
            if ( resource_bundle_helper == null )
                return null;
            return resource_bundle_helper.getTopLocale();
        }
    
	/**
	 * Returns a localised string from a resource bundle according to language
         * preferences determined from the HTTP request headers.
         */
        public String getLocalisedString( Request req, String properties_name, String id )
        {
            ResourceBundleHelper resource_bundle_helper;
            resource_bundle_helper = 
             ResourceBundleHelper.getResourceBundleHelper( properties_name, req.getHeader( "Accept-Language" ) );
            if ( resource_bundle_helper == null )
                return null;
            return resource_bundle_helper.getString( id );
        }

        /**
	 * writes a localised string from a resource bundle according to language
         * preferences determined from the HTTP request headers.
         */
        public void writeLocalisedString( Request req, PrintWriter writer, String properties_name, String id )
        {
            String str = getLocalisedString( req, properties_name, id );
            if ( str != null )
                writer.print( str );
        }
        
        	
        	
        	
        }
        
        		
