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

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.bodington.database.PrimaryKey;
import org.bodington.server.BuildingServerException;
import org.bodington.server.resources.Resource;


/**
 * This is the Java class used to instantiate objects from records in the
 * log_books database table.
 * 
 * @author Jon Maber
 */
public class LogBook extends Resource
	{

	/**
	 * A constant that defines which bit in the flags int to use for this flag.
	 */
	public static final int FLAG_USER_CLOSABLE = 1;
	
	/**
	 * Marked as private so can only be accessed via get/set methods.
	 */
	private PrimaryKey	log_book_id;
	private int			log_flags;
	
	
	private transient LogBookSection[] sections=null;
	
	
    /**
     * Used to find out what session class to instantiate if a user wants to
     * interact with this LogBook.
     * 
     * @return The class of the session to instantiate.
     */
    public Class sessionClass()
    	{
        // This method is derived from class org.bodington.server.resources.Resource
        // to do: code goes here
        return org.bodington.logbook.server.LogBookSessionImpl.class;
    	}
    	
    			
    /**
     * This method is required for all database objects in the Bodington System. 
     * In this it simply passes on to the get method for the field that
     * contains the primary key.  This is used by the database code of the
     * Bodington System to identify the object in its cache of database objects.
     * 
     * @return The PrimaryKey object that contains a unique id number for this object.
     */
    public PrimaryKey getPrimaryKey()
		{
        return getLogBookId();
        }

    /**
     * This method is called by the Bodington database code after a new object
     * is saved and therefore inserted as a new record in the database.  Never
     * call this method in user code.
     * 
     * @param key A key (primarykey id number) determined by the database handler of the 
     * Bodington System.
     */
    public void setPrimaryKey(PrimaryKey key)
    	{
    	setLogBookId( key );
    	}
    /**
     * Returns the id of this log book.  Will return null if the log book was
     * instantiated but hasn't yet been saved to the database.
     * 
     * @return The id of the log book or null if it has never been saved.
     */
    	

    public PrimaryKey getLogBookId()
		{
        return log_book_id;
        }

    /**
     * User code should never call this method.  It is called by Bodington system
     * when it loads the log book from the database.  The setUnsaved() method is
     * not called here because this method is only called to instantiate the 
     * database record.
     * 
     * @param key The id of the log book.
     */
    public void setLogBookId(PrimaryKey key)
    	{
    	log_book_id = key;
    	setResourceId( key );
    	}
    	
    	
	/**
	 * Get an integer containing all the flags for this log book.  Mainly
	 * used by the Bodington system when saving this object to the database.
	 * 
	 * @return An integer representing up to 32 flags.
	 */
	public int getLogFlags()
		{
		return log_flags;
		}

	/**
	 * Set all (up to 32) flags at once.  Mainly used by the Bodington
	 * system when loading the object from the database.  The setUnsaved()
	 * method is called if changes are made because this method might be
	 * used to modify an already instantiated object and the "unsaved"
	 * flag used later to conditionally save the object only if it is
	 * different to the database record it was loaded from.
	 * 
	 * @param f An integer representing up to 32 flags.
	 */
	public void setLogFlags( int f )
		{
		if ( f==log_flags ) return;
		log_flags=f;
    	setUnsaved();
		}

	/**
	 * Convenience method for finding out if the user closable flag is set.
	 * 
	 * @return True/false flag.
	 */
	public boolean isUserClosable()
		{
		return (log_flags & FLAG_USER_CLOSABLE) != 0;
		}
	
	/**
	 * Convenience user method for setting a single flag.  If it represents a
	 * change of state the object is marked as having unsaved changes.
	 * 
	 * @param b The value to set the flag to.
	 */
	public void setUserClosable( boolean b )
		{
		if ( isUserClosable() == b )
			return;
		log_flags = log_flags ^ FLAG_USER_CLOSABLE;		
		setUnsaved();
		}

 
 
	
	/**
	 * This class can hold references to the sections that belong to it and
	 * so avoid a lot of database queries but this relies on this invalidate
	 * method being called whenever a section is added, deleted or reordered
	 * in the log book.  Since the only class that will do that is the
	 * LogBookSessionImpl it can easily arrange to call this method every time.
	 * When this object is garbage collected the references to the sections will
	 * be lost and so the sections can be garbage collected too.
	 */
	public void invalidateSections()
		{
		sections = null;
		}




	/**
	 * Find the biggest ordinal number of all the sections in the log book.
	 * 
	 * @return Ordinal of last section.
	 */
	public int getMaxSectionOrdinal()
		throws BuildingServerException
		{
		findLogBookSections();
		if ( sections.length == 0 )
			return 0;
		return sections[sections.length-1].getOrdinal();
		}

   	/**
   	 * If sections haven't changed and they were already loaded from the database
   	 * this just returns an array that was prepared earlier.  Otherwise it calls
   	 * a static finder method in LogBookSection with the log_book_id as the only
   	 * search criterion.
   	 * 
   	 * @return A array of sections in the correct order.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
		
   	public LogBookSection[] findLogBookSections()
		throws BuildingServerException
		{
		if ( sections != null )
			return sections;
			
		Enumeration enumeration = LogBookSection.findLogBookSections( "log_book_id = " + log_book_id, "ordinal" );
		Vector list = new Vector();
		while ( enumeration.hasMoreElements() )
			list.addElement( enumeration.nextElement() );
			
		sections =  (LogBookSection[])list.toArray( new LogBookSection[0] );
		return sections;
		}
   	/**
   	 * Loads all the sections and asks each to find all its questions.  These
   	 * are all compiled in a single Hashtable.
   	 * 
   	 * @return A hashtable of all questions under all sections of this log book.
   	 * @exception org.bodington.server.BuildingServerException
   	 */

   	public Hashtable findLogBookQuestions()
		throws BuildingServerException
		{
		int i, j;
		LogBookQuestion[] questions;
		Hashtable q_table = new Hashtable();
		findLogBookSections();
		
		for ( i=0; i<sections.length; i++ )
			{
			questions = sections[i].findLogBookQuestions();
			for ( j=0; j<questions.length; j++ )
				q_table.put( questions[j].getPrimaryKey(), questions[j] );
			}
			
		return q_table;
		}

   	/**
   	 * Asks the specified section to find all its questions.
   	 * 
   	 * @param section_id The unique id of the section whose questions are of interest.
   	 * @return An array of the questions in the specified section in proper order.
   	 * If no section exists in this log book with the id specified an empty list 
   	 * will be returned.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
   	public LogBookQuestion[] findLogBookQuestions( PrimaryKey section_id )
		throws BuildingServerException
		{
		findLogBookSections();

		for ( int i=0; i<sections.length; i++ )
			{
			if ( sections[i].getPrimaryKey().equals( section_id ) )
				return sections[i].findLogBookQuestions();
			}
			
		return new LogBookQuestion[0];
		}

   	/**
   	 * This static method is used to find and load LogBooks from the database.  
   	 * Code that needs to find LogBooks could call PersistentObject.findPersistentObject
   	 * directly but this method is a neater solution and provides an opportunity for
   	 * specialist initialisation for objects found.
   	 * 
   	 * @param key The primary key (id) of the LogBook to find and load.
   	 * @return Reference to the loaded LogBook or null if not found.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
   	public static LogBook findLogBook( PrimaryKey key )
		throws BuildingServerException
		{
		return (LogBook)findPersistentObject( key, "org.bodington.logbook.server.LogBook" );
		}


    public int getResourceType()
    	{
    	return RESOURCE_LOGBOOK;
    	}

	}
	
