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

import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.AbstractTableFilter;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.ErrorMessage;
import org.opengion.fukurou.util.ErrMsg;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.resource.ResourceFactory;
import org.opengion.hayabusa.resource.ResourceManager;
// import static org.opengion.fukurou.system.HybsConst.CR;						// 8.0.0.0 (2021/07/31) Delete

/**
 * TableFilter_JUDG は、TableFilter インターフェースを継承した、DBTableModel 処理用の
 * 実装クラスです。
 *
 * 必要なカラムから、判定結果(JUDG) と 判定理由(RIYU) を設定します。
 * これは、GG10 の発生日(DY_HATU),登録ｷｰ(SET_KEY),設定ｸﾞﾙｰﾌﾟ(SET_GRP),ﾄｰｸﾝ(TOKEN) の
 * ﾚｺｰﾄﾞを処理して、判定結果を設定します。
 *
 * GG10 書き込むﾃｰﾌﾞﾙ (必須ｶﾗﾑ)
 *   値ﾃﾞｰﾀ(VAL)			値の設定(存在、上限、下限判定)
 *   判定結果(JUDG)			0:未決 1:不要 2:任意 3:合格 4:保留 5:警告 6:必須 7:不合格
 *   判定理由(RIYU)			上限、下限で判定した結果が入っている。titleに入れてﾎﾟｯﾌﾟｱｯﾌﾟさせる
 *
 * GG01 ﾄｰｸﾝﾏｽﾀ (GG02がnullの時)
 *   ﾃﾞｰﾀ型(DATA_TYPE)		EDITORを決定
 *
 * 	GG02 雛形設定ﾏｽﾀ
 *   登録方法(CDREC)		0:未決 1:不要 2:任意 4:保留 6:必須
 *   異常下限(E_MIN)		異常値の下限判定に使用
 *   警告下限(W_MIN)		警告値の下限判定に使用
 *   警告上限(W_MAX)		警告値の上限判定に使用
 *   異常上限(E_MAX)		異常値の上限判定に使用
 *
 * @og.formSample
 * ●形式：
 *      ① &lt;og:tableFilter classId="JUDG" /&gt;
 *
 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加
 *
 * @version  0.9.0  2000/10/17
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.1,
 */
public class TableFilter_JUDG extends AbstractTableFilter {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "8.0.0.0 (2021/08/20)" ;

	// 8.0.0.0 (2021/07/31) ﾛｰｶﾙ変数に置き換え可能
//	private int noVal		= -1;
//	private int noJudg		= -1;
//	private int noRiyu		= -1;

//	private int noType		= -1;

//	private int noCdrec		= -1;
//	private int noEmin		= -1;
//	private int noWmin		= -1;
//	private int noWmax		= -1;
//	private int noEmax		= -1;

	private DBTableModel table ;

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更。
	 */
	public TableFilter_JUDG() { super(); }

