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

import org.opengion.fukurou.util.StringUtil ;
import org.opengion.hayabusa.common.HybsSystemException;			// 6.4.7.0 (2016/06/03)

import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;	// 6.1.0.0 (2014/12/26) refactoring
import static org.opengion.fukurou.system.HybsConst.CR ;			// 6.1.0.0 (2014/12/26)

import java.text.MessageFormat;
import java.util.Arrays;											// 6.4.7.0 (2016/06/03)

/**
 * systemId , lang に対応したラベルデータを作成します。
 *
 * ラベルデータは、項目(CLM)に対して、各種ラベル情報を持っています。
 * 従来のラベルは、表示名称として、一種類しか持っていませんでしたが、
 * ラベルデータは、３種類の名称と、１種類の概要を持っています。
 *
 *   label       : 名称(長)      従来のラベルと同じで定義された文字そのものです。
 *   shortLabel  : 名称(HTML短)  概要説明をバルーン表示する短い名称です。
 *   longLabel   : 名称(HTML長)  概要説明をバルーン表示する長い名称です。
 *   description : 概要説明      カラムの説明やバルーンに使用します。
 *
 * 名称(HTML長)は、従来の表示名称にあたります。これは、一般的なラベルとして
 * 使用されます。名称(HTML短)は、テーブル一覧のヘッダーの様に、特殊なケースで、
 * 簡略化された名称を使用するときに利用されます。この切り替えは、自動で判断されます。
 * 名称(HTML短)に、なにも設定されていない場合は、名称(HTML長)が自動的に使用されますので
 * 初期データ移行時には、そのまま、通常時もテーブルヘッダー時も同じ文字列が
 * 使用されます。
 * ただし、一覧表示のうち、EXCEL出力などのデータには、名称(長)が使用されます。
 * これは、名称(HTML短)や名称(HTML長)は、Tips表示を行う為のHTML構文を採用している為
 * テキスト等に出力するには不適切だからです。また、EXCEL等のツールでは、ラベル名が
 * 長くてもセル幅等で調整できる為、簡略化された名称よりも正式名称で出力します。
 *
 * ラベルデータを作成する場合は、同一ラベルで、作成区分(KBSAKU)違いの場合は、
 * 最も大きな作成区分を持つコードを使用します。
 * 作成区分(KBSAKU)は、0:システム予約、1:アプリ設定、2:ユーザー設定 という具合に
 * カスタマイズの度合いに応じて大きな数字を割り当てることで、キー情報を上書き修正
 * することが可能になります。(削除することは出来ません。)
 *
 * @og.rev 4.0.0.0 (2004/12/31) 新規作成
 * @og.group リソース管理
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class LabelData implements LabelInterface {

	/** 内部データのカラム番号 {@value}	*/
	public static final int CLM			= 0 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int SNAME		= 1 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int LNAME		= 2 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int DESCRIPTION	= 3 ;
//	/** 内部データのカラム数 {@value}	*/
//	public static final int DATA_SIZE	= 4 ;		// 7.2.6.0 (2020/06/30) 未使用なので削除

	/** リソース読み込みのために一時利用 4.3.5.7 (2009/03/22) */
	/* default */ static final int FG_LOAD		= 4 ;
	/** FGLOAD の読み込み済み設定用のUNIQ 6.3.1.1 (2015/07/10) */
	/* default */ static final int UNIQ			= 5 ;
	/** FGLOAD の読み込み済み設定用のSYSTEM_ID 6.3.1.1 (2015/07/10) */
	/* default */ static final int SYSTEM_ID	= 6 ;

	public static final int SNO			= 7 ;	// 7.2.6.1 (2020/07/17) 内部的に使ってないが定義しておく

	private final String	key			;		// 項目
	private final String	label		;		// 名称(長)
	private final String	shortLabel	;		// 名称(HTML短)
	private final String	longLabel	;		// 名称(HTML長)
	private final String	description	;		// 概要説明
	private final boolean	official	;		// リソースＤＢから作成されたかどうか
//	private final boolean	isFormat	;		// メッセージフォーマット対象かどうか 4.0.0.0 (2007/10/17) 7.1.0.1 (2020/02/07) 長,短,概要などあるため、直前にチェック
	private final String	rawShortLabel;		// 名称(未変換短) 4.3.8.0 (2009/08/01)
