/*
 * 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.fukurou.db;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Properties;

/**
 * JAXBで自動生成されたDBIDクラスを拡張したクラスです。
 * (継承しているわけではない)
 * <BR>
 * 以下の属性が追加されています。<BR>
 * dbProductName<BR>
 * dbProductVersion<BR>
 * driverName<BR>
 * driverVersion<BR>
 *
 * @og.rev 4.0.0 (2007/10/25) 新規作成
 * @og.rev 5.1.7.0 (2010/06/01) メソッドの修正、Cloneable の追加(浅いコピー)
 *
 * @version  4.0
 * @author	 高橋正和
 * @since	 JDK5.0,
 */
public class EDbid implements Cloneable {

	private 	String	dbidKey			= "DEFAULT";
	private 	String	url				= null;
	private 	String	user			= null;
	private 	String	password		= null;
	private 	boolean	readonly		= false;
	private 	int		mincount		= 3;
	private 	int		maxcount		= 30;
	private 	int		pooltime		= 3000;
	private 	boolean	isUseAppInfo	= true;
	private 	boolean isParamMetaData	= false;		// 5.3.8.0 (2011/08/01)

	private 	String	dbProductName	= null;
	private 	String	dbProductVersion= null;
	private 	String	driverName		= null;
	private 	String	driverVersion	= null;

	/* DBConfigでpropertiesの指定を可能にします 5.5.2.0 */
	private final Properties props = new Properties();

	/**
	 * dbidKeyの取得
	 *
	 * 内部的には、大文字のみで管理します。
	 *
	 * @return	dbidキー
	 */
	public String getDbidKey() {
		return dbidKey;
	}

	/**
	 * dbidキーの設定
	 *
	 * 内部的には、大文字のみで管理します。
	 *
	 * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
	 *
	 * @param value 接続先ID
	 */
	protected void setDbidKey( final String value ) {
		if( isNotNull( value ) ) { dbidKey = value.toUpperCase( Locale.JAPAN ); }
	}

	/**
	 * ＵＲＬの取得
	 *
	 * @return	ＵＲＬ
	 */
	public String getUrl() {
		return url;
	}

	/**
	 * ＵＲＬの設定
	 *
	 * @param value ＵＲＬ文字列
	 */
	protected void setUrl( final String value ) {
		if( isNotNull( value ) ) { url = value; }
	}

	/**
	 * ユーザーの取得
	 *
	 * @return	ユーザー
	 */
	public String getUser() {
		return user;
	}

	/**
	 * userの設定
	 *
	 * @param value user文字列
	 */
	protected void setUser( final String value ) {
		if( isNotNull( value ) ) { user = value; }
	}

	/**
	 * パスワードの取得
	 *
	 * @return	パスワード
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * パスワードの設定
	 *
	 * @param value パスワード文字列
	 */
	protected void setPassword( final String value ) {
		if( isNotNull( value ) ) { password = value; }
	}

	/**
	 * readonlyの取得
	 *
	 * @return	[true:読み取り専用/false:通常]
	 */
	public boolean isReadonly() {
		return readonly ;
	}

	/**
	 * readonlyの設定
	 *
	 * @param value  readonly文字列 [true/false]
	 */
//	protected void setReadonly( final Boolean value ) {
//		if( value != null ) { readonly = value.booleanValue(); }
//	}
	protected void setReadonly( final String value ) {
		if( isNotNull( value ) ) { readonly = Boolean.valueOf( value ).booleanValue(); }
	}

	/**
	 * 最小数の取得
	 *
	 * @return	最小数
	 */
	public int getMincount() {
		return mincount;
	}

	/**
	 * 最小数の設定
	 *
	 * @param value 最小数(数字タイプ文字列)
	 */
//	protected void setMincount( final Integer value ) {
//		if( value != null ) { mincount = value.intValue(); }
//	}
	protected void setMincount( final String value ) {
		if( isNotNull( value ) ) { mincount = Integer.valueOf( value ).intValue(); }
	}

	/**
	 * 最大数の取得
	 *
	 * @return	最大数
	 */
	public int getMaxcount() {
		return maxcount;
	}

	/**
	 * 最大数の設定
	 *
	 * @param value 最大数(数字タイプ文字列)
	 */
//	protected void setMaxcount( final Integer value ) {
//		if( value != null ) { maxcount = value.intValue(); }
//	}
	protected void setMaxcount( final String value ) {
		if( isNotNull( value ) ) { maxcount = Integer.valueOf( value ).intValue(); }
	}

