/*
 * Paraselene
 * Copyright (c) 2009  Akira Terasaki
 * このファイルは同梱されているLicense.txtに定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene.test;

import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * テスト用セッション。
 */
@SuppressWarnings("deprecation")
public class TestSession implements HttpSession {
	private HashMap<String,Object>	session = new HashMap<String,Object>();
	private boolean ok_f = true;
	private Date	now = new Date();

	/**
	 * コンストラクタ。
	 */
	public TestSession() {
	}

	/**
	 * このセッションが作成された時刻を、
	 * GMT 1970年 1 月 1 日 0 時からのミリ秒単位で返します。
	 * @return GMT 1970年 1 月 1 日 からのミリ秒単位で表した、
	 * このセッションが作成された時刻を示す long
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public long getCreationTime() throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		return now.getTime();
	}

	/**
	 * このセッションに割り当てられた一意の識別子が格納された文字列を返します。
	 * この識別子はサーブレットコンテナによって割り当てられ、実装に依存します。
	 * @return このセッションに割り当てられた識別子を指定する文字列
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public String getId() throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		return Integer.toString( hashCode() );
	}

	/**
	 * このセッションに関連付けられた要求をクライアントが最後に送信した時刻を 
	 * GMT 1970 年 1 月 1 日 0 時からのミリ秒数として返します。
	 * 返される時刻は実際にはコンテナが要求を受信した時刻を指します。<br>
	 * セッションに関連付けられた値の取得や設定といった操作を
	 * アプリケーションが実行しても、このアクセス時刻は更新されません。
	 * @return このセッションに関連付けられた要求をクライアントが
	 * 最後に送信した時刻を GMT 1970 年 1 月 1 日からのミリ秒数で表現した long
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public long getLastAccessedTime() throws IllegalStateException {
		return getCreationTime();
	}

	/**
	 * 常にnullを返します。
	 * @return null。
	 */
	public ServletContext getServletContext() {
		return null;
	}

	private int int_v = 360;

	/**
	 * 何もしません。
	 * @param interval getMaxInactiveInterval()で取得できます。
	 */
	public void setMaxInactiveInterval(int interval) {
		int_v = interval;
	}

	/**
	 * setMaxInactiveInterval()した値を返します。
	 * @return setMaxInactiveInterval()の設定値。
	 */
	public int getMaxInactiveInterval() {
		return int_v;
	}

	/**
	 * 指定された名前でこのセッションにバインドされたオブジェクトを返します。
	 * その名前でバインドされたオブジェクトがない場合は、null を返します。
	 * @param name オブジェクトの名前を指定する文字列
	 * @return 指定された名前のオブジェクト
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public Object getAttribute(String name) throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		return session.get( name );
	}

	class Names implements Enumeration<String> {
		ArrayList<String>	data = new ArrayList<String>();
		int	pnt = 0;
		Names( Set<String> n ) {
			data.addAll( n );
		}
		public boolean hasMoreElements() {
			return data.size() < pnt;
		}
		public String nextElement() throws NoSuchElementException {
			if ( !hasMoreElements() )	throw new NoSuchElementException();
			pnt++;
			return data.get( pnt - 1 );
		}
	}
	/**
	 * このセッションにバインドされたすべてのオブジェクトの名前が格納された、
	 * String オブジェクトの Enumeration を返します。
	 * @return このセッションにバインドされたすべてのオブジェクトの名前が格納された、
	 * String オブジェクトの Enumeration
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public Enumeration<?> getAttributeNames() throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		return new Names( session.keySet() );
	}

	/**
	 * 指定された名前を使用して、オブジェクトをこのセッションにバインドします。
	 * 同じ名前のオブジェクトがすでにセッションにバインドされている場合は、
	 * オブジェクトが置き換えられます。<br>
	 * セッションにバインドされるオブジェクトが HttpSessionBindingListener 
	 * を実装している場合は、このメソッドが実行された後にコンテナが 
	 * HttpSessionBindingListener.valueBound を呼び出します。<br>
	 * このセッションにおいて、すでに同じ名前をもち、かつ 
	 * HttpSessionBindingListener を実装しているオブジェクトがバインドされている
	 * 場合は、そのオブジェクトに対して HttpSessionBindingListener.valueUnbound 
	 * メソッドが呼び出されます。
	 * @param name オブジェクトがバインドされる名前。null であってはならない
	 * @param value バインドされるオブジェクト
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public void setAttribute( String name, Object value )
	throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		Object	old = session.get( name );
		if ( old == null )	old = value;
		else	removeAttribute( name );
		session.put( name, value );
		if ( value instanceof HttpSessionBindingListener ) {
			HttpSessionBindingListener	obj = (HttpSessionBindingListener)value;
			obj.valueBound( new HttpSessionBindingEvent( this, name, old ) );
		}
	}

	/**
	 * 指定された名前でバインドされたオブジェクトをこのセッションから削除します。
	 * セッションに指定された名前でバインドされたオブジェクトがない場合、
	 * このメソッドは何も実行しません。<br>
	 * オブジェクトが HttpSessionBindingListener を実装している場合は、
	 * このメソッドが実行された後にコンテナが 
	 * HttpSessionBindingListener.valueUnbound を呼び出します。
	 * @param name このセッションから削除されるオブジェクトの名前
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public void removeAttribute( String name ) throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		Object	value = session.remove( name );
		if ( value == null )	return;
		if ( value instanceof HttpSessionBindingListener ) {
			HttpSessionBindingListener	obj = (HttpSessionBindingListener)value;
			obj.valueUnbound( new HttpSessionBindingEvent( this, name, obj ) );
		}
	}

	/**
	 * このセッションを無効化し、バインドされていたすべてのオブジェクトを
	 * アンバインドします。
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public void invalidate() throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		Names	names = new Names( session.keySet() );
		String[]	s = names.data.toArray( new String[0] );
		for ( int i = 0; i < s.length; i++ ) {
			removeAttribute( s[i] );
		}
		ok_f = false;
	}

	/**
	 * 常にfalseを返します。
	 * @return 常にfalse
	 * @exception IllegalStateException 
	 * 無効化されたセッションでこのメソッドが呼び出された場合
	 */
	public boolean isNew() throws IllegalStateException {
		if ( !ok_f ) throw new IllegalStateException();
		return false;
	}

	@Deprecated public @SuppressWarnings("deprecation") HttpSessionContext getSessionContext() { return null; }
	@Deprecated public void removeValue(java.lang.String name) {}
	@Deprecated public void putValue(java.lang.String name,java.lang.Object value) {}
	@Deprecated public java.lang.String[] getValueNames() { return null; }
	@Deprecated public java.lang.Object getValue(java.lang.String name) { return null; }

}