//	private final boolean	isFormatDesc;		// 概要がフォーマット対象か 4.3.7.6 (2009/07/15) 7.1.0.1 (2020/02/07) 未使用
	private final String	rawLongLabel;		// 名称(未変換長) 5.6.8.2 (2013/09/20)

	/**
	 * null LabelData オブジェクトを作成します。
	 * このオブジェクトは、ＤＢリソース上に存在しない場合に使用される
	 * null 情報を表す、LabelData オブジェクトです。
	 *
	 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel対応
	 * @og.rev 5.7.3.0 (2014/02/07) public に格上げします。
	 * @og.rev 7.0.1.5 (2018/12/10) 名前とﾗﾍﾞﾙだけ異なるLabelDataオブジェクトを作成します。
	 *
	 * @param	inkey	キー情報
	 */
	public LabelData( final String inkey ) {
		this( inkey,inkey );
//		key			= inkey.intern() ;
//		label		= key ;		// 名称(長)
//		shortLabel	= key ;		// 名称(HTML短)
//		longLabel	= key ;		// 名称(HTML長)
//		description	= ""  ;		// 概要説明
//		official	= false;	// 非正式
//		isFormat 	= false;	// 非フォーマット 4.0.0.0 (2007/10/17)
//		rawShortLabel = key;	// 名称(未変換短) 4.3.8.0 (2009/08/01)
//		isFormatDesc = false;	// 概要フォーマット 4.3.7.6 (2009/07/15)
//		rawLongLabel = key;		// 名称(未変換長)5.6.8.2 (2013/09/20)
	}

	/**
	 * 名前とﾗﾍﾞﾙだけ異なるLabelDataオブジェクトを作成します。
	 *
	 * これは、ﾗﾍﾞﾙを簡易的に利用する場合に使用する、LabelData オブジェクトです。
	 *
	 * @og.rev 7.0.1.5 (2018/12/10) 名前とﾗﾍﾞﾙだけ異なるLabelDataオブジェクトを作成します。
	 * @og.rev 7.1.0.1 (2020/02/07) isFormat、isFormatDescは、長,短,概要などあるため、直前にチェックするので廃止。
	 *
	 * @param	inkey	キー情報
	 * @param	inLbl	ﾗﾍﾞﾙ
	 */
	public LabelData( final String inkey,final String inLbl ) {
		key			= inkey.intern() ;
		label		= inLbl ;	// 名称(長)
		shortLabel	= inLbl ;	// 名称(HTML短)
		longLabel	= inLbl ;	// 名称(HTML長)
		description	= ""  ;		// 概要説明
		official	= false;	// 非正式
//		isFormat 	= false;	// 非フォーマット 4.0.0.0 (2007/10/17) 7.1.0.1 (2020/02/07) 廃止
		rawShortLabel = inLbl;	// 名称(未変換短) 4.3.8.0 (2009/08/01)
//		isFormatDesc = false;	// 概要フォーマット 4.3.7.6 (2009/07/15) 7.1.0.1 (2020/02/07) 廃止
		rawLongLabel = inLbl;	// 名称(未変換長)5.6.8.2 (2013/09/20)
	}

	/**
	 * 配列文字列のデータを元に、LabelDataオブジェクトを構築します。
	 * このコンストラクタは、他のパッケージから呼び出せないように、
	 * パッケージプライベートにしておきます。
	 * このコンストラクタは、ＤＢリソースファイルを想定しています。
	 *
	 * @og.rev 5.4.0.1 (2011/11/01) SNAME、概要説明、rawShortLabel 関係の処理を修正
	 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel対応
	 * @og.rev 6.2.2.0 (2015/03/27) BRと\nを相互に変換する処理を追加
	 * @og.rev 6.2.2.3 (2015/04/10) htmlフィルターに、BR→改行処理機能を追加。
	 * @og.rev 6.3.9.0 (2015/11/06) StringUtil.yenN2br は、null を返しません。
	 * @og.rev 7.1.0.1 (2020/02/07) isFormat、isFormatDescは、長,短,概要などあるため、直前にチェックするので廃止。
	 *
	 * @param	data	CLM,SNAME,LNAME,DESCRIPTION
	 */
	LabelData( final String[] data ) {
		key			= data[CLM].intern() ;								// 項目
		label		= StringUtil.yenN2br( data[LNAME] ) ;				// 6.2.2.3 (2015/04/10) 名称(HTML長)
		description	= StringUtil.yenN2br( data[DESCRIPTION] ) ;			// 6.2.2.3 (2015/04/10) 概要説明
		official	= true;												// 正式
//		isFormat	= label.indexOf( '{' ) >= 0 ;						// 4.0.0.0 (2007/10/17)
		String title = null;

		rawLongLabel = label;		// 名称(未変換長)5.6.8.2 (2013/09/20)
		if( description.isEmpty() ) {									// 6.3.9.0 (2015/11/06) StringUtil.yenN2br は、null を返しません。
//			isFormatDesc = false;
			// 5.4.0.1 (2011/11/01) title と label が間違っている。(SNAME が存在する場合)
			title     = StringUtil.htmlFilter( label,true ) ;			// 6.2.2.0 (2015/03/27)

			// 概要説明がない場合は、そのままラベルを使用する。
			longLabel = label;
		}
		else {
//			isFormatDesc = description.indexOf( '{' ) >= 0 ;			// 5.1.8.0 (2010/07/01) nullポインタの参照外し対策
			title        = StringUtil.htmlFilter( description,true ) ;	// 6.2.2.0 (2015/03/27)

			// 概要説明がある場合は、ツールチップにDESCRIPTIONを表示する。
			longLabel = "<span title=\""
							+ title
							+ "\">"
							+ label
							+ "</span>" ;
		}

		final String sname = data[SNAME];		// 名称(HTML短)
		if( sname == null || sname.isEmpty() ) {
			// SNAME がない場合は、longLabel を使用する。
			shortLabel    = longLabel;
			rawShortLabel = label;		// 5.4.0.1 (2011/11/01) longLabel を使うと、ツールチップが加味されるため。
		}
		else {
			// SNAME が存在する場合、ツールチップにdescriptionかlabelを使用する。
			shortLabel = "<span title=\""
							+ title
							+ "\">"
							+ sname
							+ "</span>" ;
			rawShortLabel = sname; // 4.3.8.0 (2009/08/01)
		}
	}

	/**
	 * ラベルオブジェクトのキーを返します。
	 *
	 * @return	ラベルオブジェクトのキー
	 */
	public String getKey() { return key; }

	/**
	 * ラベルオブジェクトの名称を返します。
	 * これは、ＤＢ上の LNAME(名称(長))に該当します。
	 *
	 * @return	ラベルオブジェクトの名称(短)
	 */
	public String getLabel() { return label; }

	/**
	 * ラベルオブジェクトの名称(短)を返します。
	 * 概要説明がない場合でかつＤＢ上のSNAMEが未設定の場合は、
	 * LNAME が返されます。SNAMEが設定されている場合は、
	 * ツールチップにLNAME が表示されます。
	 * 概要説明が存在する場合は、ツールチップに概要説明が
	 * 表示されます。
	 *
	 * @return	ラベルオブジェクトの名称(短)
	 */
	public String getShortLabel() { return shortLabel; }

	/**
	 * ラベルオブジェクトの名称(長)を返します。
	 * 概要説明が存在する場合は、ツールチップに概要説明が
	 * 表示されます。
	 *
	 * @return	ラベルオブジェクトの名称(長)
	 * @see #getLongLabel( String )
	 */
	public String getLongLabel() { return longLabel; }

	/**
	 * ラベルインターフェースの名称(長)を返します。
	 * ツールチップに表示するタイトル属性(概要説明)を置き換えます。
	 * null の場合は、既存のgetLongLabel()を返します。
	 *
	 * @og.rev 6.2.2.0 (2015/03/27) BRと\nを相互に変換する処理を追加
	 * @og.rev 6.2.2.3 (2015/04/10) htmlフィルターに、BR→改行処理機能を追加。
	 *
	 * @param	title	ツールチップに表示するタイトル属性
	 *
	 * @return	ラベルインターフェースの名称(長)
	 * @see #getLongLabel()
	 */
	public String getLongLabel( final String title ) {
		final String tipsLabel ;
		if( title == null ) {
			tipsLabel = longLabel;
		}
		else {
			tipsLabel = "<span title=\""
							+ StringUtil.htmlFilter( title,true )	// 6.2.2.3 (2015/04/10)
							+ "\">"
							+ label
							+ "</span>" ;
		}
		return tipsLabel ;
	}

	/**
	 * ラベルインターフェースの引数付きメッセージを返します。
	 * メッセージの引数部分に、文字列配列を適用して、MessageFormat
	 * で変換した結果を返します。(MessageData でのみ有効です。)
	 *
	 * @og.rev 4.0.0.0 (2007/10/17) メッセージリソース統合に伴い、MessageDataより移行
	 * @og.rev 4.3.8.0 (2009/08/01) 引数にHTMLサニタイジング処理
	 * @og.rev 5.0.0.2 (2009/09/15) サニタイジング処理をやめる
	 * @og.rev 6.4.3.4 (2016/03/11) ラベル {n} が存在しない場合は、引数を連結せず、元のラベルを返す。
	 * @og.rev 6.4.5.0 (2016/04/08) リソースから作成された場合は、引数を連結せず、そうでない場合は連結します。
	 * @og.rev 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
	 * @og.rev 7.0.7.0 (2019/12/13) #getMessage(String...) , #getDescription(String...) , #getShortMessage(String...) を統合します。
	 * @og.rev 7.1.0.1 (2020/02/07) isFormat、isFormatDescは、長,短,概要などあるため、直前にチェックするので廃止。
	 *
	 * @param	lbl		メッセージを作成する元となるラベル文字列
	 * @param	vals	メッセージ引数の文字列配列(可変長引数)
	 *
	 * @return	ラベルインターフェースの引数付きメッセージ
	 */
