<?php
/**
*  フレームワークのメインクラス
*
* PHP version 5
*
* @package    core
* @author     stk2k <stk2k@sazysoft.com>
* @copyright  2008 stk2k, sazysoft
*/

class Framework
{
	/*
	 *	フレームワークを起動
	 */
	public static function run()
	{
		try{
			//=======================================
			// タイムゾーンの設定
			//
			$default_tz = Profile::getString( 'DEFAULT_TIMEZONE' );
			date_default_timezone_set( $default_tz );
//			ini_set( 'date.timezone', CHARCOAL_TIMEZONE );

			//=======================================
			// ログの初期化
			//

			// プロファイルに設定されているロガーを取得
			$logger_names = Profile::getArray( 'LOG_LOGGERS' );

			// ロガーの登録
			foreach( $logger_names as $key ){
				$logger = Factory::createLogger( $key );
				Logger::append( $key, $logger );
			}

			// ロガー出力を開始
			Logger::init();

			// 起動メッセージ
			log_info( 'system,config', '===========================================================', __FILE__, __LINE__ );
			log_info( 'system,config', ' CHARCOAL framework version 1.0 (c)sazysoft,stk2k          ', __FILE__, __LINE__ );
			log_info( 'system,config', '===========================================================', __FILE__, __LINE__ );

			log_info( 'system', 'charcoalフレームワークを開始します。', __FILE__, __LINE__ );


			//=======================================
			// クラスローダの登録
			//
			$class_loaders = Profile::getArray('CLASS_LOADERS');
			if ( $class_loaders && is_array($class_loaders) ) {
				foreach( $class_loaders as $loader_name ) 	{
					$loader = Factory::createClassLoader( $loader_name );
					ClassLoader::addClassLoader( $loader );
				}
			}

			//=======================================
			// セッションハンドラの作成
			//

			if ( Profile::getBoolean('USE_SESSION') ) {
				log_info( 'system', 'セッションハンドラの作成を開始します。', __FILE__, __LINE__ );

				// セッションハンドラ名の取得
				$session_handler_name = Profile::getString( 'SESSION_HANDLER_NAME' );

				// セッションハンドラの作成
				$session_handler = Factory::createSessionHandler( $session_handler_name );

				log_info( 'system', 'セッションハンドラの作成を終了しました。', __FILE__, __LINE__ );
			}

			//=======================================
			// Requestパラメータの取得
			//

			log_info( 'system', 'Requestパラメータの解析を開始します。', __FILE__, __LINE__ );

			// Requestオブジェクトを作成
			$request = Factory::createRequest( CHARCOAL_RUNMODE );

			$proc_key = $request->get( PROC_KEYWORD );

			log_info( 'system', "プロシージャキーは[$proc_key]です。", __FILE__, __LINE__ );

			//=======================================
			// URLマッピング（HTTPのみ）
			//

			if ( CHARCOAL_RUNMODE === 'http'  && Profile::getBoolean('USE_URL_MAPPING') ) {
				log_info( 'system', 'URLマッピングを開始します。', __FILE__, __LINE__ );

				// URLマッパー名
				$url_mapper_name = Profile::getString('URL_MAPPER' );

				// URLマッパーを作成
				$url_mapper = Factory::createURLMapper( $url_mapper_name );

				// マッピング実行
				$url_mapper->mapURL( $request );

				$proc_key = $request->get( PROC_KEYWORD );

				log_info( 'system', "プロシージャキーは[$proc_key]です。", __FILE__, __LINE__ );
			}

			//=======================================
			// ProcedureKeyが未指定の場合
			//

			// プロファイルから取得
			if ( !$proc_key ){
				$proc_key = Profile::getString('DEFAULT_PROCKEY');
				if ( !$proc_key || $proc_key->isEmpty() ){
					log_error( 'system', 'プロファイルにデフォルトプロシージャキー[DEFAULT_PROCKEY]が定義されていません。', __FILE__, __LINE__ );
					throw new HttpException('500');
				}
			}

			//=======================================
			// Procedureの作成
			//

			// プロシージャを作成
			list( $procedure, $proc_name ) = Factory::createProcedure( $proc_key );

			//=======================================
			// コンテナの作成と起動
			//

			// DIコンテナを作成
			DIContainer::createContainer( $procedure );

			//=======================================
			// Responseの作成
			//

			// Requestオブジェクトを作成
			$response = new Response();

			//=======================================
			// ProcedureContextの作成
			//

			if ( Profile::getBoolean('USE_SESSION') ){
				// セッションを作成
				$session = new Session();

				// ProcedureContextオブジェクトを作成
				$context = new ProcedureContext( $proc_name, $procedure, $session );

				// セッションの開始
				$session->start();
				$session->restore();
			}
			else{
				// ProcedureContextオブジェクトを作成
				$context = new ProcedureContext( $proc_name, $procedure );
			}

			//=======================================
			// Procedureの実行
			//

			log_info( 'system', 'プロシージャ[$proc_name]を実行します。', __FILE__, __LINE__ );

			// プロシージャの実行
			$procedure->execute( $request, $context, $response );

			log_info( 'system', 'プロシージャ[$proc_name]を実行しました。', __FILE__, __LINE__ );

			//=======================================
			// 終了処理
			//

			// セッション情報の保存
			if ( Profile::getBoolean('USE_SESSION') ) {
				$session->save();
				$session->close();
			}

			//=======================================
			// コンテナの破棄
			//

			DIContainer::destroy();

			// 終了メッセージ
			log_info( 'system', 'charcoalフレームワークを終了します。', __FILE__, __LINE__ );
		}
		catch ( HttpException $e )
		{
			// ステータスコード
			$status = $e->getStatusCode();

			// ユーザ定義のerror_docsを検索
			$html_file = ResourceLocator::getWebAppPath( 'error_docs' , "$status.html" );

			if ( !is_file($html_file) ){
				// なければデフォルトのerror_docsを検索
				$html_file = ResourceLocator::getSystemPath( 'error_docs' , "$status.html" );
			}

			if ( is_file($html_file) ){
				// 読み込みと表示
				readfile( $html_file );
				print "<br>";
			}
			else{
				// Errorドキュメントファイルがない
				log_warning( 'system,error', "エラードキュメント($html_file)が存在しません。", __FILE__, __LINE__ );
			}

			// ヘッダ処理
			$header_msg_array = array(
					'401' => 'Unauthorized',
					'403' => 'Forbidden',
					'404' => 'Not Found',
					'500' => 'Internal Server Error',
				);
			$header_msg = $header_msg_array[$status];
			$message = "HTTP/1.0 $status $header_msg";
			header( $message );

			// エラーログ出力
			log_error( 'system,error', $message, __FILE__, __LINE__ );
		}
		catch ( CharcoalException $e ){

			$cause_list = $e->getCauseList();

			$cause_list[] = new CharcoalException( 'Framework#run() failed', $e );

			include( 'core/exception_list.php' );

		}
	}
}
