/*
 * "Peko" Visual Novel System
 *
 * All Rights Reserved.
 * Copyright (c) 1999-2003 Tsukuba Bunko.
 *
 * $Id: Session.java,v 1.1.2.1 2003/12/11 10:12:19 ppoi Exp $
 */
package tsukuba_bunko.peko.session;

import	java.io.Serializable;

import	java.util.Date;
import	java.util.HashMap;
import	java.util.HashSet;

import	tsukuba_bunko.peko.Logger;

import	tsukuba_bunko.peko.scenario.SceneContext;


/**
 * 現在のセッションの情報を格納します。
 * @author	$Author: ppoi $
 * @version	$Revision: 1.1.2.1 $
 */
public class Session	implements Serializable	{

	/**
	 * セッションフラグ
	 */
	protected HashSet	_sessionFlags = null;

	/**
	 * システムフラグ
	 */
	protected HashSet	_systemFlags = null;

	/**
	 * システムフラグのロードタイムスタンプ
	 */
	protected Date	_timestamp = null;


	/**
	 * 現在進行中のシーンのコンテクスト
	 */
	protected SceneContext	_sceneContext = null;

	/**
	 * その他の属性
	 */
	protected HashMap	_attributes = new HashMap( 17 );


	/**
	 * 現在シーンを処理しているスレッド
	 */
	protected transient Thread	_activeThread = null;


	/**
	 * <code>Session</code> のインスタンスを生成します。
	 */
	public Session()
	{
		super();
	}


	/**
	 * 現在進行中のシーンのコンテクストを設定します。
	 * @param	context	シーンコンテクスト
	 * @param	processThread	シーンを処理するスレッド
	 */
	public synchronized void setSceneContext( SceneContext context, Thread processThread )
	{
		_sceneContext = context;
		_activeThread = processThread;
	}

	/**
	 * 現在のスレッドで進行中のシーンのコンテクストを設定します。
	 * @param	context	シーンコンテクスト
	 */
	public void setSceneContext( SceneContext context )
	{
		setSceneContext( context, Thread.currentThread() );
	}

	/**
	 * セッションで現在進行中のシーンのコンテクストを取得します。
	 * @return	シーン名
	 */
	public SceneContext getSceneContext()
	{
		return _sceneContext;
	}


	/**
	 * セッションフラグを立てます。
	 * @param	flagID	立てるフラグのフラグ ID
	 */
	public void declareSessionFlag( String flagID )
	{
		Logger.debug( "[session] declare session flag: " + flagID );
		if( isActiveThread() )	{
			_sessionFlags.add( flagID );
		}
		else	{
			Logger.debug( "[session] canceled declaring session flag: " + flagID );
		}
	}

	/**
	 * セッションフラグを降ろします。
	 * @param	flagID	降ろすフラグのフラグ ID
	 */
	public void undeclareSessionFlag( String flagID )
	{
		Logger.debug( "[session] undeclare session flag: " + flagID );
		if( isActiveThread() )	{
			_sessionFlags.remove( flagID );
		}
		else	{
			Logger.debug( "[session] canceled undeclaring session flag: " + flagID );
		}
	}

	/**
	 * 指定されたフラグがセッションフラグとして立てられているかどうかを判定します。
	 * @param	flagID	判定するフラグ ID
	 * @return	フラグが立っている場合 <code>true</code>、それ以外 <code>false</code>
	 */
	public boolean isDeclaredSessionFlag( String flagID )
	{
		return _sessionFlags.contains( flagID );
	}

	/**
	 * システムフラグを立てます。
	 * @param	flagID	立てるフラグのフラグ ID
	 */
	public void declareSystemFlag( String flagID )
	{
		Logger.debug( "[session] declare system flag: " + flagID );
		if( isActiveThread() )	{
			_systemFlags.add( flagID );
		}
		else	{
			Logger.debug( "[session] canceled declaring system flag: " + flagID );
		}
	}

	/**
	 * システムフラグを降ろします。
	 * @param	flagID	降ろすフラグのフラグ ID
	 */
	public void undeclareSystemFlag( String flagID )
	{
		Logger.debug( "[session] undeclare system flag: " + flagID );
		if( isActiveThread() )	{
			_systemFlags.remove( flagID );
		}
		else	{
			Logger.debug( "[session] canceled undeclaring system flag: " + flagID );
		}
	}

	/**
	 * 指定されたフラグがシステムフラグとして立てられているかどうかを判定します。
	 * @param	flagID	判定するフラグ ID
	 * @return	フラグが立っている場合 <code>true</code>、それ以外 <code>false</code>
	 */
	public boolean isDeclaredSystemFlag( String flagID )
	{
		return _systemFlags.contains( flagID );
	}


	/**
	 * セッションフラグ集合を設定します。
	 * @param	flagSet	フラグ集合
	 */
	public void setSessionFlagSet( HashSet flagSet )
	{
		_sessionFlags = flagSet;
	}

	/**
	 * セッションフラグ集合を取得します。
	 * @return	フラグ集合
	 */
	public HashSet getSessionFlagSet()
	{
		return _sessionFlags;
	}

	/**
	 * システムフラグ集合を設定した時刻を取得します。
	 * @return	システムフラグ集合を設定した時刻
	 */
	public Date getTimestamp()
	{
		return _timestamp;
	}

	/**
	 * システムフラグ集合を設定します。<code>timestamp</code> が、現在のコンテクストに設定されている時刻より古い場合は設定は反映されません。
	 * @param	flagSet	フラグ集合
	 * @param	timestamp	フラグ集合のタイムスタンプ
	 */
	public void setSystemFlagSet( HashSet flagSet, Date timestamp )
	{
		if( (_timestamp == null) || _timestamp.before(timestamp) )	{
			_systemFlags = flagSet;
			_timestamp = timestamp;
		}
	}

	/**
	 * システムフラグ集合を取得します。
	 * @return	フラグ集合
	 */
	public HashSet getSystemFlagSet()
	{
		return _systemFlags;
	}


	/**
	 * セッションに属性を設定します。
	 * @param	name	属性名
	 * @param	value	属性値
	 */
	public void setSessionAttribute( String name, Serializable value )
	{
		_attributes.put( name, value );
	}

	/**
	 * セッションの属性を取得します。
	 * @param	name	属性名
	 * @return	属性値
	 */
	public Object getSessionAttribute( String name )
	{
		return _attributes.get( name );
	}


	/**
	 * 現在のスレッドがシーン処理中のスレッドかどうかを判定します。
	 * @return	現在のスレッドがシーン処理中のスレッドの場合 <code>true</code>、それ以外の場合 <code>false</code>
	 */
	protected boolean isActiveThread()
	{
		return (_activeThread == Thread.currentThread());
	}
}