//	public String getMessage( final String... vals ) {			// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
	private String getMessage( final String lbl , final String[] vals ) {
		final String rtn ;

		final String[] args		= ( vals == null ) ? new String[0] : vals ;
		final boolean isFormat	= lbl != null && lbl.indexOf( '{' ) >= 0 ;		// 7.1.0.1 (2020/02/07)
		if( isFormat ) {
			// 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
			try {
//				rtn = MessageFormat.format( label,(Object[])args );
				rtn = MessageFormat.format( lbl,(Object[])args );
			}
			catch( final IllegalArgumentException ex ) {
				final String errMsg = "MessageFormatエラー:"
							+ " Key [" + key + "]"
//							+ " Pattern [" + label + "]"
							+ " Pattern [" + lbl + "]"
							+ " Arguments [" + Arrays.toString( (Object[])args ) + "]" ;
				throw new HybsSystemException( errMsg,ex );
			}
		}
		else {
			// 6.4.5.0 (2016/04/08) リソースから作成された場合は、引数を連結せず、そうでない場合は連結します。
			if( official ) {
//				rtn = label ;			// 6.4.3.4 (2016/03/11)
				rtn = lbl ;				// 6.4.3.4 (2016/03/11)
			}
			else {
				final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
//					.append( label );
					.append( lbl );
				for( final String val : args ) {
//					if( val != null && ! val.equals( label ) ) {
					if( val != null && ! val.equals( lbl ) ) {
						buf.append( ' ' ).append( val );					// 6.0.2.5 (2014/10/31) char を append する。
					}
				}
				rtn = buf.toString();
			}
		}
		return rtn ;
	}

	/**
	 * ラベルインターフェースの引数付きメッセージを返します。
	 * メッセージの引数部分に、文字列配列を適用して、MessageFormat
	 * で変換した結果を返します。(MessageData でのみ有効です。)
	 *
	 * @og.rev 4.0.0.0 (2007/10/17) メッセージリソース統合に伴い、MessageDataより移行
	 * @og.rev 4.3.8.0 (2009/08/01) 引数にHTMLサニタイジング処理
	 * @og.rev 5.0.0.2 (2009/09/15) サニタイジング処理をやめる
	 * @og.rev 6.4.3.4 (2016/03/11) ラベル {n} が存在しない場合は、引数を連結せず、元のラベルを返す。
	 * @og.rev 6.4.5.0 (2016/04/08) リソースから作成された場合は、引数を連結せず、そうでない場合は連結します。
	 * @og.rev 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
	 * @og.rev 7.0.7.0 (2019/12/13) #getMessage(String...) , #getDescription(String...) , #getShortMessage(String...) を統合します。
	 *
	 * @param	vals	メッセージ引数の文字列配列(可変長引数)
	 *
	 * @return	ラベルインターフェースの引数付きメッセージ
	 */
	public String getMessage( final String... vals ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
		return getMessage( label,vals );

//		final String rtn ;
//
//		final String[] args = ( vals == null ) ? new String[0] : vals ;
//		if( isFormat ) {
//			// 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
//			try {
//				rtn = MessageFormat.format( label,(Object[])args );
//			}
//			catch( final IllegalArgumentException ex ) {
//				final String errMsg = "MessageFormatエラー:"
//							+ " Key [" + key + "]"
//							+ " Pattern [" + label + "]"
//							+ " Arguments [" + Arrays.toString( (Object[])args ) + "]" ;
//				throw new HybsSystemException( errMsg,ex );
//			}
//		}
//		else {
//			// 6.4.5.0 (2016/04/08) リソースから作成された場合は、引数を連結せず、そうでない場合は連結します。
//			if( official ) {
//				rtn = label ;			// 6.4.3.4 (2016/03/11)
//			}
//			else {
//				final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
//					.append( label );
//				for( final String val : args ) {
//					if( val != null && ! val.equals( label ) ) {
//						buf.append( ' ' ).append( val );					// 6.0.2.5 (2014/10/31) char を append する。
//					}
//				}
//				rtn = buf.toString();
//			}
//		}
//		return rtn ;
	}

	/**
	 * ラベルオブジェクトの概要説明を返します。
	 * 概要説明が存在する場合は、ラベルのツールチップに
	 * 概要説明が表示されます。
	 *
	 * @return	ラベルオブジェクトの概要説明
	 */
	public String getDescription() { return description; }

	/**
	 * ラベルオブジェクトの概要説明を返します。
	 * このメソッドでは{0},{1}...をパラメータで置換します。
	 *
	 * @og.rev 4.3.7.6 (2009/07/15) 新規作成
	 * @og.rev 4.3.8.0 (2009/08/01) 引数にHTMLサニタイジング処理
	 * @og.rev 5.0.0.2 (2009/09/15) サニタイジング処理をやめる
	 * @og.rev 5.4.0.1 (2011/11/01) {}が存在しない場合は単に概要を出力
	 * @og.rev 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
	 * @og.rev 7.0.7.0 (2019/12/13) #getMessage(String...) , #getDescription(String...) , #getShortMessage(String...) を統合します。
	 *
	 * @param	vals	メッセージ引数の文字列配列(可変長引数)
	 *
	 * @return	ラベルオブジェクトの概要説明
	 */
	public String getDescription( final String... vals ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
		return getMessage( description,vals );

//		final String rtn ;
//
//		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
//		final String[] args = ( vals == null ) ? new String[0] : vals ;
//		if( isFormatDesc ) {
//			// 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
//			try {
//				rtn = MessageFormat.format( description,(Object[])args );
//			}
//			catch( final IllegalArgumentException ex ) {
//				final String errMsg = "MessageFormatエラー:"
//							+ " Key [" + key + "]"
//							+ " Pattern [" + description + "]"
//							+ " Arguments [" + Arrays.toString( (Object[])args ) + "]" ;
//				throw new HybsSystemException( errMsg,ex );
//			}
//		}
//		else {
//			// 5.4.0.1 (2011/11/01) {}が存在しない場合は単に概要を出力 ・・・ なら、直接セットに変更
//			rtn = description;
//		}
//		return rtn ;
	}

	/**
	 * ラベルオブジェクトの名称(未変換短)を返します。
	 * このメソッドでは{0},{1}...をパラメータで置換します。
	 *
	 * @og.rev 7.0.7.0 (2019/12/13) #getMessage(String...) , #getDescription(String...) , #getShortMessage(String...) を統合します。
	 *
	 * @param	vals	メッセージ引数の文字列配列(可変長引数)
	 *
	 * @return ラベルインターフェースの名前(短)
	 */
	public String getShortMessage( final String... vals ) {
		return getMessage( rawShortLabel,vals );
	}

	/**
	 * リソースＤＢから作成されたかどうかを返します。
	 * 正式な場合は、true / リソースになく、独自に作成された場合は、false になります。
	 *
	 * @return	リソースＤＢから作成されたかどうか
	 */
	public boolean isOfficial() { return official; }

	/**
	 * ラベルオブジェクトの名称(長)をそのままの形で返します。
	 * （discription等を付けない)
	 *
	 * @og.rev 5.6.8.2 (2009/08/01) 追加
	 *
	 * @return	ラベルオブジェクトの名称(長)そのままの状態
	 */
	public String getRawLongLabel() { return rawLongLabel; }

	/**
	 * ラベルオブジェクトの名称(短)をspanタグを付けない状態で返します。
	 * SNAMEが未設定の場合は、LNAME が返されます。
	 *
	 * @og.rev 4.3.8.0 (2009/08/01) 追加
	 *
	 * @return	ラベルオブジェクトの名称(短)にspanタグを付けない状態
	 */
	public String getRawShortLabel() { return rawShortLabel; }

	/**
	 * オブジェクトの識別子として，詳細なユーザー情報を返します。
	 *
	 * @return  詳細なユーザー情報
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
			.append( "CLM :" ).append( key )
			.append( " SNAME :" ).append( shortLabel )
			.append( " LNAME :" ).append( longLabel )
			.append( " DESCRIPTION :" ).append( description ).append( CR );
		return rtn.toString();
	}
}
