/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================== */

package org.bodington.logbook.server;

import java.sql.Timestamp;
import java.util.Enumeration;

import org.bodington.server.BuildingContext;
import org.bodington.sqldatabase.SqlPersistentObject;
import org.bodington.database.PrimaryKey;
import org.bodington.server.BuildingServerException;
import org.bodington.text.BigString;
import org.bodington.server.realm.User;

/**
 * This class represents an entry made in a page of the log book.
 * Each page belongs to a single user but some people may be granted
 * access to add entries in the pages of other users.
 * 
 * @author Jon Maber
 */
public class LogBookEntry extends SqlPersistentObject
	{
	public static final int FLAG_SEEN       = 1;
	public static final int FLAG_DRAFT  	= 2;
	public static final int FLAG_SELECTED   = 4;
	public static final int FLAG_PRIVATE    = 8; /// PRIVATE and DRAFT are mutually exclusive. PJC 2004-03-25.
	
	
	private PrimaryKey	log_book_entry_id;
	private PrimaryKey	log_book_page_id;
	private PrimaryKey	log_book_question_id;
	private PrimaryKey	user_id;
	private PrimaryKey	entry_big_string_id;
	private int 		flags;
	private java.sql.Timestamp when_modified;
        private String          linked_url;
	
	
	
    /**
     * Simply redirects to getLogBookEntryId().
     * 
     * @return The primary key of the object.
     */
    public PrimaryKey getPrimaryKey()
    	{
        return getLogBookEntryId();
    	}

    /**
     * Called only by bodington database code when loading an object from
     * the database or inserting a new record in the database.
     * 
     * @param key The primary key of the object.
     */
    public void setPrimaryKey(PrimaryKey key)
    	{
    	setLogBookEntryId( key );
    	}

	
	/**
	 * Gets the unique id of the LogBookEntry.
	 * 
	 * @return A PrimaryKey.
	 */
	public PrimaryKey getLogBookEntryId()
		{
		return log_book_entry_id;
		}
		
	/**
	 * Called only when the object is loaded from the database
	 * or a new object is saved.
	 * 
	 * @param id The primary key from the database.
	 */
	public void setLogBookEntryId( PrimaryKey id )
		{
		log_book_entry_id = id;
		}


	/**
	 * Which log book page (which user) does this entry 
	 * belong to.
	 * 
	 * @return The id of the log book page.
	 */
	public PrimaryKey getLogBookPageId()
		{
		return log_book_page_id;
		}
	/**
	 * When creating a new entry or loading an entry from the 
	 * database, sets the id of the page this entry belongs to.
	 * 
	 * @param id The id of the logbook page.
	 */
		
	public void setLogBookPageId( PrimaryKey id )
		{
		log_book_page_id = id;
		setUnsaved();
		}
		

	/**
	 * Under which question was this entry entered?
	 * 
	 * @return The id of the question.
	 */
	public PrimaryKey getLogBookQuestionId()
		{
		return log_book_question_id;
		}
		
	/**
	 * When making a new entry or loading an entry from the 
	 * database indicated which question this entry was made
	 * under.
	 * 
	 * @param id The id of the question.
	 */
	public void setLogBookQuestionId( PrimaryKey id )
		{
		log_book_question_id = id;
		setUnsaved();
		}
		
		

	/**
	 * Gets the id of the user who made the entry.
	 * 
	 * @return Id number of the user.
	 */
	public PrimaryKey getUserId()
		{
		return user_id;
		}
		
	/**
	 * When making a new entry or loading an entry from the
	 * database, indicated who made the entry.
	 * 
	 * @param id The user id.
	 */
	public void setUserId( PrimaryKey id )
		{
		user_id = id;
		setUnsaved();
		}


	public User getUser()
		throws BuildingServerException
		{
		if ( user_id == null )
			return null;
		return User.findUser( user_id );
		}
		

	/**
	 * Gets the id of the entry in the big_strings table that
	 * contains the text of the entry.
	 * 
	 * @return PrimaryKey of the big_string entry.
	 */
	public PrimaryKey getEntryBigStringId()
		{
		return entry_big_string_id;
		}
		
	/**
	 * When creating or editing an entry sets the id of the
	 * record that contains the actual text.  Normally only called
	 * when making a new entry or loading an entry from the
	 * database because editing the text of an existing entry
	 * can be done by modifying the existing BigString object.
	 * 
	 * @param s The id of a big_string entry.
	 */
	public void setEntryBigStringId( PrimaryKey s )
		{
		entry_big_string_id = s;
		setUnsaved();
		}
		
	/**
	 * Convenience method that loads the BigString object that
	 * is referenced by the entry_big_string_id property.
	 * 
	 * @return Text of the entry.
	 * @exception org.bodington.server.BuildingServerException
	 */
	public String getEntry()
		throws BuildingServerException
		{
		if ( entry_big_string_id == null )
			return null;
		BigString bstr = BigString.findBigString( entry_big_string_id );
		if ( bstr == null )
			return null;
		return bstr.getString();
		}
		
	/**
	 * Convenience method that finds the big string entry
	 * referenced by entry_big_string and changes its text
	 * value.
	 * 
	 * @param s The new text for this entry.
	 * @exception org.bodington.server.BuildingServerException
	 */
	public void setEntry( String s )
		throws BuildingServerException
		{
		BigString bstr=null;
		if ( entry_big_string_id != null )
			bstr = BigString.findBigString( entry_big_string_id );
		if ( bstr == null )
			{
			bstr = new BigString();
			bstr.setString( s );
			bstr.save();
			entry_big_string_id = bstr.getBigStringId();
			setUnsaved();
			return;
			}

		bstr.setString( s );
		bstr.save();
		}
	
		
	/**
	 * 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 getFlags()
		{
		return 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 setFlags( int f )
		{
		if ( f==flags ) return;
		flags=f;
    	setUnsaved();
		}



	public boolean beenSeen()
		{
		return (flags & FLAG_SEEN) != 0;
		}
	public void setSeen( boolean b )
		{
		if ( b == beenSeen() )
			return;
		setFlags( flags ^ FLAG_SEEN );
		}
	public boolean isDraft()
		{
		return (flags & FLAG_DRAFT) != 0;
		}
	public void setDraft( boolean b )
		{
		if ( b == isDraft() )
			return;
		setFlags( flags ^ FLAG_DRAFT );
		}
	public boolean isSelected()
		{
		return (flags & FLAG_SELECTED) != 0;
		}
	public void setSelected( boolean b )
		{
		if ( b == isSelected() )
			return;
		setFlags( flags ^ FLAG_SELECTED );
		}
	public boolean isPrivate()
		{
		return (flags & FLAG_PRIVATE) != 0;
		}
	public void setPrivate( boolean b )
		{
		if ( b == isPrivate() )
			return;
		setFlags( flags ^ FLAG_PRIVATE );
		}


	/**
	 * Gets the date/time that this entry was last saved.
	 * 
	 * @return An SQL timestamp.
	 */
	public Timestamp getWhenModified()
		{
		return when_modified;
		}
		
	/**
	 * Used when creating or updating an entry to indicate when
	 * it was modified last.
	 * 
	 * @param t An SQL timestamp value.
	 */
	public void setWhenModified( Timestamp t )
		{
		when_modified = t;
		setUnsaved();
		}
		
		
	/**
	 * Get the non-site part of a linked URL, starting with a leading /.
	 * 
	 * @return a String.
	 */
	public String getLinkedUrl()
		{
		return linked_url;
		}
		
	/**
	 * Set the non-site part of a linked URL, starting with a leading /.
	 * 
	 * @param s A String.
	 */
	public void setLinkedUrl( String s )
		{
		linked_url = s;
		setUnsaved();
		}
		
		
	public boolean canEdit()
		{
		User user = (User)BuildingContext.getContext().getUser();
		if ( user == null )
			return false;
		if ( !user.getUserId().equals( this.getUserId() ) )
			return false;
		return this.isDraft() || this.isPrivate() || !this.beenSeen();
		}

   	
   	/**
   	 * This static method is used to find and load LogBookEntry from the database.  
   	 * Code that needs to find LogBookPages 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 LogBookEntry to find and load.
   	 * @return Reference to the loaded LogBookEntry or null if not found.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
   	public static LogBookEntry findLogBookEntry( PrimaryKey key )
		throws BuildingServerException
		{
		return (LogBookEntry)findPersistentObject( key, "org.bodington.logbook.server.LogBookEntry" );
		}
	
   	/**
   	 * This static method is used to find and load LogBookEntries from the database.  
   	 * Code that needs to find LogBookEntries could call PersistentObject.findPersistentObject
   	 * directly but this method is a neater solution and provides an opportunity for
   	 * specialist initialisation for objects found.
   	 * 
   	 * @param where An SQL WHERE clause used to load LogBookPages.
   	 * @return Reference to the loaded LogBookPage or null if not found.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
   	public static Enumeration findLogBookEntries( String where, String order )
		throws BuildingServerException
		{
		return findPersistentObjects( where, order, "org.bodington.logbook.server.LogBookEntry" );
		}
   	
   	/**
   	 * This static method is used to find how many LogBookEntries a LogBookQuestion
   	 * has in the database.
   	 * @param question The question to look for entries against.
   	 * @return The number of entries for this question.
   	 * @exception org.bodington.server.BuildingServerException
   	 */
   	public static int count(LogBookQuestion question)
   	    throws BuildingServerException
   	    {
   	    return countPersistentObjects("log_book_question_id = "+ question.getPrimaryKey(), "org.bodington.logbook.server.LogBookEntry");
   	    }
	}
