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

import	java.util.ArrayList;

import	tsukuba_bunko.peko.ActionControler;
import	tsukuba_bunko.peko.Logger;
import	tsukuba_bunko.peko.PekoSystem;

import	tsukuba_bunko.peko.session.Session;

import	tsukuba_bunko.peko.scenario.select.SelectCoordinator;

import	tsukuba_bunko.peko.scenario.stage.StageCoordinator;

import	tsukuba_bunko.peko.scenario.text.TextCoordinator;


/**
 * シナリオの処理を行うプロセッサモジュールです。
 * @author	$Author: ppoi $
 * @version	$Revision: 1.1.2.1 $
 */
public class ScenarioProcessor	{

	/**
	 * キュー
	 */
	protected ArrayList	_queue = new ArrayList( 5 );

	/**
	 * キューの最大値
	 */
	protected int	_maxQueueSize = 4;

	/**
	 * 生成した SceneProcessor 数
	 */
	protected int	_processorCount = 0;

	/**
	 * 現在シーンを処理中の SceneProcessor
	 */
	protected SceneProcessor	_currentSceneProcessor = null;

	/**
	 * 現在のコンテクスト
	 */
	protected Session	_session = null;


	/**
	 * TextCanvas コーディネータ
	 */
	protected TextCoordinator	_textCooridnator = null;

	/**
	 * StageCanvas コーディネータ
	 */
	protected StageCoordinator	_stageCoordinator = null;

	/**
	 * SelectCanvas コーディネータ
	 */
	protected SelectCoordinator	_selectCoordinator = null;


	/**
	 * <code>ScenarioProcessor</code> のインスタンスを生成します。
	 */
	public ScenarioProcessor()
	{
		super();
		_queue.add( new SceneProcessor(this) );
		_queue.add( new SceneProcessor(this) );

		_textCooridnator = new TextCoordinator();
		_stageCoordinator = new StageCoordinator();
		_selectCoordinator = new SelectCoordinator();
	}


	/**
	 * 指定された第１シーン、セッションでシナリオの再生を開始します。
	 * @param	sceneName	第１シーン名
	 * @param	session	セッション
	 */
	public synchronized void playScenario( String sceneName, Session session )
	{
		if( _currentSceneProcessor != null )	{
			Logger.error( "[scene] BUG! current scene processor is still alive!" );
			exit();
		}
		SceneProcessor	processor = getSceneProcessor();
		processor.setTextCoordinator( _textCooridnator );
		processor.setStageCoordinator( _stageCoordinator );
		processor.setSelectCoordinator( _selectCoordinator );
		_currentSceneProcessor = processor;
		_session = session;

		ActionControler	controler = PekoSystem.getInstance().getActionControler();
		controler.setActive( true );
		processor.process( sceneName, session );
	}

	/**
	 * シナリオの再生を終了します。
	 */
	public synchronized void exit()
	{
		if( _currentSceneProcessor != null )	{
			Logger.debug( "[scenario] exit ScenarioProcessor" );
			_currentSceneProcessor.abort();
			_currentSceneProcessor = null;
			_session = null;

			ActionControler	controler = PekoSystem.getInstance().getActionControler();
			controler.start();
		}
	}

	/**
	 * シーンを処理するシーンプロセッサを取得します。
	 * @return	シーンプロセッサ
	 */
	protected synchronized SceneProcessor getSceneProcessor()
	{
		try	{
			if( _queue.isEmpty() )	{
				if( _processorCount < _maxQueueSize )	{
					SceneProcessor	processor = new SceneProcessor( this );
					_processorCount++;
					return processor;
				}
				else	{
					while( _queue.isEmpty() )	{
						wait( 50 );
					}
				}
			}
			return (SceneProcessor)_queue.remove( 0 );
		}
		catch( InterruptedException ie )	{
			Logger.debug( "[scene] interrupted", ie );
			return null;
		}
	}

	/**
	 * 処理が終了した SceneProcessor をキューに戻します。
	 * @param	processor	キューに戻すシーンプロセッサ
	 */
	protected synchronized void pushSceneProcessor( SceneProcessor processor )
	{
		_queue.add( processor );
	}

	/**
	 * シーンの終了を通知します。
	 * @param	processor	終了の通知を発行したシーンプロセッサ
	 */
	protected synchronized void sceneEnded( SceneProcessor processor )
	{
		if( _currentSceneProcessor == processor )	{
			SceneContext	context = processor.getSceneContext();
			String	nextSceneName = context.getNextSceneName();
			if( nextSceneName != null )	{
				if( "peko:end".equals(nextSceneName) )	{
					exit();
					ActionControler	controler = PekoSystem.getInstance().getActionControler();
					controler.returnTitle( true );
				}
				else	{
					_currentSceneProcessor.abort();
					_session.setSceneContext( null );
					PekoSystem.getInstance().getCanvasManager().advancesNewPage();
					PekoSystem.getInstance().getCanvasManager().getCurrentPage().commit();
					_currentSceneProcessor = getSceneProcessor();
					_currentSceneProcessor.setTextCoordinator( _textCooridnator );
					_currentSceneProcessor.setStageCoordinator( _stageCoordinator );
					_currentSceneProcessor.setSelectCoordinator( _selectCoordinator );
					_currentSceneProcessor.process( context.getNextSceneName(), _session );
				}
			}
			else	{
				Logger.error( MessageIDs.SCN0012E );
				exit();
				ActionControler	controler = PekoSystem.getInstance().getActionControler();
				controler.returnTitle( true );
			}
		}
	}
}