	/**
	 * DBTableModel処理を実行します。
	 *
	 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加
	 * @og.rev 7.4.2.3 (2021/06/09) NUMBERやDECIMALﾌｫｰﾏｯﾄされているので書き戻す。
	 *
	 * @return 処理結果のDBTableModel
	 */
	public DBTableModel execute() {
		table = getDBTableModel();
		if( table == null ) { return table; }				// 6.4.0.5 (2016/01/09)

		final ResourceManager resource = ResourceFactory.newInstance( "ja" ) ;

		final  int noVal	= table.getColumnNo( "VAL"				);	// 値ﾃﾞｰﾀ(必須)
		final  int noJudg	= table.getColumnNo( "JUDG"				);	// 判定結果(必須)
		final  int noRiyu	= table.getColumnNo( "RIYU"				);	// 判定理由(必須)
		final  int noType	= table.getColumnNo( "DATA_TYPE", false );	//
		final  int noCdrec	= table.getColumnNo( "CDREC"	, false );	//
		final  int noEmin	= table.getColumnNo( "E_MIN"	, false );	//
		final  int noWmin	= table.getColumnNo( "W_MIN"	, false );	//
		final  int noWmax	= table.getColumnNo( "W_MAX"	, false );	//
		final  int noEmax	= table.getColumnNo( "E_MAX"	, false );	//

		final int rowCnt = table.getRowCount();
		for( int row=0; row<rowCnt; row++ ) {
			final String[] data  = table.getValues( row );

			final String val     = data[noVal] ;
			final String orgJudg = data[noJudg];					// 現在の判定結果をｷｰﾌﾟ(4:保留対応)
			final String cdrec   = rowData( row,noCdrec ,"0" );		// 登録方法 0:未決 1:不要 2:任意 4:保留 6:必須
			// ﾃﾞｰﾀが未設定の場合か、1:不要 2:任意 の場合は、登録方法(CDREC) をそのままセットする。
			if( val== null || val.isEmpty() || "1".equals( cdrec ) || "2".equals( cdrec ) ) {
				data[noJudg] = cdrec;
			}
			else {
				// 判定結果(JUDG) 0:未決 1:不要 2:任意 3:合格 4:保留 5:警告 6:必須 7:不合格
				final String dbType= rowData( row,noType,"TP_TEXT" );		// DBﾀｲﾌﾟ 未指定時は、TP_TEXT:ﾃｷｽﾄ
				if( "TP_ON".equals( dbType ) ) {							// TP_ON : 0:未決 1:OK 2:NG (3:保留)
					if(      "1".equals( val ) ){ data[noJudg] = "3"; }		// 3:合格
					else if( "0".equals( val ) ){ data[noJudg] = "0"; }		// 0:未決
					else if( "3".equals( val ) ){ data[noJudg] = "4"; }		// (3:保留) は使われていないが、あれば、4:保留
					else						{ data[noJudg] = "7"; }		// 7:不合格
				}
				else if( "TP_CHECK".equals( dbType ) ) {					// TP_CHECK : 1:ﾁｪｯｸ 0:未
					if(      "1".equals( val ) )	{ data[noJudg] = "3"; }	// 3:合格
		//			else if( "6".equals( cdrec ) )	{ data[noJudg] = "6"; }	// 合格以外で、登録方法が 6:必須 の場合は、6:必須 をｾｯﾄ
					else						{ data[noJudg] = cdrec; }	// 合格以外は、登録方法(CDREC) をそのままセット
				}
				else if( "TP_INT".equals( dbType ) || "TP_REAL".equals( dbType ) ) {
					final double emin = rowData( row,noEmin,Double.NEGATIVE_INFINITY );		// 異常下限(E_MIN)
					final double wmin = rowData( row,noWmin,Double.NEGATIVE_INFINITY );		// 警告下限(W_MIN)
					final double wmax = rowData( row,noWmax,Double.POSITIVE_INFINITY );		// 警告上限(W_MAX)
					final double emax = rowData( row,noEmax,Double.POSITIVE_INFINITY );		// 異常上限(E_MAX)

					try {
						final String numVal = StringUtil.deleteChar( val,',' );				// 7.4.2.3 (2021/06/09) NUMBERやDECIMALﾌｫｰﾏｯﾄされているので。
//						final double wval = Double.parseDouble( val );		// DBﾀｲﾌﾟが、TP_INTかTP_REALなので数値変換出来る
						final double wval = Double.parseDouble( numVal );	// DBﾀｲﾌﾟが、TP_INTかTP_REALなので数値変換出来る

						// 厳しい方からﾁｪｯｸする。
						if( emin > wval ) {			// 異常下限(E_MIN)より小さい
							data[noJudg] = "7";		// 7:不合格
							data[noRiyu] = String.format( "下限値(%.2f)異常 [ ＞ %.2f ]" ,emin,wval );
						}
						else if( emax < wval ) {	// 異常上限(E_MAX)より大きい
							data[noJudg] = "7";		// 7:不合格
							data[noRiyu] = String.format( "上限値(%.2f)異常 [ ＜ %.2f ]" ,emax,wval );
						}
						else if( wmin > wval ) {	// 警告下限(W_MIN)より小さい
							data[noJudg] = "5";		// 5:警告
							data[noRiyu] = String.format( "下限値(%.2f)警告 [ ＞ %.2f ]" ,wmin,wval );
						}
						else if( wmax < wval ) {	// 警告上限(W_MAX)より大きい
							data[noJudg] = "5";		// 5:警告
							data[noRiyu] = String.format( "上限値(%.2f)警告 [ ＜ %.2f ]" ,wmax,wval );
						}
						else {
							data[noJudg] = "3";		// 3:合格
							data[noRiyu] = "";		// 判定理由のｸﾘｱ
						}

						data[noVal] = numVal ;		// 7.4.2.3 (2021/06/09) NUMBERやDECIMALﾌｫｰﾏｯﾄされているので書き戻す。
					}
					catch( final NumberFormatException ex ) {
						data[noJudg] = "7";			// 7:不合格
						data[noRiyu] = "数値変換ｴﾗｰ " + val ;
					}
				}
				// TP_ON,TP_CHECK,TP_INT,TP_REAL 以外はDBTyleで値のﾁｪｯｸを行う。
				else {
					final DBColumn clm = resource.makeDBColumn( dbType );

					try {
						data[noVal] = clm.valueSet( val ) ;		// 7.4.2.3 (2021/06/09) 実登録データを作成して、書き戻す。
					}
					catch( RuntimeException ex ) {
						System.err.println( ex.getMessage() );	// 8.0.0.0 (2021/07/31)
//						;	// #valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
					}

					// エラーﾁｪｯｸ。 正常時は null
					final ErrorMessage errMsg = clm.valueCheck( val,false );			// 厳密にチェックしない
					if( errMsg == null || errMsg.isOK() ) {
						data[noJudg] = "3";		// 3:合格
						data[noRiyu] = "";		// 判定理由のｸﾘｱ
					}
					else {
						final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
										.append( "<div class='small'>" );

						for( final ErrMsg err : errMsg.toArray() ) {
							buf.append( resource.getShortErrorMsg( err ) );
						}
						data[noRiyu] = buf.append( "</div>" ).toString();

						if( errMsg.getKekka() == ErrorMessage.WARNING ) {
							data[noJudg] = "5";		// 5:警告
						}
						else {						// errMsg.getKekka() >= ErrorMessage.NG だが、警告以外はｴﾗｰにします。
							data[noJudg] = "7";		// 7:不合格
						}
					}
				}
			}

			// ｵﾘｼﾞﾅﾙの判定結果が、4:保留 で、5:警告か7:不合格 の場合は、4:保留 のままにしておく。
			if( "4".equals( orgJudg ) && ( "5".equals( data[noJudg] ) || "7".equals( data[noJudg] ) ) ) {
				data[noJudg] = "4";		// 4:保留
			}
		}

		return table;
	}

