/*
 * 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 static org.opengion.fukurou.util.StringUtil.nval2;

/**
 * systemId に対応したカラムデータを作成します。
 *
 * カラムデータは、項目(CLM)に対して、各種カラム情報を持っています。
 * エンジン内部で使用している DBColumn オブジェクトは、RENDERER や EDITOR など
 * 実際にはオブジェクトで管理していますが、この ColumnData では、それらのキーとなる
 * 文字列を持っています。実際に DBColumn オブジェクトの構築時に、各属性オブジェクトを
 * 生成(または、キャッシュから取り出し)ます。
 *
 * カラムデータを作成する場合は、同一カラムで、作成区分(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 ColumnData {

	/** 内部データのカラム番号 {@value}	*/
	public static final int CLM				= 0 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int CLS_NAME		= 1 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int USE_LENGTH		= 2 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int VIEW_LENGTH		= 3 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int RENDERER		= 4 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int EDITOR			= 5 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int DBTYPE			= 6 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int DATA_DEFAULT	= 7 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int LABEL_CLM		= 8 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int CODE_CLM		= 9 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int CLM_PARAM		= 10 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int RENDERER_PARAM	= 11 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int EDITOR_PARAM	= 12 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int TYPE_PARAM		= 13 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int ROLES			= 14 ;
	/** 内部データのカラム番号 {@value}	*/
	public static final int FIELD_SIZE		= 15 ;					// 6.2.0.0 (2015/02/27) フィールドサイズ 追加

	/** 内部データのカラム数 {@value}	*/
	public static final int DATA_SIZE		= 16 ;					// 6.2.0.0 (2015/02/27) 件数を増やす

	/** リソース読み込みのために一時利用 4.3.5.7 (2009/03/22) */
	/* default */ static final int FG_LOAD			= 16 ;						// 6.2.0.0 (2015/02/27) 位置をずらす
	/** FGLOAD の読み込み済み設定用のUNIQ 6.3.1.1 (2015/07/10) */
	/* default */ static final int UNIQ				= 17 ;
	/** FGLOAD の読み込み済み設定用のSYSTEM_ID 6.3.1.1 (2015/07/10) */
	/* default */ static final int SYSTEM_ID			= 18 ;

	private final String	name			;		// カラム名
	private final String	className		;		// データの属性(VARCHAR2,NUMBER...)
	private final String	maxlength		;		// 最大桁数
	private final String	viewLength		;		// 表示桁数
	private final String	fieldSize		;		// 6.2.0.0 (2015/02/27) 入力枠サイズ
	private final String	renderer		;		// 表示種別
	private final String	editor			;		// 編集種別
	private final String	dbType			;		// 文字種別(S9,X...)
	private final String	dataDef			;		// データのデフォルト値
	private final String	labelClm		;		// ラベルカラム
	private final String	codeClm			;		// コードカラム
	private final String	columnPrm		;		// カラムパラメータ
	private final String	rendererPrm		;		// 表示パラメータ
	private final String	editorPrm		;		// 編集パラメータ
	private final String	dbTypePrm		;		// 文字パラメータ
	private final String	roles			;		// カラムロール
	private final RoleMode	roleMode		;		// 4.3.0.0 (2008/07/04) ロールズとモードを管理するオブジェクト

	private final int		totalSize		;		// 総桁数(小数点も含む)
	private final int		sizeX			;		// カラムの文字桁数(整数部)
	private final int		sizeY			;		// カラムの文字桁数(小数部)
	private final boolean   official		;		// リソースＤＢから作成されたかどうか

	/**
	 * 配列文字列のデータを元に、ColumnDataオブジェクトを構築します。
	 * このコンストラクタは、他のパッケージから呼び出せないように、
	 * パッケージプライベートにしておきます。
	 * このコンストラクタは、ＤＢリソースファイルを想定しています。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 * @og.rev 5.1.6.0 (2010/05/01) DBTypeの初期値を "XK" とします。
	 * @og.rev 5.2.2.0 (2010/11/01) パラメーターもVer3互換のためNVAL2で処理します。
	 * @og.rev 5.5.8.5 (2012/11/27) 編集パラメータで、"=" と記述されている場合は、表示パラメータを利用する。
	 * @og.rev 6.1.0.0 (2014/12/26) カラムの表示桁数(小数部)対応
	 * @og.rev 6.2.0.0 (2015/02/27) フィールドサイズ 追加(VIEW_LENGTHと分離して、役割を明確にする)
	 *
	 * @param	data	CLM,CLS_NAME,USE_LENGTH,VIEW_LENGTH,
	 *                      RENDERER,EDITOR,DBTYPE,DATA_DEFAULT,LABEL_CLM,CODE_CLM,
	 *                      CLM_PARAM,RENDERER_PARAM,EDITOR_PARAM,TYPE_PARAM,ROLES,FIELD_SIZE
	 *
	 */
	public ColumnData( final String[] data ) {
		name		= data[CLM].intern() ;						// カラム名
		className	= data[CLS_NAME].intern() ;					// データの属性
		maxlength	= data[USE_LENGTH].replace( '.',',' ).intern();		// 最大桁数
		fieldSize	= nval2( data[FIELD_SIZE]	 , null ) ;		// 6.2.0.0 (2015/02/27) 入力枠サイズ
		renderer	= nval2( data[RENDERER]		 , null ) ;		// 表示種別
		editor		= nval2( data[EDITOR]		 , null ) ;		// 編集種別
		dbType		= nval2( data[DBTYPE]		 , "XK" ) ;		// 文字種別  5.1.6.0 (2010/05/01)
		dataDef		= nval2( data[DATA_DEFAULT]	 , ""   ) ;		// データのデフォルト値
		labelClm	= nval2( data[LABEL_CLM]	 , name ) ;		// ラベルカラム
		codeClm		= nval2( data[CODE_CLM]		 , name ) ;		// コードカラム
		columnPrm	= nval2( data[CLM_PARAM]	 , null ) ;		// カラムパラメータ
		rendererPrm	= nval2( data[RENDERER_PARAM], null ) ;		// 表示パラメータ
		dbTypePrm	= nval2( data[TYPE_PARAM]	 , null ) ;		// 文字パラメータ
		roles		= nval2( data[ROLES]		 , null ) ;		// カラムロール
		official	= true;										// リソースＤＢから作成されたかどうか

		// 6.1.0.0 (2014/12/26) カラムの表示桁数(小数部)対応と、カンマ置換処理
		final String viewLen = nval2( data[VIEW_LENGTH] , null ) ;
		viewLength = viewLen == null ? null : viewLen.replace( '.',',' ).intern();

		// 5.5.8.5 (2012/11/27) 編集パラメータで、"=" と記述されている場合は、表示パラメータを利用する。
		final String tempEditPrm = nval2( data[EDITOR_PARAM], null ) ;
		if( "=".equals( tempEditPrm ) ) {
			editorPrm = rendererPrm	;
		}
		else {
			editorPrm = tempEditPrm	;
		}

		roleMode	= RoleMode.newInstance( roles );	// ロールモード

		// x,y 形式の場合、x + 2 桁で表されます。(マイナス記号と小数点記号)
		// 7,3 は、 xxxx,yyy のフォーマットで、データ長は、9 になります。
		final int ch = maxlength.indexOf( ',' ) ;
		if( ch > 0 ) {
			sizeY = Integer.parseInt( maxlength.substring( ch+1 ) );
			sizeX = Integer.parseInt( maxlength.substring( 0,ch ) ) - sizeY;
			totalSize = sizeX + sizeY+ 2;
		}
		else {
			sizeY = 0;
			sizeX = Integer.parseInt( maxlength );
			if( "S9".equals( dbType ) ) {
				totalSize = sizeX + 1;	// 数字型の場合は、マイナス記号分を加える。
			}
			else {
				totalSize = sizeX ;
			}
		}
	}

	/**
	 * ColumnDataオブジェクトを元に、名前だけ異なるColumnDataオブジェクトを構築します。
	 *
	 * @og.rev 7.0.1.5 (2018/12/10) 名前だけ異なるColumnDataオブジェクトを作成します。
	 *
	 * @param   name  となる元ColumnDataオブジェクト
	 * @param   name  カラム名
	 *
	 */
	private ColumnData( final ColumnData other,final String name ) {
		this.name		= name;
		className		= other.className	;
		maxlength		= other.maxlength	;
		viewLength		= other.viewLength	;
		fieldSize		= other.fieldSize	;
		renderer		= other.renderer	;
		editor			= other.editor		;
		dbType			= other.dbType		;
		dataDef			= other.dataDef		;
		labelClm		= other.labelClm	;
		codeClm			= other.codeClm		;
		columnPrm		= other.columnPrm	;
		rendererPrm		= other.rendererPrm	;
		editorPrm		= other.editorPrm	;
		dbTypePrm		= other.dbTypePrm	;
		roles			= other.roles		;
		roleMode		= other.roleMode	;
		totalSize		= other.totalSize	;
		sizeX			= other.sizeX		;
		sizeY			= other.sizeY		;
		official		= other.official	;
	}

	/**
	 * 内部データの属性をコピーした、名前だけ異なるColumnDataオブジェクトを作成します。
	 *
	 * @og.rev 7.0.1.5 (2018/12/10) 名前だけ異なるColumnDataオブジェクトを作成します。
	 *
	 * @param   name  カラム名
	 * @return	カラムデータオブジェクト
	 */
	public ColumnData copyOf( final String name ) {
		return new ColumnData( this , name );
	}

	/**
	 * カラム名を返します。
	 *
	 * @return  カラム名
	 */
	public String getName() { return name; }

	/**
	 * カラムのデータの属性を返します。
	 *
	 * @return  カラムのデータの属性
	 */
	public String getClassName() { return className; }

	/**
	 * フィールドの使用桁数を返します。
	 * 小数指定の場合は、"7,3" のようなカンマで整数部、小数部を区切った書式になります。
	 * 7,3 は、 xxxx,yyy のフォーマットで、整数部４桁、小数部３桁を意味します。
	 *
	 * @return  使用桁数
	 */
	public String getMaxlength() { return maxlength; }

	/**
	 * フィールドのデータ長を返します。
	 * 通常は、整数型の文字列とデータ長は同じですが,小数点を表すデータ長は
	 * x.y 形式の場合、x + 1 桁で表されます。
	 * 6.2 は、 xxxx.yy のフォーマットです。
	 *
	 * @return  データ長定義文字列
	 */
	public int getTotalSize() { return totalSize; }

	/**
	 * フィールドの整数部のデータ長を返します。
	 *
	 * @return  データ長定義文字列
	 */
	public int getSizeX() { return sizeX ; }

	/**
	 * フィールドの小数部のデータ長を返します。
	 *
	 * @return  データ長定義文字列
	 */
	public int getSizeY() { return sizeY ; }

	/**
	 * 文字列の表示文字数を返します。
	 *
	 * これは、テキストフィールドのサイズではなく、Renderer系の表示に使用する
	 * 文字数指定に使われます。
	 * 無指定の場合は、null が返されます。
	 *
	 * @return  表示文字数
	 */
	public String getViewLength() { return viewLength; }

	/**
	 * フィールドの入力枠サイズを返します。
	 *
	 * テキストフィールドのサイズに該当します。
	 * 何も指定しない場合は、null が返ります。
	 * その場合の、入力枠サイズは、maxlength が使用されます。
	 * ただし、桁数が大きい場合は、システム定数の HTML_COLUMNS_MAXSIZE や、
	 * HTML_VIEW_COLUMNS_MAXSIZE で指定された値が使われます。
	 * それらの値よりも、ここで取得 した fieldSize が優先されます。
	 *
	 * @og.rev 6.2.0.0 (2015/02/27) フィールドサイズ 追加(VIEW_LENGTHと分離して、役割を明確にする)
	 *
	 * @return  入力枠サイズ
	 */
	public String getFieldSize() { return fieldSize; }

	/**
	 * 表示種別を返します。
	 *
	 * @return  表示種別の文字列
	 */
	public String getRenderer() { return renderer; }

	/**
	 * 編集種別を返します。
	 *
	 * @return  編集種別
	 */
	public String getEditor() { return editor; }

	/**
	 * 文字種別を返します。
	 *
	 * @return  文字種別
	 */
	public String getDbType() { return dbType; }

	/**
	 * ラベルカラムを返します。
	 *
	 * @return  ラベルカラム
	 */
	public String getLabelColumn() { return labelClm; }

	/**
	 * コードカラムを返します。
	 *
	 * @return  コードカラム
	 */
	public String getCodeColumn() { return codeClm; }

	/**
	 * データのデフォルト値を返します。
	 *
	 * @return  データのデフォルト値
	 */
	public String getDefault() { return dataDef; }

	/**
	 * カラムのパラメータを取得します。
	 *
	 * @return	カラムパラメータ
	 */
	public String getColumnParam() { return columnPrm; }

	/**
	 * 表示用レンデラーのパラメータを取得します。
	 *
	 * @return	表示パラメータ
	 */
	public String getRendererParam() { return rendererPrm; }

	/**
	 * 編集用エディターのパラメータを取得します。
	 *
	 * @return	編集パラメータ
	 */
	public String getEditorParam() { return editorPrm; }

	/**
	 * データタイプのパラメータを取得します。
	 *
	 * @return	データタイプのパラメータ
	 */
	public String getDbTypeParam() { return dbTypePrm; }

	/**
	 * カラムロールを取得します。
	 *
	 * @return	カラムロール
	 */
	public String getRoles() { return roles; }

	/**
	 * カラムオブジェクトのロールモードを返します。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @return カラムオブジェクトのロールモード
	 */
	public RoleMode getRoleMode() { return roleMode; }

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

	/**
	 * 内部データの文字列配列を返します。
	 *
	 * @og.rev 6.2.0.0 (2015/02/27) フィールドサイズ 追加(VIEW_LENGTHと分離して、役割を明確にする)
	 *
	 * @return	内部データの文字列配列
	 */
	public String[] getColumnData() {
		String[] data = new String[DATA_SIZE];

		data[CLM			] = name		;
		data[CLS_NAME		] = className	;
		data[USE_LENGTH 	] = maxlength	;
		data[VIEW_LENGTH	] = viewLength	;
		data[FIELD_SIZE		] = fieldSize	;			// 6.2.0.0 (2015/02/27)
		data[RENDERER		] = renderer	;
		data[EDITOR 		] = editor		;
		data[DBTYPE 		] = dbType		;
		data[DATA_DEFAULT	] = dataDef		;
		data[LABEL_CLM		] = labelClm	;
		data[CODE_CLM		] = codeClm		;
		data[CLM_PARAM		] = columnPrm	;
		data[RENDERER_PARAM	] = rendererPrm	;
		data[EDITOR_PARAM	] = editorPrm	;
		data[TYPE_PARAM 	] = dbTypePrm	;
		data[ROLES			] = roles		;

		return data ;
	}
}
