/*
 * "Peko" Visual Novel System
 *
 * All Rights Reserved.
 * Copyright (c) 1999-2003 Tsukuba Bunko.
 *
 * $Id: ResourceManager.java,v 1.3.2.1 2003/12/11 11:11:53 ppoi Exp $
 */
package tsukuba_bunko.peko.resource;

import	java.net.URL;

import	tsukuba_bunko.resource.DeserializerMapping;
import	tsukuba_bunko.resource.Resources;

import	tsukuba_bunko.peko.InitializationError;
import	tsukuba_bunko.peko.Logger;


/**
 * "Peko" が使用するリソースを管理する機能を提供します。
 * @author	$Author: ppoi $
 * @version	$Revision: 1.3.2.1 $
 */
public class ResourceManager	{

	/**
	 * ログメッセージを格納したファイル
	 */
	protected static final String	RES_MESSAGE = "messages.xml";

	/**
	 * システム構成リソースを格納したファイル
	 */
	protected static final String	RES_SYSTEM = "system.xml";

	/**
	 * メニュー項目リソースを格納したファイル
	 */
	protected static final String	RES_MENU = "menu.xml";

	/**
	 * ダイアログ構成リソースを格納したファイル
	 */
	protected static final String	RES_DIALOG = "dialog.xml";

	/**
	 * キャンバス構成リソースを格納したファイル
	 */
	protected static final String	RES_CANVAS = "canvas.xml";

	/**
	 * ゲーム構成リソースを格納したファイル
	 */
	protected static final String	RES_GAME ="game-info.xml";

	/**
	 * タイトル画面構成リソースを格納したファイル
	 */
	protected static final String	RES_TITLE = "title.xml";


	/**
	 * 唯一のインスタンス
	 */
	private static ResourceManager	_instance = null;


	/**
	 * リソースローダ
	 */
	private PekoResourceLoader	_loader = null;


	/**
	 * リソース
	 */
	private Resources	_resources = null;

	/**
	 * ロケーションリソース
	 */
	private LocationResources	_locationResources = null;


	/**
	 * <code>ResourceManager</code> のインスタンスを作成します。
	 */
	protected ResourceManager()
	{
		super();
	}


	/**
	 * リソースが存在するかどうかを判定します。
	 * @param	resourceID	リソース ID
	 * @return	存在する場合 <code>true</code>、存在しない場合 <code>false</code>
	 */
	public boolean exists( String resourceID )
	{
		return (_resources.getResource(resourceID) != null);
	}

	/**
	 * リソースを取得します。
	 * @param	resourceID	リソース ID
	 * @return	リソース。対応するリソースが存在しない場合 <code>null</code>。
	 */
	public Object getResource( String resourceID )
	{
		return getResource( resourceID, false );
	}

	/**
	 * リソースを取得します。
	 * @param	resourceID	リソース ID
	 * @param	nowarn	<code>true</code> の場合、ワーニングログを出力しない
	 * @return	リソース。対応するリソースが存在しない場合 <code>null</code>。
	 */
	public Object getResource( String resourceID, boolean nowarn )
	{
		Object	resource = _resources.getResource( resourceID );
		if( !nowarn )	{
			if( resource == null )	{
				Logger.warn( MessageIDs.RES0001W.getMessage( new Object[]{resourceID} ) );
			}
		}
		return resource;
	}

	/**
	 * ロケーションリソースを取得します。
	 * @return	ロケーションリソース
	 */
	public LocationResources getLocationResources()
	{
		return _locationResources;
	}


	/**
	 * リソースローダを取得します。
	 * @return	リソースローダ
	 */
	private PekoResourceLoader getResourceLoader()
	{
		try	{
			if( _loader == null )	{
				_loader = new PekoResourceLoader();
			}
			return _loader;
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to create instance of PekoResourceLoader", e );
			Logger.fatal( MessageIDs.RES0014F, e );
			throw ie;
		}
	}

