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

import org.opengion.fukurou.util.Attributes;
import org.opengion.fukurou.util.XHTMLTag;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;

import org.opengion.hayabusa.db.AbstractEditor;
import org.opengion.hayabusa.db.CellEditor;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.db.DBColumnConfig;
import org.opengion.hayabusa.resource.ResourceFactory;
import org.opengion.hayabusa.resource.ResourceManager;
import org.opengion.hayabusa.resource.LabelData;

import java.util.Locale ;

/**
 * 動的カラムのEntryカラムを編集する場合に使用するエディタークラスです。
 *
 * Editor_ENTCLM は、Editor_EntryColumn の略で、Editor_COLUMN.java を
 * 強化した形で作成します。
 * これは、引数の値をキーに、DBColumn を動的に作成する機能になります。
 *
 * Editor_COLUMN との違いは、こちらは、行ではなく、Entry形式のカラムを
 * 作成するところです。つまり、行番号は、関係ありません。
 * 通常は、カラム名__行番号 をキーとするテキストフィールドなどを
 * 出力しますが、Editor_ENTCLM は、名前そのものをキーとする
 * テキストフィールドなどを出力します。
 * あと、カラム引数(:で区切られた値)が使えます。
 * 通常は、値(Value)に、カラム名のみをセットしますが、コロン(:)で、
 * 区切ってパラメータを渡せます。
 *
 * カラム名:値:must:Length:Label:Editor:DBType:EditParam の順番です。
 *
 * コロンの数だけ分離しますが、数は少なくても良いが並び順は、必須です。
 *
 * 通常、このままでは、リソースに存在することが前提ですが、
 * 編集パラメータに、SAVE=TRUE というキーワードをセットすると、
 * 個々に作成した値を元に、ResourceManager に、動的に作成した
 * LabelData を追加する機能を持たせます。
 * この、LabelData は、通常のLabelDataLoaderのプールではなく、
 * ResourceManagerで、個別に管理されるため、特殊な方法を使わないと
 * 値を取り出すことはできません。
 * このキャッシュされたラベルを用いることで、columnCheckのエラーメッセージ
 * のラベルを動的に書き換えたラベルで表示することができます。
 *
 * さらに、編集パラメータに、QUERY=・・・・ というキーワードを
 * セットすると、そのSQL分を実行して、コードリソースを作成します。
 * こちらは、SAVE=TRUE の場合のみ実行され、コードリソースのキャッシュに
 * セットされます。
 *
 * このエディタはeventColumnに対応していません。
 *
 * カラムの表示に必要な属性は, DBColumn オブジェクト より取り出します。
 * このクラスは、DBColumn オブジェクト毎に１つ作成されます。
 * @og.group データ編集
 *
 * @og.rev 5.4.2.2 (2011/12/14) 新規追加。
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class Editor_ENTCLM extends AbstractEditor {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.5.2 (2016/05/06)" ;

	private final String	lang ;
	private final boolean	isSave ;
	private final String	codeQuery ;
	private final boolean	addNoValue ;		// 5.4.2.3 (2011/12/22)

	/**
	 * デフォルトコンストラクター。
	 * このコンストラクターで、基本オブジェクトを作成します。
	 *
	 * @og.rev 5.4.2.3 (2011/12/22) addNoValue 属性を追加します。
	 */
	public Editor_ENTCLM() {
		super();		// 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
		lang		= null;
		isSave		= false;
		codeQuery	= null;
		addNoValue	= false;		// 5.4.2.3 (2011/12/22)
	}

	/**
	 * DBColumnオブジェクトを指定したprivateコンストラクター。
	 *
	 * @og.rev 5.4.2.3 (2011/12/22) addNoValue 属性を追加します。
	 * @og.rev 6.4.4.2 (2016/04/01) nameのfinal化
	 *
	 * @param	clm	DBColumnオブジェクト
	 */
	private Editor_ENTCLM( final DBColumn clm ) {
	//	super();		// 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
		super( clm );	// 6.4.4.2 (2016/04/01) nameのfinal化
	//	name = clm.getName();		// ここでいう名前は、オリジナルなので、動的に作成するときには使用しない。
		lang = clm.getLang();
		addNoValue = clm.isAddNoValue() ;		// 5.4.2.3 (2011/12/22)

		final String orgParam = clm.getEditorParam();
		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
		if( orgParam == null ) {
			isSave	  = false;
			codeQuery = null;
		}
		else {
			final String upParam = orgParam.toUpperCase(Locale.JAPAN);
			// 編集パラメータに、SAVE=TRUE というキーワードがあるかどうかのチェック
			isSave = upParam.indexOf( "SAVE=TRUE" ) >= 0 ;

			// QUERY= のキーワードがあれば、コードリソースの検索用SQLとなる。(パラメータの残りすべて)
			final int adrs = upParam.indexOf( "QUERY=" );
			codeQuery = adrs >= 0 ? orgParam.substring( adrs+6,orgParam.length() ) : null;
		}

	}

	/**
	 * 各オブジェクトから自分のインスタンスを返します。
	 * 自分自身をキャッシュするのか、新たに作成するのかは、各サブクラスの実装に
	 * まかされます。
	 *
	 * @param	clm	DBColumnオブジェクト
	 *
	 * @return	CellEditorオブジェクト
	 * @og.rtnNotNull
	 */
	public CellEditor newInstance( final DBColumn clm ) {
		return new Editor_ENTCLM( clm );
	}

	/**
	 * データの編集用文字列を返します。
	 *
	 * 通常は、値(Value)に、カラム名のみをセットしますが、コロン(:)で、
	 * 区切ってパラメータを渡せます。
	 *
	 * カラム名:値:must:Length:Label:Editor:DBType:EditParam の順番です。
	 *
	 * コロンの数だけ分離しますが、数は少なくても良いが並び順は、必須です。
	 *
	 * @og.rev 5.4.2.3 (2011/12/22) addNoValue 属性を追加します。
	 * @og.rev 5.4.3.4 (2012/01/12) official フラグをセットします。パラメータにラベル追加
	 * @og.rev 6.4.5.2 (2016/05/06) rendAttri,editAttri は、not null にします。
	 *
	 * @param	value 入力値
	 *
	 * @return	データの表示用文字列
	 * @og.rtnNotNull
	 */
	@Override
	public String getValue( final String value ) {
		// 先頭文字が コロン(:)の場合は、カラム名が省略されているので、エラー
		if( value == null || value.isEmpty() || value.charAt(0) == ':'  ) {		// or判定なので、StringUtil.startsChar は使えません。
			final String errMsg = "指定のカラムの値が設定されていません。"
						+ CR
						+ "  name=[" + name + "]"
						+ "  value=[" + value + "]";
			throw new HybsSystemException( errMsg );
		}

		final ResourceManager resource = ResourceFactory.newInstance( lang ) ;
		final String[] vals = value.split( ":" , 8 );			// ８分割します。

		final String key    = vals[0];									// 配列０は、カラム名
		final String val    = vals.length >= 2 ? vals[1] : null;		// 配列１は、値
		final String must   = vals.length >= 3 ? vals[2] : null;		// 配列２は、must
		final String len    = vals.length >= 4 ? vals[3] : null;		// 配列３は、Length
		final String lbl    = vals.length >= 5 ? vals[4] : null;		// 配列４は、Label
		final String edit   = vals.length >= 6 ? vals[5] : null;		// 配列５は、Editor
		final String dbtype = vals.length >= 7 ? vals[6] : null;		// 配列６は、DBType
		final String edPrm  = vals.length >= 8 ? vals[7] : null;		// 配列７は、EditParam

		final boolean isMust = "1".equalsIgnoreCase( must ) || "true".equalsIgnoreCase( must ) ;	// mustが設定されているかどうか
		// キーに対応するDBColumnがなければ、null が返される。
		DBColumn dbColumn = resource.getDBColumn( key );

		// DBColumnConfig で値のセット
		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
		final DBColumnConfig config = (dbColumn == null) ? new DBColumnConfig( key ) : dbColumn.getConfig();

		// 5.4.3.4 (2012/01/12) official フラグをセットします。
		config.setOfficial( true );

		// 5.4.2.3 (2011/12/22) addNoValue 属性を追加
		config.setAddNoValue( addNoValue );

		String mstChStr = "";
		if( isMust ) {			// 配列２は、must
			final Attributes editAttri = config.getEditorAttributes();
			editAttri.add( "class","must" );
			config.setEditorAttributes( editAttri );

			// must 指定の場合に、チェック用のhidden を作成します。
			mstChStr = XHTMLTag.hidden( HybsSystem.MUST_KEY + "must", key );
		}
		if( len != null && !len.isEmpty() ) {			// 配列３は、Length
			config.setMaxlength( len );
		}
		// 5.4.3.4 (2012/01/12) パラメータにラベル追加
		if( lbl != null && !lbl.isEmpty() ) {			// 配列４は、Label
			final LabelData labelData = resource.getLabelData( lbl ) ;
			config.setLabelData( labelData );
		}
		if( edit != null && !edit.isEmpty() ) {			// 配列５は、Editor
			config.setEditor( edit );
		}
		if( dbtype != null && !dbtype.isEmpty() ) {		// 配列６は、DBType
			config.setDbType( dbtype );
		}
		if( edPrm != null && !edPrm.isEmpty() ) {		// 配列７は、EditParam
			config.setEditorParam( edPrm );
		}

		// 動的なコードリソースの作成
		if( codeQuery != null && isSave ) {
			config.setCodeData( resource.getCodeData( key,codeQuery ) );
		}

		dbColumn = new DBColumn( config );
		if( isSave ) {	// isSave が true で、セーブする。
			resource.setDBColumn( key,dbColumn );
		}

		// val と must は、キャッシュされた DBColumn と別に、毎回異なるケースを想定します。
		return dbColumn.getEditorValue( val ) + mstChStr;
	}

	/**
	 * このクラスでは、Entry形式の編集用の文字列を作成します。
	 * よって、行番号を付加しません。
	 *
	 * @param	row   行番号
	 * @param	value 入力値
	 *
	 * @return	データ表示/編集用の文字列
	 * @og.rtnNotNull
	 */
	@Override
	public String getValue( final int row,final String value ) {
		return getValue( value );
	}
}
