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

import paraselene.*;

/**
 * 遷移先指定。
 * 直前のページ(直前に output したページ(履歴より取得します))に画面遷移します。<br>
 * 履歴にページが無い場合、{@link Feedback}と同じ動作をします。<br>
 * 元々{@link Popup}でポップアップ表示されたページであれば、
 * ポップアップを閉じます。
 */
public class Closure extends Forward implements AjaxForward {
	private static final long serialVersionUID = 2L;

	Page close_page = null;

	static final PageID	CLOSE = new PageID(){
		public boolean isSame( Page p ){ return false; }
		public int getID(){ return -1; }
		public PageID getPageID( int id ){ return null; }
		public PageFactory getPageFactory(){ return null; }
		public String toString() { return "Closure.CLOSE page"; }
	};

	private static PageID getLastPage( Page myself, History history ) {
		if ( myself == null || history == null )	return CLOSE;
		if ( myself.getPopupType() != null )	return myself.getID();
		Page	last = history.getPage();
		if ( myself == last ) {
			for ( int i = 1; last != null; i++ ) {
				last = history.getPage( i );
				if ( last != myself )	break;
			}
		}
		if ( last == null )	return CLOSE;
		return last.getID();
	}

	/**
	 * 同じ動作であるか？
	 * 同一ページを閉じるClosureを同じ動作と見なします。
	 * @param o 比較対象。
	 * @return true:同一動作、false:異なる動作。
	 */
	public boolean equals( Object o ) {
		if ( !(o instanceof Closure) )	return false;
		Closure	c = (Closure)o;
		return close_page == c.close_page;
	}

	/**
	 * コンストラクタ。
	 * 履歴上で、直前にスタックされているページで output を処理します。<br>
	 * Daemon からこのコンストラクタを指定するとクラッシュします。<br>
	 * セッションは維持されます。
	 */
	public Closure() {
		super( getLastPage( SandBox.getCurrentPage().getParentPage(), SandBox.getCurrentRequestParameter().getHistory() ) );
		close_page = SandBox.getCurrentPage().getParentPage();
	}

	/**
	 * コンストラクタ。
	 * @param page ポップアップ。
	 * これがポップアップでなければ動作は不定です。
	 */
	public Closure( Page page ) {
		super( page.getParentPage().getID() );
		close_page = page.getParentPage();
	}

	boolean is_refresh() {
		return close_page.getPopupType() == null;
	}

	static boolean isClosure( Page from, Page next, RequestParameter req ) {
		if ( from == null || next == null )	return false;
		if ( from.getPopupType() != null )	return true;
		return next.getID() == getLastPage( from, req.getHistory( from.getHistoryKey() ) );
	}

	public String toString() {
		StringBuilder	buf = new StringBuilder( "Closure:" );
		buf = buf.append( close_page.getID().toString() );
		buf = buf.append( "/" ).append( close_page.getUniqueKey() );
		return buf.toString();
	}

	OutputCall makeOutput( int nk, Page lp, RequestParameter r, SessionData sd ) {
		if ( close_page.getPopupType() == null ) {
			Option.trace( "new LocationOutput <- %s", this );
			return new LocationOutput( nk, lp, this, r, sd );
		}
		Option.trace( "new CloseOutput <- %s", this );
		return new CloseOutput( nk, lp, this, r, sd );
	}

	CometCall makeCometCall( History h ) {
		if ( close_page.getPopupType() == null ) {
			Option.trace( "new LocationCometCall <- %s", this );
			return new LocationCometCall( h, this );
		}
		Option.trace( "new CloseCometCall <- %s", this );
		return new CloseCometCall( h, this );
	}
}