	/**
	 * ログメッセージを読み込みます。
	 */
	private void loadLogMessages()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_MESSAGE );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of log messgages." );
				Logger.fatal( "[RES9998F] missing resource file of log messgages.", ie );
				throw ie;
			}
			Logger.debug( "loading log messages from " + resourceURL.toString() );

			_resources = Resources.newInstance( resourceURL );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of log messages.", e );
			Logger.fatal( "[RES9999F] fail to load resources of log messages.", ie );
			throw ie;
		}
	}

	/**
	 * システム構成リソースを読み込みます。
	 */
	private void loadSystemConfigurationResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_SYSTEM );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of PVNS resource." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_SYSTEM}, ie );
				throw ie;
			}
			Logger.debug( "loadingresources of system configuration from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();
			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of system configuration", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_SYSTEM}, ie );
			throw ie;
		}

		LocationConfigurator	configurator = new LocationConfigurator();
		_locationResources = configurator.configure( _resources );
	}

	/**
	 * メニュー項目構成リソースを読み込みます。
	 */
	private void loadMenuResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_MENU );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of menu items." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_MENU}, ie );
				throw ie;
			}
			Logger.debug( "loading resources of menu items from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();
			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of menu item configuration", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_SYSTEM}, ie );
			throw ie;
		}
	}

	/**
	 * ダイアログ構成リソースを読み込みます。
	 */
	private void loadDialogConfigurationResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_DIALOG );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of dialog configuration." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_DIALOG}, ie );
				throw ie;
			}
			Logger.debug( "loading resources of dialog configuration from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();
			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of dialog configuration", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_DIALOG}, ie );
			throw ie;
		}
	}

	/**
	 * キャンバス構成リソースを読み込みます。
	 */
	private void loadCanvasConfigurationResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_CANVAS );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of canvas configuration." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_CANVAS}, ie );
				throw ie;
			}
			Logger.debug( "loading resources of canvas configuration from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();
			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of canvas configuration", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_CANVAS}, ie );
			throw ie;
		}
	}

	/**
	 * タイトル画面構成リソースを読み込みます。
	 */
	private void loadTitleConfigurationResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_TITLE );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of title configuration." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_TITLE}, ie );
				throw ie;
			}
			Logger.debug( "loading resources of title configuration from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();
			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of title configuration", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_TITLE}, ie );
			throw ie;
		}
	}



	/**
	 * ゲーム情報リソースを読み込みます。
	 */
	private void loadGameInfoResources()
	{
		try	{
			URL	resourceURL = getClass().getClassLoader().getResource( ResourceManager.RES_GAME );
			if( resourceURL == null )	{
				InitializationError	ie = new InitializationError( "missing resource file of game information resource." );
				Logger.fatal( MessageIDs.RES0002F, new Object[]{ResourceManager.RES_GAME}, ie );
				throw ie;
			}
			Logger.debug( "loading game information resources from " + resourceURL.toString() );

			PekoResourceLoader	loader = getResourceLoader();

			DeserializerMapping	mapping = loader.getDeserializerMapping();
			IconDeserializer	deserializer = (IconDeserializer)mapping.getResourceDeserializer( "peko:icon" );
			deserializer.setBaseURL( _locationResources.getMiscDirecotryURL() );

			loader.loadResource( resourceURL, _resources );
		}
		catch( Exception e )	{
			InitializationError	ie = new InitializationError( "fail to load resources of game information resource", e );
			Logger.fatal( MessageIDs.RES0003F, new Object[]{ResourceManager.RES_GAME}, ie );
			throw ie;
		}
	}

	/**
	 * <code>ResourceManager</code> のインスタンスを初期化します。
	 * @throws	InitializationError	初期化に失敗した場合
	 */
	private void initialize()
	{
		Logger.debug( "[resource] start initializing ResourceManager." );

		loadLogMessages();

		loadSystemConfigurationResources();
		loadMenuResources();
		loadDialogConfigurationResources();
		loadCanvasConfigurationResources();
		loadTitleConfigurationResources();

		loadGameInfoResources();

		Logger.debug( "[resource] finish initializing ResourceManager." );
	}


	/**
	 * <code>ResourceManager</code> の唯一のインスタンスを取得します。
	 * @return	唯一の <code>ResourceManager</code> のインスタンス
	 */
	public static ResourceManager getInstance()
	{
		if( _instance == null )	{
			synchronized( ResourceManager.class )	{
				if( _instance == null )	{
					_instance = new ResourceManager();
					_instance.initialize();
				}
			}
		}
		return _instance;
	}
}