/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.db;

import org.opengion.hayabusa.common.HybsSystem ;
import org.opengion.hayabusa.common.HybsSystemException ;
import org.opengion.hayabusa.common.SystemManager ;
import org.opengion.hayabusa.resource.CodeData;
import org.opengion.fukurou.util.Cleanable;

import java.util.Map;
import java.util.WeakHashMap ;

/**
 * Selectionオブジェクトを取得する為に使用するファクトリクラスです。
 *
 * Selectionオブジェクト のキー(codeName)を元に、オブジェクトをキャッシュ管理
 * することが、主な機能です。
 *
 * @og.rev 3.5.5.7 (2004/05/10) 新規作成
 * @og.group 選択データ制御
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class SelectionFactory {
	// private static final Map<String,Selection>  codeMap = new WeakHashMap<String,Selection>();
	private static final Map<String,Selection>	dbMap		= new WeakHashMap<String,Selection>( HybsSystem.BUFFER_SMALL );
	private static final Map<String,Selection>	dbRadioMap	= new WeakHashMap<String,Selection>( HybsSystem.BUFFER_SMALL ); // 4.3.3.6 (2008/11/15)

	// 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
	static {
		Cleanable clr = new Cleanable() {
			public void clear() {
				SelectionFactory.clear();
			}
		};

		SystemManager.addCleanable( clr );
	}

	/**
	 *  デフォルトコンストラクターをprivateにして、
	 *  オブジェクトの生成をさせないようにする。
	 *
	 */
	private SelectionFactory() {
	}

	/**
	 * コードデータオブジェクトより、コードリソースSelectionオブジェクトを構築します。
	 *
	 * @og.rev 4.0.0.0 (2007/11/07) DBColumnにSelectionオブジェクトをキャッシュするように変更
	 *
	 * @param   cdData CodeData コードデータ
	 *
	 * @return  Selectionオブジェクト
	 */