	/**
	 * DBTableModelから、指定行-列のデータを取得します。
	 *
	 * 列番号がマイナスの場合は、ｶﾗﾑが存在していないため、初期値を返します。
	 *
	 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加
	 * @og.rev 8.0.0.0 (2021/08/20) spotbugs:Bug kind and pattern: UwF - UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR
	 *
	 * @param	row 行
	 * @param	col 列
	 * @param	defVal 初期値(文字列)
	 *
	 * @return 指定行-列のデータ(文字列)
	 */
	private String rowData( final int row , final int col , final String defVal ) {
		String rtn = defVal ;
//		if( col >= 0 ) {
		if( col >= 0 && table != null ) {		// 8.0.0.0 (2021/08/20) spotbugs
			final String val = table.getValue( row,col );
			if( val != null && !val.isEmpty()) {
				rtn = val ;
			}
		}
		return rtn ;
	}

	/**
	 * DBTableModelから、指定行-列のデータを取得します。
	 *
	 * 列番号がマイナスの場合は、ｶﾗﾑが存在していないため、初期値を返します。
	 *
	 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加
	 * @og.rev 8.0.0.0 (2021/08/20) spotbugs:Bug kind and pattern: UwF - UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR
	 *
	 * @param	row 行
	 * @param	col 列
	 * @param	defVal 初期値(数値)
	 *
	 * @return 指定行-列のデータ(数値)
	 */
	private double rowData( final int row , final int col , final double defVal ) {
		double rtn = defVal ;
		if( col >= 0 && table != null ) {		// 8.0.0.0 (2021/08/20) spotbugs
			final String val = table.getValue( row,col );
			if( val != null && !val.isEmpty()) {
				try {
					rtn = Double.parseDouble( val ) ;
				}
				catch( final NumberFormatException ex ) {
					final String errMsg = "数値項目の数値変換ｴﾗｰ　行=" + row + " , 列=" + col + " , 値=" + val ;
					throw new HybsSystemException( errMsg,ex );
				}
			}
		}
		return rtn ;

//		final String val = col < 0 ? null : table.getValue( row,col ) ;
//
//		try {
//			return val == null || val.isEmpty() ? defVal : Double.parseDouble( val );
//		}
//		catch( final NumberFormatException ex ) {
//			final String errMsg = "数値項目の数値変換ｴﾗｰ　行=" + row + " , 列=" + col + " , 値=" + val ;
//			throw new HybsSystemException( errMsg,ex );
//		}
	}
}
