/* ======================================================================
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.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 org.apache.crimson.tree.*;

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


	
	
	//Hashtable templates;
	Integer id;
	public String facilityname;
	//Facility deffacility;

	static DateFormat serverdateformat, shortserverdateformat, mediumserverdateformat, gmtdateformat;
	static TimeZone servertimezone;

	static
		{
		//information from www.ast.cam.ac.uk
		//British Summer Time ought to be regularised by EEC
		//convention from 1998 on (at least) to 2001 as
		//starting from last Sunday in March ending last Sunday
		//in October.  Changes take place at 1am GMT.

        //String tzids[] = TimeZone.getAvailableIDs();
        //int tz;
        //Logger.getLogger( "org.bodington" ).fine( "Time Zone IDs..." );
        //for ( tz=0; tz<tzids.length; tz++ )
        //    {
        //    Logger.getLogger( "org.bodington" ).fine( tzids[tz] );
        //    }


		gmtdateformat=DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.SHORT );
		gmtdateformat.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
		//shortserverdateformat=DateFormat.getDateInstance( DateFormat.SHORT );
		shortserverdateformat=(DateFormat)new SimpleDateFormat( "d/M/yyyy" );
		mediumserverdateformat=DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT );
		serverdateformat=DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.FULL );
		servertimezone = new SimpleTimeZone( 0, "GMT",   //based on existing GMT time zone but with daylight saving
					/*MARCH*/   2, /*LAST*/ -1, /*SUNDAY*/ 1, /*1amGMT*/ 60*60*1000,
					/*OCTOBER*/ 9, /*LAST*/ -1, /*SUNDAY*/ 1, /*1amGMT*/ 60*60*1000 );
		serverdateformat.setTimeZone( servertimezone );
		shortserverdateformat.setTimeZone( servertimezone );
		mediumserverdateformat.setTimeZone( servertimezone );

        //Logger.getLogger( "org.bodington" ).fine( "Time Zone IDs..." );
        //tzids = TimeZone.getAvailableIDs();
        //for ( tz=0; tz<tzids.length; tz++ )
        //    {
        //    Logger.getLogger( "org.bodington" ).fine( tzids[tz] );
        //    }

		}

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

	public static String formatDate( java.util.Date d, int detail ) 
		throws IOException
		{
		String str, gmtstr;
		switch ( detail )
			{
			case 1:
				str = shortserverdateformat.format(d);
				break;
			case 2:
				str = mediumserverdateformat.format(d);
				break;
			default:
				str = serverdateformat.format(d);
				break;
			}
		return str;
		}

	public static void outputDate( PrintWriter out, java.util.Date d, int detail ) 
		throws IOException
		{
		String str=formatDate( d, detail );
		out.print( str );
		}





	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>" );
				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
			{
			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() );
			    }
			}
		}

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

        
        private 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;
        }
        
	private 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();
        
        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 + "')";
		}
                
                String nav_background_colour = session.getProperty( "style_navigation_background_colour", "#007c88" );
                String nav_foreground_colour = session.getProperty( "style_navigation_foreground_colour", "#ffffff" );
                String nav_emphasis_colour = session.getProperty( "style_navigation_emphasis_colour", "#ffa401" );
                String nav_extra_emphasis_colour = session.getProperty( "style_navigation_extra_emphasis_colour", "#ff0000" );
		String nav_table_colour = session.getProperty( "style_navigation_table_colour", "#9090b0" );
                String nav_table_emphasis_colour = session.getProperty( "style_navigation_table_emphasis_colour", "#8080b0" );
		
                String nav_link_colour = session.getProperty( "style_navigation_link_colour", "#aaaaff" );
                String nav_link_visited_colour = session.getProperty( "style_navigation_link_visited_colour", "#ccccdd" );
                String nav_link_active_colour = session.getProperty( "style_navigation_link_active_colour", "#333399" );
                String nav_link_hover_colour = session.getProperty( "style_navigation_link_hover_colour", "#8040ff" );

		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 + "')";
		}
                
                String background_colour = session.getProperty( "style_background_colour", "#ccccc0" );
                String foreground_colour = session.getProperty( "style_foreground_colour", "#333366" );
		String table_colour = session.getProperty( "style_table_colour", "#9090b0" );
                String table_emphasis_colour = session.getProperty( "style_table_emphasis_colour", "#8080b0" );
                String emphasis_colour = session.getProperty( "style_emphasis_colour", "#aa6600" );
                String extra_emphasis_colour = session.getProperty( "style_extra_emphasis_colour", "#ff0000" );

                String link_colour = session.getProperty( "style_link_colour", "#403399" );
                String link_visited_colour = session.getProperty( "style_link_visited_colour", "#333380" );
                String link_active_colour = session.getProperty( "style_link_active_colour", "#333399" );
                String link_hover_colour = session.getProperty( "style_link_hover_colour", "#8040ff" );

                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" );
                stylesheetProperty( entry.content, "color", foreground_colour );
                if ( background_image != null )
                {
                    stylesheetProperty( entry.content, "background-image", background_image );
                    stylesheetProperty( entry.content, "background-repeat", "repeat" );
                }

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

                stylesheetEntry( entry.content, ".bodington_navigation_page" );
                stylesheetProperty( entry.content, "color", nav_foreground_colour );
                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_colour );
                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_link_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:visited" );
                stylesheetProperty( entry.content, "color", nav_link_visited_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:active" );
                stylesheetProperty( entry.content, "color", nav_link_active_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page a:hover" );
                stylesheetProperty( entry.content, "color", nav_link_hover_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:link" );
                stylesheetProperty( entry.content, "color", link_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:visited" );
                stylesheetProperty( entry.content, "color", link_visited_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:active" );
                stylesheetProperty( entry.content, "color", link_active_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "a:hover" );
                stylesheetProperty( entry.content, "color", link_hover_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page em" );
                stylesheetProperty( entry.content, "color", nav_emphasis_colour );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, "em" );
                stylesheetProperty( entry.content, "color", emphasis_colour );
                stylesheetProperty( entry.content, "font-style", "normal" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page strong" );
                stylesheetProperty( entry.content, "color", nav_emphasis_colour );
                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", emphasis_colour );
                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", table_emphasis_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bodington_navigation_page .bs-table-acl" );
                stylesheetProperty( entry.content, "background-color", nav_table_emphasis_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-table-opaque" );
                stylesheetProperty( entry.content, "background-color", table_colour );
                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_table_colour );
                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", table_emphasis_colour );
                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_table_emphasis_colour );
                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_emphasis_colour );
                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_colour );
                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_colour );
                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", extra_emphasis_colour );
                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", extra_emphasis_colour );
                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", emphasis_colour );
                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", emphasis_colour );
                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", emphasis_colour );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-messaging-title .bs-messaging-author" );
                stylesheetProperty( entry.content, "color", emphasis_colour );
                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", table_colour ); 
                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", emphasis_colour );
		stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-logbook-menu-command A" );
                stylesheetProperty( entry.content, "color", emphasis_colour );
		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", emphasis_colour );
                stylesheetEndEntry( entry.content );
		
                stylesheetEntry( entry.content, ".bs-logbook-menu-section A:visited" );
                stylesheetProperty( entry.content, "color", emphasis_colour );
                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", emphasis_colour );
		stylesheetProperty( entry.content, "font-weight", "bold" );
                stylesheetEndEntry( entry.content );

                stylesheetEntry( entry.content, ".bs-logbook-entry-date" );
                stylesheetProperty( entry.content, "color", emphasis_colour );
                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 );

                entry.last_modified = System.currentTimeMillis();
                author_style_sheets.put( resource_id, entry );
                return entry;
            }
        }
        
        private StyleSheetEntry compileUserStyleSheet( 
            org.bodington.servlet.HttpSession http_session, StyleSheetSessionData sss_data, 
	    PrimaryKey user_id, StyleSheetEntry entry )
        throws RemoteException, BuildingServerException
        {
       	    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%";
                }
                
		change_colour = !"normal".equals( colour_option );
		
                
                // null value indicates that the user style sheet should not
                // change the colour.
                Color background_colour = nav_session.getPropertyColor( "style_background_colour", new Color( 0xccccc0 ) );
                Color foreground_colour = nav_session.getPropertyColor( "style_foreground_colour", new Color( 0x333366 ) );
                Color nav_background_colour = nav_session.getPropertyColor( "style_navigation_background_colour", new Color( 0x007c88 ) );
                Color nav_foreground_colour = nav_session.getPropertyColor( "style_navigation_foreground_colour", new Color( 0xffffff ) );
                Color preferred_colour;
                ColourPreferenceMapper colour_mapper=new ColourPreferenceMapper();
                ColourPreferenceMapper nav_colour_mapper=new ColourPreferenceMapper();
                
                if ( change_colour )
                {
                    colour_mapper.setReferenceColours( background_colour, foreground_colour );
                    nav_colour_mapper.setReferenceColours( nav_background_colour, nav_foreground_colour );
                    
                    if ( colour_option.equals( "black" ) )
                    {
                        colour_mapper.setType( ColourPreferenceMapper.TYPE_BLACK_ON_WHITE );
                        nav_colour_mapper.setType( ColourPreferenceMapper.TYPE_BLACK_ON_WHITE );
                    }
                    else if ( colour_option.equals( "white" ) )
                    {
                        colour_mapper.setType( ColourPreferenceMapper.TYPE_WHITE_ON_BLACK );
                        nav_colour_mapper.setType( ColourPreferenceMapper.TYPE_WHITE_ON_BLACK );
                    }
                    else if ( colour_option.equals( "contrast" ) )
                    {
                        colour_mapper.setType( ColourPreferenceMapper.TYPE_CONTRAST );
                        nav_colour_mapper.setType( ColourPreferenceMapper.TYPE_CONTRAST );
                    }
                    else if ( colour_option.equals( "soft" ) )
                    {
                        colour_mapper.setType( ColourPreferenceMapper.TYPE_SOFT );
                        nav_colour_mapper.setType( ColourPreferenceMapper.TYPE_SOFT );
                    }
                    else
                    {
                        colour_mapper.setType( ColourPreferenceMapper.TYPE_NORMAL );
                        nav_colour_mapper.setType( ColourPreferenceMapper.TYPE_NORMAL );
                    }
                }
                
                Color emphasis_colour = nav_session.getPropertyColor( "style_emphasis_colour", new Color( 0xffa401 ) );
                Color extra_emphasis_colour = nav_session.getPropertyColor( "style_extra_emphasis_colour", new Color( 0xff0000 ) );
                Color link_colour = nav_session.getPropertyColor( "style_link_colour", new Color( 0xffffff ) );
                Color link_visited_colour = nav_session.getPropertyColor( "style_link_visited_colour", new Color( 0xc0c0c0 ) );
                Color link_active_colour = nav_session.getPropertyColor( "style_link_active_colour", new Color( 0x9393ff ) );
                Color link_hover_colour = nav_session.getPropertyColor( "style_link_hover_colour", new Color( 0xb0b0ff ) );

                Color nav_emphasis_colour = nav_session.getPropertyColor( "style_navigation_emphasis_colour", new Color( 0xffa401 ) );
                Color nav_extra_emphasis_colour = nav_session.getPropertyColor( "style_navigation_extra_emphasis_colour", new Color( 0xff0000 ) );
		Color nav_table_colour = nav_session.getPropertyColor( "style_navigation_table_colour", new Color( 0x9090b0 ) );
                Color nav_table_emphasis_colour = nav_session.getPropertyColor( "style_navigation_table_emphasis_colour", new Color( 0x8080b0 ) );
                Color nav_link_colour = nav_session.getPropertyColor( "style_navigation_link_colour", new Color( 0xaaaaff ) );
                Color nav_link_visited_colour = nav_session.getPropertyColor( "style_navigation_link_visited_colour", new Color( 0xccccdd ) );
                Color nav_link_active_colour = nav_session.getPropertyColor( "style_navigation_link_active_colour", new Color( 0x333399 ) );
                Color nav_link_hover_colour = nav_session.getPropertyColor( "style_navigation_link_hover_colour", new Color( 0x8040ff ) );
                
                if ( change_size || change_colour )
                {
                    stylesheetEntry( entry.content, "body" );
                    if ( change_size )
                        stylesheetProperty( entry.content, "font-size", font_size );
                    
		    
                    if ( change_colour )
                    {
                        preferred_colour = colour_mapper.getPreferredBackgroundColor();
                        if ( !background_colour.equals( preferred_colour ) )
			{
                            stylesheetProperty( entry.content, "background-color", "#" + Integer.toHexString( preferred_colour.getRGB() ).substring( 2 ) );
			    stylesheetProperty( entry.content, "background-image", "none" );
			}
                        preferred_colour = colour_mapper.getPreferredForegroundColor( foreground_colour );
                        if ( !foreground_colour.equals( preferred_colour ) )
                            stylesheetProperty( entry.content, "color", "#" + Integer.toHexString( preferred_colour.getRGB() ).substring( 2 ) );
                    }
                    stylesheetEndEntry( entry.content );

		    // the white background colour scheme
		    // needs to put dark background on images in case they are white
		    
		    // don't need to do this if the icons can change colour
		    //if ( colour_option.equals( "black" )  )
		    //{
			//stylesheetEntry( entry.content, "img" );
			//stylesheetProperty( entry.content, "background-color", "#000000" );
			//stylesheetEndEntry( entry.content );
		    //}

                    stylesheetEntry( entry.content, ".bodington_navigation_page" );
                    if ( change_size )
                        stylesheetProperty( entry.content, "font-size", font_size );
                    
                    if ( change_colour )
                    {
                        preferred_colour = nav_colour_mapper.getPreferredBackgroundColor();
                        if ( !nav_background_colour.equals( preferred_colour ) )
			{
                            stylesheetProperty( entry.content, "background-color", "#" + Integer.toHexString( preferred_colour.getRGB() ).substring( 2 ) );
			    stylesheetProperty( entry.content, "background-image", "none" );
			}
                        preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_foreground_colour );
                        if ( !nav_foreground_colour.equals( preferred_colour ) )
                            stylesheetProperty( entry.content, "color", "#" + Integer.toHexString( preferred_colour.getRGB() ).substring( 2 ) );
                    }
                    stylesheetEndEntry( entry.content );
                }

                
                if ( change_colour )
                {
                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_link_colour );
                    if ( !nav_link_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bodington_navigation_page a:link" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_link_visited_colour );
                    if ( !nav_link_visited_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bodington_navigation_page a:visited" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_link_active_colour );
                    if ( !nav_link_active_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bodington_navigation_page a:active" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_link_hover_colour );
                    if ( !nav_link_hover_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bodington_navigation_page a:hover" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( link_colour );
                    if ( !link_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, "a:link" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( link_visited_colour );
                    if ( !link_visited_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, "a:visited" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( link_active_colour );
                    if ( !link_active_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, "a:active" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( link_hover_colour );
                    if ( !link_hover_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, "a:hover" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_emphasis_colour );
                    if ( !nav_emphasis_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bodington_navigation_page em" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bodington_navigation_page strong" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-links-heading" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }
                
                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( nav_emphasis_colour );
                    if ( !nav_emphasis_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, "em" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, "strong" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-messaging-week" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-menu-command" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-menu-command A" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-menu-section A" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-menu-section A:visited" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-entry-author" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                        stylesheetEntry( entry.content, ".bs-logbook-entry-date" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( foreground_colour );
                    if ( !foreground_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bs-messaging-date" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.getPreferredForegroundColor( extra_emphasis_colour );
                    if ( !extra_emphasis_colour.equals( preferred_colour ) )
                    {
                        stylesheetEntry( entry.content, ".bs-messaging-day" );
                        stylesheetProperty( entry.content, "color", preferred_colour );
                        stylesheetEndEntry( entry.content );
                    }

                    preferred_colour = nav_colour_mapper.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 );
                    }
                }
                
                entry.last_modified = System.currentTimeMillis();
                return entry;
            }
        }
        

        
	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( 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() ): " );
				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: " );
				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( "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;
			}
			
		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() );
	    }
	    
	}
	
	
	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 );
	    
	    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() );
            session_cookie.setPath( request.getContextPath() );
	    
	    // 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 )
	{
	    out.print( "<form method=\"post\" 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" );
        }
	

	public void logout( Request req, PrintWriter out )
	{
	    try
	    {
		NavigationSession nav_session = req.getServerNavigationSession();
		if ( nav_session == null )
		    return;
		
		nav_session.clearAuthenticationCredentials();
	    }
	    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;
		        }
		    }
        

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



	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.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;
				}
			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 ( !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;
			}
