/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             Stuart E. Middleton
//      Created date:           2004/04/30
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.state;

import java.lang.*;
import java.util.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class State extends Object implements Serializable {

	// member variables
	private Vector mvectorFlags;
	private Hashtable mhashObjects;

	// logger variable
	private Logger mlogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.state.State");

	/**
	 * constructor
	 */
	public State()
	{
		super();

		// init vectors
		mvectorFlags = new Vector();
		mhashObjects = new Hashtable();

		// all done
	}

	/**
	 * destructor
	 */
	public void finalize() throws Throwable
	{
		// clear the contents of the hash tables and vectors
		mvectorFlags.removeAllElements();
		mhashObjects.clear();

		// all done
		return;
	}

	/**
	 * add a flag to this state object
	 * @param strFlagName The name of the flag to be asserted
	 */
	synchronized public void addFlag( String strFlagName )
	{
		try
		{
			// check params
			if( strFlagName == null ) return;

			// add string to vector of flags
			mvectorFlags.addElement( strFlagName );

			// all done
			return;
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during addFlag",ex);
			return;
		}
	}

	/**
	 * check to see if a flag has been asserted
	 * @param strFlagName The name of the flag to check
	 * @return true if flag is asserted
	 */
	synchronized public boolean checkFlag( String strFlagName )
	{
		try
		{
			// check params
			if( strFlagName == null ) return false;

			// return if flag exists
			return mvectorFlags.contains( strFlagName );
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during checkFlag",ex);
			return false;
		}
	}

	/**
	 * Get all flags. Returns null on error.
	 * @return vector conaining flag strings
	 */
	synchronized public Vector getFlags()
	{
		int i;
		Vector vectorResult;

		try
		{
			// make vector
			vectorResult = new Vector();

			// add flag strings to vector
			for( i=0;i<mvectorFlags.size();i++ )
				vectorResult.addElement( (String) mvectorFlags.elementAt(i) );

			// all done
			return vectorResult;
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during getFlags",ex);
			return null;
		}
	}

	/**
	 * Add an object to this state's object list.
	 * @param strObjectName The name of the object's label
	 * @param object The object itself
	 */
	synchronized public void addObject( String strObjectName, Object object )
	{
		try
		{
			// check params
                  if( strObjectName == null || object == null ) return;

			// add string to vector of flags
			mhashObjects.put( strObjectName, object );

			// all done
			return;
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during addObject",ex);
			return;
		}
	}

	/**
	 * get an object from this states object store, or null if not found
	 * @param strObjectName The label of the object wanted
	 * @return object attached to the tag provided
	 */
	synchronized public Object getObject( String strObjectName )
	{
		try
		{
			// check params
			if( strObjectName == null ) return null;

			// return if flag exists
			return mhashObjects.get( strObjectName );
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during getObject",ex);
			return null;
		}
	}

	/**
	 * write state and contents to a stream
	 * @param out Output stream where writes should go
	 */
	synchronized private void writeObject(java.io.ObjectOutputStream out) throws IOException
	{
		int i;
		Enumeration enumKeys;
		String strKey;

		try
		{
			// write the number of flags
			out.writeInt( mvectorFlags.size() );

			// write the flags
			for( i=0;i<mvectorFlags.size();i++ )
				out.writeObject( mvectorFlags.elementAt(i) );

			// write the number of objects
			out.writeInt( mhashObjects.size() );

			// write the object labels, then objects in order
			enumKeys = mhashObjects.keys();
			while( enumKeys.hasMoreElements() ) {
				strKey = (String) enumKeys.nextElement();
				out.writeObject( strKey );
				out.writeObject( mhashObjects.get( strKey ) );
			}

			// all done
			return;
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during writeObject",ex);
			throw new IOException("Failed to serialize state object");
		}
	}

	/**
	 * read state and contents from a stream
	 * @param in Input stream where to read from
	 */
	synchronized private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
	{
		int i, nFlags, nObjects;
		String strKey;

		// init (no constructor)
		mlogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.state.State");

		try
		{

			// make the vector and hash table since constructor will not be called
			if( mvectorFlags == null )
				mvectorFlags = new Vector();
			mvectorFlags.removeAllElements();

			if( mhashObjects == null )
				mhashObjects = new Hashtable();
			mhashObjects.clear();

			// read the number of flags
			nFlags = in.readInt();

			// read all the flags
			for( i=0;i<nFlags;i++ )
				mvectorFlags.addElement( (String) in.readObject() );

			// read the number of object/label pairs
			nObjects = in.readInt();

			// read all object/label pairs [key,object]
			for( i=0;i<nObjects;i++ ) {
				strKey = (String) in.readObject();
				mhashObjects.put( strKey,in.readObject() );
			}

			// all done
			return;
		}
		catch ( Exception ex )
		{
			mlogger.log( Level.SEVERE,"Exception during readObject",ex);
			throw new IOException("Failed to de-serialize state object");
		}
	}

} // end of State