	/**
	 * プールに保管して置く時間(秒数))の取得
	 *
	 * @return	プールに保管する時間(秒数)
	 */
	public int getPooltime() {
		return pooltime;
	}

	/**
	 * プールに保管して置く時間(秒数))の設定
	 *
	 * @param value プールに保管して置く時間(秒数)(数字タイプ文字列)
	 */
//	protected void setPooltime( final Integer value ) {
//		if( value != null ) { pooltime = value.intValue(); }
//	}
	protected void setPooltime( final String value ) {
		if( isNotNull( value ) ) { pooltime = Integer.valueOf( value ).intValue(); }
	}

	/**
	 * ApplicationInfoオブジェクトを使用するかどうか[true/false]の情報を取得
	 *
	 * @return	使用するかどうか
	 */
	public boolean isApplicationInfo() {
		return isUseAppInfo ;
	}

	/**
	 * ApplicationInfoオブジェクトを使用するかどうか[true/false]の情報を設定
	 *
	 * @param value ApplicationInfoオブジェクトを使用するかどうか [true/false]
	 */
//	protected void setApplicationInfo( final Boolean value ) {
//		if( value != null ) { isUseAppInfo = value.booleanValue(); }
//	}
	protected void setApplicationInfo( final String value ) {
		if( isNotNull( value ) ) { isUseAppInfo = Boolean.valueOf( value ).booleanValue(); }
	}

	/**
	 * メタデータを受け取って
	 * dbProductName,dbProductVersion,driverName,driverVersion
	 * を一括で設定します
	 *
	 * @og.rev 4.0.0.0 (2007/10/30) 保持情報オブジェクト化に伴う変更
	 * @og.rev 5.3.8.0 (2011/08/01) postgreSQL時のカラムタイプ判定の必要有無(ApplicationInfo.useParameterMetaData)
	 *
	 * @param meta メタデータオブジェクト
	 * @throws SQLException
	 */
	public void setMetaDataInfo( final DatabaseMetaData meta ) throws SQLException {
		dbProductName	= meta.getDatabaseProductName() ;
		dbProductVersion= meta.getDatabaseProductVersion() ;
		driverName		= meta.getDriverName() ;
		driverVersion	= meta.getDriverVersion() ;

		isUseAppInfo	= isUseAppInfo && "ORACLE".equalsIgnoreCase( dbProductName ) ;
		isParamMetaData	= "PostgreSQL".equalsIgnoreCase( dbProductName );		// 5.3.8.0 (2011/08/01)
	}

	/**
	 * DBプロダクト名の取得
	 *
	 * @return	DBプロダクト名
	 */
	public String getDbProductName() {
		return dbProductName;
	}

	/**
	 * DBプロダクト・バージョンの取得
	 *
	 * @return	DBプロダクト・バージョン
	 */
	public String getDbProductVersion() {
		return dbProductVersion;
	}

	/**
	 * ドライバー名の取得
	 *
	 * @return	ドライバー名
	 */
	public String getDriverName() {
		return driverName;
	}

	/**
	 * ドライバーのバージョンの取得
	 *
	 * @return	ドライバーのバージョン
	 */
	public String getDriverVersion() {
		return driverVersion;
	}

	/**
	 * ParamMetaData を利用するかどうか[true/false]を返します。
	 *
	 * これは、PostgreSQL の時は、trueになります。
	 *
	 * @og.rev 5.3.8.0 (2011/08/01) 新規追加
	 *
	 * @return	利用するかどうか[true/false]
	 */
	public boolean useParamMetaData() {
		return isParamMetaData ;
	}

	/**
	 * propMapへの追加
	 *
	 * @og.rev 5.5.2.0 (2012/05/01) 新規追加
	 * @param key プロパティのキー
	 * @param val ポロパティの値
	 */
	protected void addProp(final String key, final String val){
		props.put ( key, val );
	}