*/
		}



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

	
	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\">" );
		}
		
			
			
	private void resourceMenuItem( MenuItem item, Request breq, PrintWriter out, String target )
		throws IOException
		{
		// output details of single item
		out.println( "<IMG SRC=" + breq.getContextPath() + "/icons/thread-filler.gif><BR>" );

			
		if ( item.getHRef() != null )
			{
			out.print( "<A" );
			if ( target!=null )
				{
				out.print( " TARGET=\"" );
				out.print( target );
				out.print( "\"" );
				}
			out.print( " HREF=\"" );
			out.print( item.getHRef() );
			out.print( "\">" );
			}

		out.print( "<NOBR>" );
		out.println( "<! " + item.getType() + "!>" );
		if ( item.getType().equals( "container" ) )
			out.print( "<IMG BORDER=0 SRC=bs_template_navigation_folder-small.gif>" );
		else
			out.print( "<IMG BORDER=0 SRC=bs_template_navigation_file-small.gif>" );
			
			
		if ( item.getTitle() != null )
			out.print( item.getTitle() );
		else
			if ( item.getHRef() != null )
				out.print( item.getHRef() );
			else
				out.print( "<I>untitled item</I>" );
			
		out.println( "</NOBR>" );
			

		if ( item.getHRef() != null )
			out.println( "</A>" );
		}

	private void resourceMenuItemChildren( MenuItem item, Request breq, PrintWriter out, String target, boolean self )
		throws IOException
		{
		int i;
		MenuItem child, sibling;
		sibling = (MenuItem)item.getNextSibling();
		

		// children go in a table
		out.println( "<TABLE border=0 cellpadding=0 cellspacing=0>" );

		//children in a single table cell
		for ( i=0; i<item.getChildCount(); i++ )
			{
			child = (MenuItem)item.getChildAt( i );
			
			// put every child in a row of the children table
			out.println( "<TR>" );
			// if self was output then lines are needed to the children
			if ( self  )
				{
				// all but last child need continuation line
				if ( (i+1)<item.getChildCount() )
					out.print( "<TD VALIGN=TOP BACKGROUND=" + breq.getContextPath() + "/icons/thread-line.gif>" );
				else
					out.print( "<TD VALIGN=TOP>" );
				// need "L" line to resource
				out.println( "<IMG SRC=" + breq.getContextPath() + "/icons/thread-empty.gif>" );
				out.println( "</TD>" );
				}

			out.println( "<TD VALIGN=TOP>" );
			resourceMenuItem( child, breq, out, target );
			out.println( "</TD></TR>" );
			
			if ( child.getChildCount()>0 )
				{
				if ( self  )
					{
					// all but last child need continuation line to left of grandchildren
					if ( (i+1)<item.getChildCount() )
						out.print( "<TD VALIGN=TOP BACKGROUND=" + breq.getContextPath() + "/icons/thread-line.gif>" );
					else
						out.print( "<TD VALIGN=TOP>" );
					}
				out.println( "<TD VALIGN=TOP>" );
				resourceMenuItemChildren( child, breq, out, target, true );
				out.println( "</TD></TR>" );
				}
			}
				
		out.println( "</TABLE>" );
		}


	private void resourceMenu( Request breq, PrintWriter out )
		throws IOException
		{
		int i;
		Menu menu;
		MenuItem item, child;
		NavigationSession session;
		
        String tree_attribute = (String)breq.getInsertAttribute( "tree", null );
        boolean tree =  tree_attribute == null                      || 
                        tree_attribute.equalsIgnoreCase( "yes" )    || 
                        tree_attribute.equalsIgnoreCase( "true" )           ;

        String target_attribute = (String)breq.getInsertAttribute( "target", null );

		try
			{
			session = (NavigationSession)BuildingSessionManagerImpl.getSession( org.bodington.server.resources.NavigationSessionImpl.class );
			session.setResource( breq.getResource().getResourceId() );
			
			menu = session.getResourceMenu();
			
			item = (MenuItem)menu.getRoot();
			if ( item.getChildCount()> 0 )
				resourceMenuItemChildren( item, breq, out, target_attribute, false );

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

		}

	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 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;
            
            // 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();
                
            String colour_mapper_code="";
            Template template = null;
            
            try
            {
                
                
                // user colour preferences from http session if previously loaded
                colour_mapper_code="";
                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();
                
                // get current resource too
                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 );
                }

        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;
		boolean range, link, italic;
		int n;
		BuildingContext context;
		Resource resource, current, next;
		context = BuildingContext.getContext();
		FacilityList fl = FacilityList.getFacilities();
		Facility facility;
		Template template;
		String description;
                String colour_mapper_code="";

		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();

			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 )
					{
					description = current.getDescription().trim();
					
					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>" );
						    out.print( "<IMG alt=\"Small icon.\" BORDER=0 SRC=\"" );
						    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;
				    		}

					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() );
						if ( current.checkPermission( Permission.MANAGE ) && (description==null || description.length()==0) )
							{
							out.print( " <A TARGET=_top HREF=\"" );
   							out.print( current.getName() );
   							out.println( "/\" alt=\"Mangage heading\">&gt;</A>" );
							}
						out.println( "</H4>" );
						
						if ( description!=null && description.length()>0 )
							{
		    				out.print( "<DIV CLASS=bs-links-heading-description>" );
        				    out.print( current.getDescription()  );
							if ( current.checkPermission( Permission.MANAGE ) )
								{
								out.print( " <A TARGET=_top HREF=\"" );
   								out.print( current.getName() );
   								out.println( "/\" alt=\"Mangage heading\">&gt;</A>" );
								}
    						out.println( "</DIV>" );
    					    }
						//if ( next!=null && next.getResourceType() != Resource.RESOURCE_HEADING )
						out.println( "</TD>" );
						}
					else
						{

						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( "<IMG alt=\"Icon.\" CLASS=bs-links-icon BORDER=0 SRC=\"" );
						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 ( current.getDescription()!=null && current.getDescription().length()>0 )
							{
							out.print( "<DIV CLASS=bs-links-description>" );
							out.print( current.getDescription()  );
							out.print( "</DIV>" );
							}

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


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

			if ( name.equalsIgnoreCase( "linkout" ) )
				{
				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 ( i>0 )
				    	absurl=absurl+current.getName()+"/";

                    iconurl = absurl + "bs_template_navigation_icon.gif";

        			facility = fl.get( new Integer( current.getHttpFacilityNo() ) );
        			if ( facility!=null )
        			    {
                        template = Template.get( facility.facilityname, current.getImplicitHttpUIStyle(), current.getResourceId(), "icon.gif" );
                        if ( template != null )
                            iconurl = breq.getContextPath() + "/processedgif/templates" + template.getUrl() + colour_mapper_code;
                        }
					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( "\" " );
					out.print( "ALT=\"" );
					if ( branch.hasMoreElements() )
						out.print( "Jump out to: " );
					else
						out.print( "Refresh view onto: " );
					out.print( current.getTitle() );
					out.print( "\">" );
					out.print( "</A>" );
					}
				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;

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


					out.print( "<form method=\"POST\" action=\"bs_template_top.html\">" );
					if ( ues.containsResource( breq.getResource() ) )
                                            writeTemplateGifTag(breq, out, html_body_class, "input", 
                                                "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", 
                                                "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>" );
					}
				catch ( Exception ex )
					{
					//do nowt
					return;
					}
				}
			}
		catch ( BuildingServerException bsex )
			{
			return;
			}

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



    private 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..." );

				
			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 )
					out.print( summary.getUpdatedTime().toString() );
				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" );

				if ( general_title_opt == null )
					general_title_opt = "a";
				if ( general_elements == null )
					general_elements = "a";
				
				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.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;
			}
		}
		

	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() );
        }
        
    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 );
    }
    
    /** 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 );
        }
		
    }