//	public static Selection newCodeSelection( final CodeData cdData ) {
//		String key = cdData.getColumn() ;
//		Selection select = codeMap.get( key );
//		if( select == null ) {
//			synchronized( codeMap ) {
//				select = new Selection_CODE( cdData );
//				codeMap.put( key,select );
//			}
//		}
//		return select;
//	}

	/**
	 * DB検索(SQL)文字列より、データベースSelectionオブジェクトを構築します。
	 * Selection_DB では、検索行毎のクエリーがあるため、name + query でキャッシュします。
	 *
	 * @og.rev 4.0.0.0 (2006/11/15) lang 属性を追加します。
	 *
	 * @param   query DB検索(SQL)文字列
	 * @param	dbid  データベース接続先ID
	 * @param	lang  リソースを使用する場合の言語
	 *
	 * @return  Selectionオブジェクト
	 */
	public static Selection newDBSelection( final String query,final String dbid,final String lang ) {
		String key = query+dbid+lang;
		Selection select = dbMap.get( key );

		if( select == null || select.isTimeOver() ) {
			synchronized( dbMap ) {
				select = new Selection_DB( query,dbid,lang );
				dbMap.put( key,select );
			}
		}
		return select;
	}

	/**
	 * DB検索(SQL)文字列より、データベースSelectionオブジェクトを構築します。
	 * Selection_DB では、検索行毎のクエリーがあるため、name + query でキャッシュします。
	 *
	 * @og.rev 4.3.3.6 (2008/11/15) 新規作成
	 *
	 * @param   query DB検索(SQL)文字列
	 * @param	dbid  データベース接続先ID
	 * @param	lang  リソースを使用する場合の言語
	 *
	 * @return  Selectionオブジェクト
	 */
	public static Selection newDBRadioSelection( final String query,final String dbid,final String lang ) {
		String key = query+dbid+lang;
		Selection select = dbRadioMap.get( key );

		if( select == null || select.isTimeOver() ) {
			synchronized( dbRadioMap ) {
				select = new Selection_DBRADIO( query,dbid,lang );
				dbRadioMap.put( key,select );
			}
		}
		return select;
	}

	/**
	 * 各種Selectionオブジェクトを構築します。
	 * ここでは、Selectionオブジェクトのタイプが、(KEYVAL,HM,NUM,YMD)について作成されます。
	 * ここで作成されるオブジェクトは、この、SelectionFactoryではキャッシュしません。
	 * 各RendererやEditorが共有されているので、そちらでキャッシュされています。
	 * type が指定のキーワード以外の場合は、Exception が返されます。
	 * ※ type="NULL" も使用可能です。これは、どんな場合でも、引数の param を返す Selection
	 * オブジェクトを返します。内部的に、CodeDataが存在しない場合など、エラーメッセージを
	 * 引数に与えて修正を促すようなケースで使用します。
	 *
	 * @og.rev 5.7.3.0 (2014/02/07) 新規作成
	 *
	 * @param   type  Selectionオブジェクトのタイプ(KEYVAL,HM,NUM,YMD)
	 * @param	param パラメータ
	 *
	 * @return  Selectionオブジェクト
	 * @throws  HybsSystemException
	 */
	public static Selection newSelection( final String type,final String param ) {
		Selection select = null;
		if( "KEYVAL".equalsIgnoreCase( type ) ) {
			select = new Selection_KEYVAL( param );
		}
		else if( "HM".equalsIgnoreCase( type ) ) {
			select = new Selection_HM( param );
		}
		else if( "NUM".equalsIgnoreCase( type ) ) {
			select = new Selection_NUM( param );
		}
		else if( "YMD".equalsIgnoreCase( type ) ) {
			select = new Selection_YMD( param );
		}
		else if( "NULL".equalsIgnoreCase( type ) ) {
			select = new Selection_NULL( param );
		}
		else {
			select = new Selection_NULL( param );
			String errMsg = "指定のタイプ[" + type + "]が、存在しません。タイプ一覧=[KEYVAL,HM,NUM,YMD]" + HybsSystem.CR ;
			throw new HybsSystemException( errMsg );
		}

		return select;
	}

	/**
	 * 各種Selectionオブジェクトを構築します。
	 * ここでは、Selectionオブジェクトのタイプが、(MENU,RADIO)について作成されます。
	 * ここで作成されるオブジェクトは、この、SelectionFactoryではキャッシュしません。
	 * 各RendererやEditorが共有されているので、そちらでキャッシュされています。
	 * type が指定のキーワード以外の場合は、Exception が返されます。
	 * codeData オブジェクトが null の場合は、Selectionオブジェクト は null が返されます。
	 *
	 * @og.rev 5.7.3.0 (2014/02/07) 新規作成
	 *
	 * @param   type  Selectionオブジェクトのタイプ(MENU,RADIO)
	 * @param	codeData CodeDataオブジェクト
	 *
	 * @return  Selectionオブジェクト
	 * @throws  HybsSystemException
	 */
	public static Selection newSelection( final String type,final CodeData codeData ) {
		Selection select = null;
		if( codeData != null ) {
			if( "MENU".equalsIgnoreCase( type ) ) {
				select = new Selection_CODE( codeData );
			}
			else if( "RADIO".equalsIgnoreCase( type ) ) {
				select = new Selection_RADIO( codeData );
			}
			else {
				String errMsg = "指定のタイプ[" + type + "]が、存在しません。タイプ一覧=[MENU,RADIO]" + HybsSystem.CR ;
				throw new HybsSystemException( errMsg );
			}
		}

		return select;
	}

	/**
	 * Selectionオブジェクトをプールからすべて削除します。
	 * システム全体を初期化するときや、動作が不安定になったときに行います。
	 * プールの方法自体が,一種のキャッシュ的な使いかたしかしていない為,
	 * 実行中でも、いつでもプールを初期化できます。
	 *
	 * @og.rev 4.3.3.6 (2008/11/15) DBRadioMap追加
	 */
	public static void clear() {
		// synchronized( codeMap ) { codeMap.clear(); }
		synchronized( dbMap   ) { dbMap.clear(); }
		synchronized( dbRadioMap ) { dbRadioMap.clear(); } // 4.3.3.6 (2008/11/15)
	}
}