	/**
	 * propMapへの追加
	 * 最初の=でkeyとvalueを分割する
	 *
	 * @og.rev 5.5.2.0 (2012/05/01) 新規追加
	 * @og.rev 5.5.2.1 (2012/05/07) propsへの追加漏れ,カンマを=に変更
	 * @param prop プロパティのキーと値の組み合わせ
	 */
	protected void addProp(final String prop){
//		if( prop!=null && prop.indexOf( ',' ) > 0 ){
		if( prop!=null && prop.indexOf( '=' ) > 0 ){
			final String key = prop.substring( 0 , prop.indexOf('=') );
			final String val = prop.substring( prop.indexOf('=') + 1 );
			addProp( key, val ); // 5.5.2.1 (2012/05/07)
		}
	}

	/**
	 * propMapの取得
	 *
	 * @og.rev 5.5.2.0 (2012/05/01) 新規追加
	 *
	 * @return 内部Propertiesオブジェクト
	 */
	public Properties getProps(){
		return props;
	}

	/**
	 * 文字列がnullでも空文字列でもないかどうかを評価します。
	 *
	 * スペース文字は、trim() してから、length() しますので、false になります。
	 *
	 * @og.rev 5.1.7.0 (2010/06/01) 新規作成
	 *
	 * @param value 評価する文字列
	 *
	 * @return 結果(true:nullでも空文字列でもない)
	 */
	private boolean isNotNull( final String value ) {
		return ( value != null && value.trim().length() > 0 ) ;
	}

	/**
	 * 自分自身の clone を返します。
	 *
	 * Cloneable の実装で、内部的には、Object クラスの clone メソッドを読んでいます。
	 *
	 * @og.rev 5.1.7.0 (2010/06/01) 新規作成
	 *
	 * @return 自分自身の clone を返します。
	 */
	@Override
	public EDbid clone() {
		try {
			return (EDbid)super.clone() ;
		}
		catch( CloneNotSupportedException ex ) {
			String errMsg = "clone が失敗しました。" ;
			throw new RuntimeException( errMsg,ex );
		}
	}

	/**
	 * 簡易な内部情報の文字列化します。
	 *
	 * @og.rev 5.3.4.0 (2011/04/01) toString() の簡易版
	 * @og.rev 5.5.2.1 (2012/05/07) properties情報を出力するようにする
	 *
	 * @return 内部情報の文字列
	 */
	public String info() {
		final String CR = System.getProperty( "line.separator" );
		final StringBuilder buf = new StringBuilder();
		buf.append( "DBID=[" ).append( dbidKey ).append( "]," );
		buf.append( "URL =[" ).append( url     ).append( "]," );
		buf.append( "USER=[" ).append( user    ).append( "]," );
		buf.append( CR );
		buf.append( "DB Product=[" ).append( dbProductName );
		buf.append( "(" ).append( dbProductVersion ).append( ")" ).append( "]" );
		buf.append( CR );
		buf.append( "DB Driver =[" ).append( driverName );
		buf.append( "(" ).append( driverVersion ).append( ")" ).append( "]" );
		buf.append( CR );
		buf.append( "PROPERTIES=[" ).append( props.toString() ).append( "]" ); // 5.5.2.1 (2012/05/07)
		buf.append( CR );
		return buf.toString();
	}

	/**
	 * 内部情報を文字列化します。
	 *
	 * @og.rev 5.3.4.0 (2011/04/01) info() メソッドを利用するように変更
	 *
	 * @return	内部情報の文字列
	 */
	@Override
	public String toString() {
		final String CR = System.getProperty( "line.separator" );
		final StringBuilder buf = new StringBuilder();
		buf.append( info() );
//		buf.append( "DBID=[" ).append( dbidKey ).append( "]," );
//		buf.append( "URL =[" ).append( url     ).append( "]," );
//		buf.append( "USER=[" ).append( user    ).append( "]," );
//		buf.append( CR );
//		buf.append( "DB Product=[" ).append( dbProductName );
//		buf.append( "(" ).append( dbProductVersion ).append( ")" ).append( "]" );
//		buf.append( CR );
//		buf.append( "DB Driver =[" ).append( driverName );
//		buf.append( "(" ).append( driverVersion ).append( ")" ).append( "]" );
//		buf.append( CR );
		buf.append( "MAXCOUNT=[" ).append( maxcount ).append( "]," );
		buf.append( "MINCOUNT=[" ).append( mincount ).append( "]," );
		buf.append( "POOLTIME=[" ).append( pooltime ).append( "]," );
		buf.append( "READONLY=[" ).append( readonly ).append( "]," );
		buf.append( "APPINFO=["  ).append( isUseAppInfo ).append( "]," );

		buf.append( CR );
		return buf.toString();
	}
}
