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

import java.sql.*;
import java.util.*;
import java.io.*;

import org.bodington.database.*;
import org.bodington.server.*;
import org.bodington.server.realm.*;
import org.bodington.server.resources.*;
import org.bodington.text.*;


public class Installer
	{
	public static final String[] system_tables =
        {
            "classes", "fields", "objects",
            "xml_objects", "xml_elements", "xml_attributes", 
            "xml_cdata", "xml_tokens", "xml_words" 
        };

        public static final String[] system_sql =
        {
          "/org/bodington/sqldatabase/Setup.sql",
          "/org/bodington/xml/Xml.sql",
          "/org/bodington/server/realm/AliasEditor.sql",
          "/org/bodington/server/resources/HeadingResource.sql"

        };
        
        public static final String sql_upgrade_2_0_to_2_1 = "/org/bodington/installation/upgrade_2_0_to_2_1.sql";
                                      
	public static final String[] tables_sql_in_order = {
          "zones",                  "/org/bodington/server/realm/Zone.sql",
          "users",                  "/org/bodington/server/realm/User.sql",
          "pass_phrases",           "/org/bodington/server/realm/PassPhrase.sql",
          "acls",                   "/org/bodington/server/realm/Acl.sql",
          "aliases",                "/org/bodington/server/realm/Alias.sql",
          "alias_entries",          "/org/bodington/server/realm/AliasEntry.sql",
          "big_strings",            "/org/bodington/text/BigString.sql",
          "resources",              "/org/bodington/server/resources/Resource.sql",
          "groups",                 "/org/bodington/server/realm/Group.sql",
          "members",                "/org/bodington/server/realm/Member.sql",
          "acl_entries",            "/org/bodington/server/realm/AclEntry.sql",
          "uploaded_files",         "/org/bodington/server/resources/UploadedFile.sql",
          "user_details",           "/org/bodington/server/realm/UserDetail.sql",
          "user_event_setups",      "/org/bodington/server/events/UserEventSetup.sql",
          "resource_event_users",   "/org/bodington/server/events/ResourceEventUser.sql",
          "external_links",         "/org/bodington/server/resources/ExternalLink.sql",
          "mcq_papers",             "/org/bodington/assessment/McqPaper.sql",
          "pigeonholes",           "/org/bodington/assessment/PigeonHole.sql",
          "questionnaires",         "/org/bodington/assessment/Questionnaire.sql",
          "textq_papers",           "/org/bodington/assessment/TextQPaper.sql",

          "mcq_questions",          "/org/bodington/assessment/McqQuestion.sql",
          "mcq_results",            "/org/bodington/assessment/McqResult.sql",
          "mcq_responses",          "/org/bodington/assessment/McqResponse.sql",

          "pigeonhole_questions",  "/org/bodington/assessment/PigeonHoleQuestion.sql",
          "pigeonhole_entries",    "/org/bodington/assessment/PigeonHoleEntry.sql",
          "pigeonhole_responses",  "/org/bodington/assessment/PigeonHoleResponse.sql",

          "questionnaire_questions",    "/org/bodington/assessment/QuestionnaireQuestion.sql",
          "questionnaire_results",      "/org/bodington/assessment/QuestionnaireResult.sql",
          "questionnaire_responses",    "/org/bodington/assessment/QuestionnaireResponse.sql",

          "text_questions",            "/org/bodington/assessment/TextQuestion.sql",
          "textq_results",              "/org/bodington/assessment/TextQResult.sql",
          "textq_responses",            "/org/bodington/assessment/TextQResponse.sql",

          "messaging_rooms",            "/org/bodington/messaging/MessagingRoom.sql",
          "messages",                   "/org/bodington/messaging/Message.sql",

          "events",                     "/org/bodington/server/events/Event.sql",
          "assessment_events",          "/org/bodington/server/events/AssessmentEvent.sql",
          "messaging_events",           "/org/bodington/server/events/MessagingEvent.sql",
          "navigation_events",          "/org/bodington/server/events/NavigationEvent.sql",
          "opinion_events",             "/org/bodington/server/events/OpinionEvent.sql",
          "user_events",                "/org/bodington/server/events/UserEvent.sql",
          "user_file_events",           "/org/bodington/server/events/UserFileEvent.sql",
          "user_management_events",     "/org/bodington/server/events/UserManagementEvent.sql",

          "jobs",                       "/org/bodington/server/Job.sql",
          "job_results",                "/org/bodington/server/JobResult.sql",
          "metadata",                   "/org/bodington/text/Metadatum.sql",

          "log_books",                  "/org/bodington/logbook/server/LogBook.sql",
          "log_book_sections",          "/org/bodington/logbook/server/LogBookSection.sql",
          "log_book_questions",         "/org/bodington/logbook/server/LogBookQuestion.sql",
          "log_book_pages",             "/org/bodington/logbook/server/LogBookPage.sql",
          "log_book_entries",           "/org/bodington/logbook/server/LogBookEntry.sql",
          "log_book_events",            "/org/bodington/logbook/server/LogBookEvent.sql"
        };

        
        public static int tableCount()
        {
            return system_tables.length + (tables_sql_in_order.length / 2);
        }
        
	public static String[] extraTables( DatabaseMetaData dbmeta )
		throws SQLException
		{
		return checkTables( dbmeta, true );
		}
		
	public static String[] existingTables( DatabaseMetaData dbmeta )
		throws SQLException
		{
		return checkTables( dbmeta, false );
		}
	
        public static String[] missingTables( String[] tables )
        {
            int i;
            Hashtable existing = new Hashtable();
            for ( i=0; i< tables.length; i++ )
                existing.put( tables[i], tables[i] );

            Vector missing = new Vector();

            for ( i=0; i<system_tables.length; i++ )
                if ( !existing.containsKey( system_tables[i] ) )
                    missing.addElement( system_tables[i] );

            for ( i=0; i<tables_sql_in_order.length; i+=2 )
            {
                if ( !existing.containsKey( tables_sql_in_order[i] ) )
                    missing.addElement( tables_sql_in_order[i] );
            }
            
            String[] list = new String[missing.size()];
            for ( i=0; i<missing.size(); i++ )
                list[i] = (String)missing.elementAt( i );
            
            return list;
        }
        
        public static boolean has2_0Tables( String[] tables )
        {
            // if it has system tables but doesn't have job_results
            // assume it is v.2.0.x
            
            int i, j;
            boolean found;

            for ( j=0; j<system_tables.length; j++ )
            {
                found=false;
                for ( i=0; i<tables.length && !found; i++ )
                    if ( tables[i].equalsIgnoreCase( system_tables[j] ) )
                        found=true;
                
                if ( !found )
                    return false;
            }

            for ( i=0; i<tables.length; i++ )
                if ( "job_results".equalsIgnoreCase( tables[i] ) )
                    return false;
            
            return true;
        }
        
	private static String[] checkTables( DatabaseMetaData dbmeta, boolean extra )
            throws SQLException
            {
		int i;
		String[] types = new String[1];
		types[0] = "TABLE";
		ResultSet results = dbmeta.getTables( null, "%", "%", types );
		Vector list = new Vector();
		String table;
                boolean found;
                Hashtable table_table = new Hashtable();
		while ( results!=null && results.next() )
		{
                    table = results.getString( "TABLE_NAME" );
                    table_table.put( table.toLowerCase(), table.toLowerCase() );
                }
		results.close();
                
		for ( i=0; i<system_tables.length; i++ )
                    if ( table_table.containsKey( system_tables[i] ) )
                        list.addElement( system_tables[i] );
                            
		for ( i=0; i<tables_sql_in_order.length; i+=2 )
                    if ( table_table.containsKey( tables_sql_in_order[i] ) )
                        list.addElement( tables_sql_in_order[i] );
                    
                
                String[] ret;
                if ( !extra )
                {
                    ret = new String[list.size()];
                    for ( i=0; i<ret.length; i++ )
    			ret[i] = (String)list.elementAt( i );
		return ret;
                }
                
                ret = new String[table_table.size()-list.size()];
                Enumeration enum = table_table.keys();
                i=0;
                while ( enum.hasMoreElements() )
                {
                    table = (String)enum.nextElement();
                    if ( !list.contains( table ) )
                        ret[i++] = table;
                }
        	return ret;
            }

	
	public static void deleteTables( Connection con )
		throws SQLException
		{
		DatabaseMetaData dbmeta = con.getMetaData();
		String[] tables = existingTables( dbmeta );
		Statement st = con.createStatement();
		
                for ( int i=tables.length-1; i>=0 ; i-- )
                    st.executeUpdate( "DROP TABLE " + tables[i] );

                st.close();
		}
		

	static int type_length;
	static String alt_type;
	static int next_constraint=1;
	//static String[] generic_sql = { "DEFAULT", "LONG VARCHAR", "LONG VARBINARY", "TIMESTAMP", "CURRENT_TIMESTAMP", "tinyint"  };
	//static String[] ms_sql = { "CONSTRAINT DEF_", "TEXT", "IMAGE", "DATETIME", "getdate()", "int2"  };
	//static String[] ms_sql = { "CONSTRAINT DEF_#", "TEXT", "IMAGE", "DATETIME", "getdate()", "TINYINT"  };

	private static int nextIndex( String line, int n,
											String[] sql_substitutions, 
											String[] sql_alternatives )
		{
		if ( sql_substitutions == null || sql_alternatives == null )
			return -1;
		
		int r, i;
		int[] index= new int[sql_substitutions.length];
		
		// find first instance of each keyword that has an alternative
		for ( i=0; i<sql_substitutions.length && i<sql_alternatives.length; i++ )
			index[i] = line.indexOf( sql_substitutions[i], n );
		
		// of those found which was first?
		r=-1;
		for ( i=0; i<sql_substitutions.length; i++ )
			{
			if ( index[i] >=0 )
				if ( r<0 || index[i]<index[r] )
					r=i;
			}
			
		// return -1 if no keyword found 
		if ( r<0 )
			return -1;
			
		type_length = sql_substitutions[r].length();
		
		// does substitution require insertion of a number?  (e.g. for a constraint)
		// signalled by a # at end of alternative
		
		i=sql_alternatives[r].indexOf( '#' );
		if ( i >= 0 )
			alt_type = sql_alternatives[r].substring( 0, i )  + (next_constraint++) + sql_alternatives[r].substring( i+1 );
		else
			alt_type = sql_alternatives[r];
		
		return index[r];
		}

	public static void executeSQLFromResource( BufferedReader input, Connection c,
																	String[] sql_substitutions, 
																	String[] sql_alternatives )
		throws SQLException, IOException
		{
		int n, m;
        Statement st = c.createStatement();
        StringBuffer buffer = new StringBuffer();
        String line, full;
	        
        line=input.readLine();
        while ( line!=null )
        	{
        	n=0;
        	while ( (m = nextIndex( line, n, sql_substitutions, sql_alternatives )) >=0 )
       			{
       			buffer.append( line.substring( n, m ) );
       			buffer.append( alt_type );
       			n = m + type_length;
      			}
        	buffer.append( line.substring( n, line.length() ) );
        	buffer.append( "\n" );
	        line=input.readLine();
	        
	        if ( line!=null )
	        	{
	        	if ( line.startsWith( "go" ) || line.startsWith( "GO" ) )
	        		{
	        		full = buffer.toString();
			        System.out.println( "EXECUTING SQL STATEMENT ==============================================" );
			        System.out.println( full );
	        		st.executeUpdate( full );
	        		buffer.setLength( 0 );
			        line=input.readLine();
	        		}
	        	}
        	}
        	st.close();
		}

/*
public static synchronized void upgradeTablesFrom2_0(	
    Connection con, 
    Class ref_class, 
    String db_user, 
    String[] sql_substitutions, 
    String[] sql_alternatives )
    throws SQLException, IOException
{
    int i;

    DatabaseMetaData dbmeta = con.getMetaData();
    String[] tables = existingTables( dbmeta );
    Hashtable existing = new Hashtable();
    for ( i=0; i< tables.length; i++ )
        existing.put( tables[i], tables[i] );
    
    Vector sql_to_execute = new Vector();
    sql_to_execute.addElement( sql_upgrade_2_0_to_2_1 );
    
    InputStream instream;
    BufferedReader input;

    //st.executeUpdate( "USE " + dbname );
    for ( i=0; i<sql_in_2_1.length; i++ )
    {
        System.err.println( "Executing SQL from " + sql_in_2_1[i] + "\n" );
        instream = ref_class.getResourceAsStream( sql_in_2_1[i] );
        if ( instream == null )
            throw new IOException( "Data file not found." );
        input = new BufferedReader( new InputStreamReader( instream ) );
        if ( input == null )
            throw new IOException( "Buffered reader not created." );
        executeSQLFromResource( input, con, sql_substitutions, sql_alternatives );
        input.close();
    }

        Statement st = con.createStatement();

        String sysuser = con.getMetaData().getUserName();

    if ( db_user != null && !sysuser.equalsIgnoreCase( db_user ) )
    {
        String sql;
        for ( i=0; i<tables_created_in_2_1.length; i++ )
        {
            sql = "GRANT  SELECT ,  INSERT ,  DELETE ,  UPDATE  ON " + tables_created_in_2_1[i] + " TO " + db_user;
            st.executeUpdate( sql );
        }
    }
    st.close();
}        
  */
        
        
    public static synchronized void createTables(	
        Connection con, 
        Class ref_class, 
        String db_user, 
        String[] sql_substitutions, 
        String[] sql_alternatives,
        boolean upgrade )
        throws SQLException, IOException
    {
        int i;

        DatabaseMetaData dbmeta = con.getMetaData();
        String[] tables = existingTables( dbmeta );
        Hashtable existing = new Hashtable();
        for ( i=0; i< tables.length; i++ )
            existing.put( tables[i], tables[i] );

        Vector sql_to_execute = new Vector();
        
        if ( upgrade )
        {
            sql_to_execute.addElement( sql_upgrade_2_0_to_2_1 );
            sql_to_execute.addElement( "/org/bodington/server/Job.sql" );
        }
        else
        {
            for ( i=0; i<system_sql.length; i++ )
                sql_to_execute.addElement( system_sql[i] );
        }
        
        for ( i=0; i<tables_sql_in_order.length; i+=2 )
        {
            if ( !existing.containsKey( tables_sql_in_order[i] ) )
                sql_to_execute.addElement( tables_sql_in_order[i+1] );
        }
        
        InputStream instream;
        BufferedReader input;
        String sql_file;
        
        //st.executeUpdate( "USE " + dbname );
        for ( i=0; i<sql_to_execute.size(); i++ )
        {
            sql_file = (String)sql_to_execute.elementAt( i );
            System.err.println( "Executing SQL from " + sql_file + "\n" );
            //message.append( "Executing SQL from " + sql_in_order[i] + "\n" );
            instream = ref_class.getResourceAsStream( sql_file );
            if ( instream == null )
                throw new IOException( "Data file not found." );
            input = new BufferedReader( new InputStreamReader( instream ) );
            if ( input == null )
                throw new IOException( "Buffered reader not created." );
            executeSQLFromResource( input, con, sql_substitutions, sql_alternatives );
            input.close();
        }

        
        tables = existingTables( dbmeta );
        Statement st = con.createStatement();

        String sysuser = con.getMetaData().getUserName();

        if ( db_user != null && !sysuser.equalsIgnoreCase( db_user ) )
        {
            String sql;
            //message.append( "Setting permissions on tables.\n" );
            for ( i=0; i<tables.length; i++ )
            {
                sql = "GRANT  SELECT ,  INSERT ,  DELETE ,  UPDATE  ON " + tables[i] + " TO " + db_user;
                st.executeUpdate( sql );
            }
        }
        st.close();
    }

    
    
    
    
	static BuildingServer server;

	static String system_zone_prefix = "sys";
	static String system_zone_name = "System Administration";
	
	static Integer admin_zone_user_group_id;
								
	static Integer sys_zone_user_group_id;
	static Integer sys_zone_staff_group_id;
	static Integer sys_zone_student_group_id;
	static Integer sys_zone_other_group_id;
	static Integer all_user_group_id		;
	static Integer all_staff_group_id		;
	static Integer all_student_group_id	;
	static Integer all_other_group_id		;
								
								
	static String building_name_recycler = "recycler";
	static String building_title_recycler = "Recycling Building";
	static String building_description_recycler = "This building is where deleted resources go.";
	
	static String building_name_admin = "admin";
	static String building_title_admin = "Site Administration Building";
	static String building_description_admin = "This building is for site administation.";
								
								
	static String u_name_sysadmin			= "System Administrator";
	static String u_surname_sysadmin		= "Administrator";
	static String u_initials_sysadmin 	= "SA";
	static String u_user_name_sysadmin	= "sysadmin";
	
	static String u_name_anon1			= "Anonymous Internet User";
	static String u_surname_anon1		= "Anonymous";
	static String u_initials_anon1 	= "AIU1";

	static String u_name_anon2			= "Anonymous Internet User 2";
	static String u_surname_anon2		= "Anonymous";
	static String u_initials_anon2 	= "AIU2";
								

        
        private static void addProperty( PrimaryKey resid, String name, String value )
        throws BuildingServerException
        {
            Metadatum m=new Metadatum();
            m.setObjectId( resid );
            m.setName( name );
            m.setValue( value );
            m.save();                
        }

	public static void createMinimalData( String props_file )
		throws Exception
		{
		int bs_status = BuildingServer.getStatus();
		if ( bs_status != BuildingServer.STATUS_NONE )
			throw new Exception( "Can't setup data because the BuildingServer has already been started." );
		
		System.out.println( "About to create Instance of BuildingServer" );
			
		BuildingServer.createInstance( true, props_file );
		
		System.out.println( "Created Instance of BuildingServer" );

		bs_status = BuildingServer.getStatus();
		if ( bs_status != BuildingServer.STATUS_READY_FOR_SETUP )
			throw new Exception( "Can't setup data because the BuildingServer failed to start." );

		System.out.println( "Instance of BuildingServer in appropriate state." );
		
		int n=1;
		
		// not really ids - these are special group flag numbers
		all_user_group_id		= new Integer(n++);
		all_staff_group_id		= new Integer(n++);
		all_student_group_id	= new Integer(n++);
		all_other_group_id		= new Integer(n++);
		sys_zone_user_group_id= new Integer(n++);
		sys_zone_staff_group_id= new Integer(n++);
		sys_zone_student_group_id= new Integer(n++);
		sys_zone_other_group_id= new Integer(n++);

		
		System.out.println( "About to get BuildingContext." );

		BuildingContext context = BuildingContext.getContext();

		System.out.println( "Got BuildingContext." );
		        
		Object obj=null;
		Zone sys_zone, user_zone;
		User sysadmin, anon1, anon2;
		PassPhrase sysadminpass;
		        
		Group newgroup, allusers, allstaff, allstudents, allothers, sysadmins, anonymi;
		Member newmember;
		Acl siteacl, recycleracl;
		AclEntry newaclentry;
		AliasEditor alias_editor;
		Resource res0, res1, res2, res3, res4, res5, recycler=null, grouptool=null;
		ResourceTree tree;
				


		sys_zone = new Zone();
		sys_zone.setPrefix( system_zone_prefix );
		sys_zone.setName( system_zone_name );
		sys_zone.save();

		sysadmin=new User();
		sysadmin.setName( u_name_sysadmin );
		sysadmin.setSurname( u_surname_sysadmin );
		sysadmin.setInitials( u_user_name_sysadmin );
		sysadmin.setZone( sys_zone );
		sysadmin.save();

		sysadminpass=new PassPhrase();
		sysadminpass.setUserId( sysadmin.getUserId() );
		sysadminpass.setUserName( u_user_name_sysadmin );
		sysadminpass.setUnencryptedPassPhrase( u_user_name_sysadmin );
		sysadminpass.save();

		anon1=new User();
		anon1.setName( u_name_anon1 );
		anon1.setSurname( u_surname_anon1 );
		anon1.setInitials( u_initials_anon1);
		anon1.setZone( sys_zone );
		anon1.save();

		anon2=new User();
		anon2.setName( u_name_anon2 );
		anon2.setSurname( u_surname_anon2 );
		anon2.setInitials( u_initials_anon2 );
		anon2.setZone( sys_zone );
		anon2.save();

      context.setUser( sysadmin );


		tree = ResourceTree.getInstance();
		
		res0=new Resource();
		res0.setZone( sys_zone );
		res0.setName( "site" );
		res0.setTitle( "Bodington System Site" );
		res0.setDescription( "This site description may appear in search results but is not normally visible " +
									"when simply navigating the site. " );
		res0.setIntroduction( "This is a web site newly created with the Bodington System. The system " +
									"administrator can change this text, the title of the site and create " +
									"resources by logging in and using the commands that will appear on the pages. " );
		res0.setHttpFacilityNo( 24 );
		tree.addResource( null, res0 );

                addProperty( res0.getResourceId(), "style_specified", "yes" );
                addProperty( res0.getResourceId(), "style_background_colour", "#f0f0e0" );
                addProperty( res0.getResourceId(), "style_background_image", "none" );
                addProperty( res0.getResourceId(), "style_foreground_colour", "#202040" );
                addProperty( res0.getResourceId(), "style_emphasis_colour", "#aa6600" );
                addProperty( res0.getResourceId(), "style_link_colour", "#403399" );
                addProperty( res0.getResourceId(), "style_link_visited_colour", "#333380" );
                addProperty( res0.getResourceId(), "style_link_active_colour", "#333399" );
                addProperty( res0.getResourceId(), "style_link_hover_colour", "#000066" );
                addProperty( res0.getResourceId(), "style_graphic_background_colour", "#f0f0e0" );
                addProperty( res0.getResourceId(), "style_graphic_foreground_colour", "#202040" );
                
                addProperty( res0.getResourceId(), "style_navigation_background_colour", "#007c88" );
                addProperty( res0.getResourceId(), "style_navigation_background_image", "none" );
                addProperty( res0.getResourceId(), "style_navigation_foreground_colour", "#ffffff" );
                addProperty( res0.getResourceId(), "style_navigation_emphasis_colour", "#ffa401" );
                addProperty( res0.getResourceId(), "style_navigation_link_colour", "#aaaaff" );
                addProperty( res0.getResourceId(), "style_navigation_link_visited_colour", "#aaaaee" );
                addProperty( res0.getResourceId(), "style_navigation_link_active_colour", "#333399" );
                addProperty( res0.getResourceId(), "style_navigation_link_hover_colour", "#ffffff" );
                addProperty( res0.getResourceId(), "style_navigation_graphic_background_colour", "#007c88" );
                addProperty( res0.getResourceId(), "style_navigation_graphic_foreground_colour", "#ffffff" );
                
		siteacl=res0.getAcl();
		Enumeration entries = siteacl.entries();
		if ( entries.hasMoreElements() )
	      {
	      newaclentry = (AclEntry)entries.nextElement();
	      newaclentry.addPermission( Permission.SYSADMIN );
	      newaclentry.save();
	      }

		res1=new Resource();
		res1.setName( building_name_admin );
		res1.setTitle( building_title_admin );
		res1.setDescription( building_description_admin );
		res1.setIntroduction( building_description_admin );
		res1.setHttpFacilityNo( 23 );
		tree.addResource( res0, res1 );

		recycler=new Resource();
		recycler.setName( building_name_recycler );
		recycler.setTitle( building_title_recycler );
		recycler.setDescription( building_description_recycler );
		recycler.setIntroduction( building_description_recycler );
		recycler.setHttpFacilityNo( 30 );
		recycler.setHttpUIStyle( new Integer( 0 ) );
		tree.addResource( res0, recycler );
		recycleracl=recycler.getAcl();

		res2=new Resource();
		res2.setName( "ground" );
		res2.setTitle( "Ground Floor" );
		res2.setDescription( "Ground floor contains tools for administering the site." );
		res2.setIntroduction( "Ground floor contains tools for administering the site." );
		res2.setHttpFacilityNo( 3 );
		tree.addResource( res1, res2 );
		
		
		
		res3=new Resource();
		res3.setName( system_zone_prefix );
		res3.setTitle( "User Administration for " + system_zone_name + " zone." );
		res3.setDescription( "Contains tools for administration of users." );
		res3.setIntroduction( "This room contains tools for administration of users." );
		res3.setHttpFacilityNo( 5 );
		tree.addResource( res2, res3 );
		       	
		res4=new AliasEditor();
		res4.setName( "userid" );
	   res4.setTitle( "Unique Identifier Tool" );
		res4.setDescription( "Use this tool to manage identifiers for users." );
	   res4.setIntroduction( "Use this tool to manage identifiers for users." );
		res4.setHttpFacilityNo( 25 );
		tree.addResource( res3, res4 );

		res4=new AliasEditor();
		res4.setName( "usercreate" );
	   res4.setTitle( "User Creation Tool" );
		res4.setDescription( "Use this tool to create users." );
	   res4.setIntroduction( "Use this tool to create users." );
		res4.setHttpFacilityNo( 26 );
		tree.addResource( res3, res4 );

		res4=new AliasEditor();
		res4.setName( system_zone_prefix );
	   res4.setTitle( "Groups of Users" );
		res4.setDescription( "Use this tool to put users into named groups." );
	   res4.setIntroduction( "Use this tool to put users into named groups." );
		res4.setHttpFacilityNo( 27 );
		tree.addResource( res3, res4 );

		grouptool = res4;

		res5=new Resource();
		res5.setName( "anonymous" );
		res5.setTitle( "anonymous" );
		res5.setDescription( "People who access the site without logging in." );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      anonymi = new Group();
      anonymi.setResourceId( res5.getResourceId() );
      anonymi.setName( "anonymous" );
      anonymi.setDescription( res5.getDescription() );
      anonymi.save();
		anonymi.addMember( anon1 );
		anonymi.addMember( anon2 );
      anonymi.save();
		

		res5=new Resource();
		res5.setName( "allusers" );
		res5.setTitle( "allusers" );
		res5.setDescription( "All types of users who have accounts in the system for this site."  );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      allusers = new Group();
      allusers.setResourceId( res5.getResourceId() );
      allusers.setName( "allusers" );
      allusers.setDescription( res5.getDescription() );
      allusers.setSpecialGroup( all_user_group_id );
      allusers.save();
		allusers.addMember( sysadmin );
      allusers.save();
        	

		res5=new Resource();
		res5.setName( "allstudents" );
		res5.setTitle( "allstudents" );
		res5.setDescription( "All students who have accounts in the system for this site."  );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      allstudents = new Group();
      allstudents.setResourceId( res5.getResourceId() );
      allstudents.setName( "allstudents" );
      allstudents.setDescription( res5.getDescription() );
      allstudents.setSpecialGroup( all_student_group_id );
      allstudents.save();
        	
		res5=new Resource();
		res5.setName( "allstaff" );
		res5.setTitle( "allstaff" );
		res5.setDescription( "All staff who have accounts in the system for this site."  );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      allstaff = new Group();
      allstaff.setResourceId( res5.getResourceId() );
      allstaff.setName( "allstaff" );
      allstaff.setDescription( res5.getDescription() );
      allstaff.setSpecialGroup( all_staff_group_id );
      allstaff.save();
        	
		res5=new Resource();
		res5.setName( "allothers" );
		res5.setTitle( "allothers" );
		res5.setDescription( "All users, other than staff abd students who have accounts in the system for this site."  );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      allothers = new Group();
      allothers.setResourceId( res5.getResourceId() );
      allothers.setName( "allothers" );
      allothers.setDescription( res5.getDescription() );
      allothers.setSpecialGroup( all_other_group_id );
      allothers.save();
		allothers.addMember( sysadmin );
      allothers.save();
        	
		res5=new Resource();
		res5.setName( "sysadmins" );
		res5.setTitle( "sysadmins" );
		res5.setDescription( "System administrators for this web site."  );
		res5.setIntroduction( res5.getDescription() );
		res5.setHttpFacilityNo( 6 );
		tree.addResource( res4, res5 );
      sysadmins = new Group();
      sysadmins.setResourceId( res5.getResourceId() );
      sysadmins.setName( "sysadmins" );
      sysadmins.setDescription( res5.getDescription() );
      sysadmins.save();
      sysadmins.addMember( sysadmin );
      sysadmins.save();
		sysadmins.addMember( sysadmin );
      sysadmins.save();


		
	   newaclentry = new AclEntry();
	   newaclentry.setPrincipal( allusers );
	   newaclentry.addPermission( Permission.SEE );
	   newaclentry.addPermission( Permission.VIEW );
	   siteacl.addEntry( newaclentry );
	   siteacl.save();
		
	   newaclentry = new AclEntry();
	   newaclentry.setPrincipal( anonymi );
	   newaclentry.addPermission( Permission.SEE );
	   newaclentry.addPermission( Permission.VIEW );
	   siteacl.addEntry( newaclentry );
	   siteacl.save();
		
	   newaclentry = new AclEntry();
	   newaclentry.setPrincipal( allusers );
	   newaclentry.addPermission( Permission.SEE );
	   newaclentry.addPermission( Permission.VIEW );
	   newaclentry.addPermission( Permission.CREATE );
	   recycleracl.addEntry( newaclentry );
	   recycleracl.save();
	   
	   BuildingServer.setupComplete();
		}
	
public static void moveGeneratedMenusFrom2_0( File old_gen_pub_dir )
throws IOException, BuildingServerException
{
    PassPhrase pass_phrase = PassPhrase.findPassPhrase( "user_name = 'sysadmin'" );
    Resource resource = ResourceTree.getInstance().findRootResource();
    
       Job j = new Job();
       
        j.setUserId( pass_phrase.getUserId() );
        j.setResourceId( resource.getResourceId() );
        j.setSessionName( "org.bodington.installation.FileUpgrader2_0_to_2_1" );
        j.setMethodName( "fetchMenus" );
        j.setParameter( old_gen_pub_dir.getAbsolutePath() );
        j.setState( Job.STATE_OVERDUE );
        j.setSubmissionTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setFromTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setToTime( null );
	j.setRepeatSpec( 0 );
	j.setRepeatType( Job.REPEAT_TYPE_ONCE );
        j.setRepeatPeriod( 1 );
	j.setFirstExecutionTime();
        j.save();
	
	
}

		
		
public static void createDemoData( String param )
throws IOException, BuildingServerException
{
    PassPhrase pass_phrase = PassPhrase.findPassPhrase( "user_name = 'sysadmin'" );
    Resource resource = ResourceTree.getInstance().findRootResource();
    
       Job j = new Job();
       
        j.setUserId( pass_phrase.getUserId() );
        j.setResourceId( resource.getResourceId() );
        j.setSessionName( "org.bodington.installation.DemoSiteBuilder" );
        j.setMethodName( "createSite" );
        j.setParameter( param );
        j.setState( Job.STATE_OVERDUE );
        j.setSubmissionTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setFromTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setToTime( null );
	j.setRepeatSpec( 0 );
	j.setRepeatType( Job.REPEAT_TYPE_ONCE );
        j.setRepeatPeriod( 1 );
	j.setFirstExecutionTime();
        j.save();
	
}

public static void moveUploadedFilesFrom2_0( File old_web_pub_dir )
throws IOException, BuildingServerException
{
    PassPhrase pass_phrase = PassPhrase.findPassPhrase( "user_name = 'sysadmin'" );
    Resource resource = ResourceTree.getInstance().findRootResource();
    
       Job j = new Job();
       
        j.setUserId( pass_phrase.getUserId() );
        j.setResourceId( resource.getResourceId() );
        j.setSessionName( "org.bodington.installation.FileUpgrader2_0_to_2_1" );
        j.setMethodName( "fetchFiles" );
        j.setParameter( old_web_pub_dir.getAbsolutePath() );
        j.setState( Job.STATE_OVERDUE );
        j.setSubmissionTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setFromTime( new java.sql.Timestamp( System.currentTimeMillis() )       );
        j.setToTime( null );
	j.setRepeatSpec( 0 );
	j.setRepeatType( Job.REPEAT_TYPE_ONCE );
        j.setRepeatPeriod( 1 );
	j.setFirstExecutionTime();
        j.save();
	
	
}

public static String getJobStatus( String class_name, String function )
throws BuildingServerException
{
    Enumeration enum = Job.findJobs( 
	"session_name = '" + class_name + "' AND method_name = '" + function + "'", "submission_time" );
    
    if ( !enum.hasMoreElements() )
	return null;
    
    // find most recent submitted job
    Job job = null;
    while ( enum.hasMoreElements() )
	job = (Job)enum.nextElement();

    // find most recent job result...
    enum = JobResult.findJobResults( "job_id = " + job.getJobId().toString(), "execution_time" );
    if ( !enum.hasMoreElements() )
	return "The job hasn't started yet.";
    
    JobResult job_result = null;
    while ( enum.hasMoreElements() )
	job_result = (JobResult)enum.nextElement();
    
    StringBuffer response = new StringBuffer();
    
    switch ( job_result.getResultCode() )
    {
	case JobResult.RESULT_INCOMPLETE:
	    response.append( "Still processing\n" );
	    break;
	case JobResult.RESULT_OK:
	    response.append( "Completed processing\n" );
	    break;
	case JobResult.RESULT_ERROR:
	    response.append( "Aborted processing\n" );
	    break;
    }
    
    if ( job_result.getBigStringId() == null )
	return response.toString();

    BigString message = BigString.findBigString( job_result.getBigStringId() );
    response.append( message );
    return response.toString();
    
}


	}
