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

import java.util.ArrayList;
import java.util.List;

import org.opengion.fukurou.db.DBUtil;
import org.opengion.fukurou.db.Transaction;
import org.opengion.fukurou.util.ApplicationInfo;
import org.opengion.fukurou.util.StringUtil;

/**
 * 伝送要求に対して、旧伝送DBのデータを読取します。
 *
 * 伝送定義マスタの読取対象は、以下の形式で定義する必要があります。
 *   (データコード) (送り先) (テキスト種別)   例):"3 D9 B119"
 * 処理実行後は、読み取ったヘッダーデータの状況を'2'に更新します。
 * 但し、読取パラメーターに"NOUPDATE"を指定した場合、処理後の更新は行われません。
 * また、エラーが発生した場合はヘッダーデータの状況を'9'に更新します。
 *
 * @og.group 伝送システム
 *
 * @version  5.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public class TransferRead_CB01 implements TransferRead {

	// 更新対象の通番NO(配列)
	private String[] htcnoArr = null;

	/**
	 * 伝送データを読み取ります。
	 *
	 * @param config 伝送設定オブジェクト
	 * @param tran トランザクションオブジェクト
	 *
	 * @return 読み取りしたデータ(配列)
	 * @see #getKeys()
	 */
	@Override
	public String[] read( final TransferConfig config, final Transaction tran ) {
		htcnoArr = getHtcno( config, tran );
		return getData( htcnoArr, tran );
	}

	/**
	 * 旧伝送DBを検索し、対象の通番NO(配列)を返します。
	 *
	 * @param config 伝送設定オブジェクト
	 * @param tran トランザクションオブジェクト
	 *
	 * @return 通番NO(配列)
	 */
	private String[] getHtcno( final TransferConfig config, final Transaction tran ) {
		String readObj = config.getReadObj();
		String[] obj = StringUtil.csv2Array( readObj, ' ' );
		if( obj.length < 3 ) {
			String errMsg = "読取対象は、(データコード) (送り先) (テキスト種別) の形式で指定して下さい。[READOBJ=" + readObj + "]";
			throw new RuntimeException( errMsg );
		}
		String hcdd = obj[0];
		String hto = obj[1];
		String hsyu = obj[2];
		if( hcdd == null || hcdd.length() == 0
		 || hto  == null || hto.length()  == 0
		 || hsyu == null || hsyu.length() == 0 ) {
			String errMsg = "読取対象は、(データコード) (送り先) (テキスト種別) は必須です。[READOBJ=" + readObj + "]";
			throw new RuntimeException( errMsg );
		}

		StringBuilder buf = new StringBuilder();
		buf.append( "SELECT A.HTCNO" );
		buf.append( " FROM CB01 A" );
		buf.append( " WHERE A.HCDD = '" + hcdd + "'" );
		buf.append( " AND A.HTO = '" + hto + "'" );
		buf.append( " AND A.HSYU = '" + hsyu + "'" );
		buf.append( " AND A.HCDJ = '1'" );
		buf.append( " ORDER BY A.HTC" );

		String[][] vals = DBUtil.dbExecute( buf.toString(),null,tran );
		List<String> hnoList = new ArrayList<String>();
		if( vals != null && vals.length > 0 ) {
			for( int row=0; row<vals.length; row++ ) {
				hnoList.add( vals[row][0] );
			}
		}

//		return hnoList.toArray( new String[0] );
		return hnoList.toArray( new String[hnoList.size()] );
	}

	/**
	 * 対象の通番NOに対してCB01を読み込みデータを配列で返します。
	 *
	 * @param htcnoArr 読取対象の通番NO(配列)
	 * @param tran トランザクション
	 *
	 * @return データ(配列)
	 */
	private String[] getData( final String[] htcnoArr, final Transaction tran ) {
		if( htcnoArr == null || htcnoArr.length == 0 ) { return new String[0]; }

		String htcnos = StringUtil.array2csv( htcnoArr );
		StringBuilder buf = new StringBuilder();
		buf.append( "SELECT A.HTEXT" );
		buf.append( " FROM CB01 A" );
		buf.append( " WHERE A.HCDJ = '5'" );
		buf.append( " AND A.HTCNO IN (" );
		buf.append( htcnos );
		buf.append( ") ORDER BY A.HTC, A.HTCNO" );

		String[][] vals = DBUtil.dbExecute( buf.toString(),null,tran );
		String[] rtn = new String[vals.length];
		for( int i=0; i<vals.length; i++ ) {
			rtn[i] = vals[i][0];
		}
		return rtn;
	}

	/**
	 * 更新対象の通番NO(配列)を返します。
	 *
	 * @og.rev 5.5.2.4 (2012/05/16) 配列を返す場合は、内部表現を暴露しないように、clone を返します。
	 *
	 * @return 通番NO(配列)
	 */
	@Override
	public String[] getKeys() {
//		return htcnoArr;
		String[] rtn = null ;
		if( htcnoArr != null ) { rtn = htcnoArr.clone(); }
		return rtn ;
	}

	/**
	 * 更新対象の通番NO(配列)をセットします。
	 *
	 * @og.rev 5.5.2.4 (2012/05/16) 参照の格納には、System.arraycopy を使います。
	 *
	 * @param keys 通番NO(配列)
	 */
	@Override
	public void setKeys( final String[] keys ) {
//		htcnoArr = keys;
		if( keys != null ) {
			int size = keys.length ;
			htcnoArr = new String[size];
			System.arraycopy( keys,0,htcnoArr,0,size );
		}
		else {
			htcnoArr = null;
		}
	}

	/**
	 * 読取した伝送データのヘッダーデータの状況を'2'(抜出済み)に更新します。
	 * 更新対象の通番NOについては、{@link #setKeys(String[])}で外部からセットすることもできます。
	 *
	 * @param config 伝送設定オブジェクト
	 * @param tran トランザクションオブジェクト
	 * @see #setKeys(String[])
	 */
	@Override
	public void complete( final TransferConfig config, final Transaction tran ) {
		if( htcnoArr == null || htcnoArr.length == 0 ) { return; }
		// 読取パラメーターに"NOUPDATE"が指定されている場合は、CB01の状況を更新しない
		if( "NOUPDATE".equalsIgnoreCase( config.getReadPrm() ) ) { return; }

		String htcnos = StringUtil.array2csv( htcnoArr );
		StringBuilder buf = new StringBuilder();
		buf.append( "UPDATE CB01 A" );
		buf.append( " SET A.HCDJ = '2'" );
		buf.append( " WHERE A.HCDJ = '1'" );
		buf.append( " AND A.HTCNO IN (" );
		buf.append( htcnos );
		buf.append( ")" );

		DBUtil.dbExecute( buf.toString(),null,tran );
	}

	/**
	 * 読取した伝送データのヘッダーデータの状況を'9'(エラー)に更新します。
	 * 更新対象の通番NOについては、{@link #setKeys(String[])}で外部からセットすることもできます。
	 *
	 * @param config 伝送設定オブジェクト
	 * @param appInfo DB接続情報
	 * @see #setKeys(String[])
	 */
	@Override
	public void error( final TransferConfig config, final ApplicationInfo appInfo ) {
		if( htcnoArr == null || htcnoArr.length == 0 ) { return; }

		String htcnos = StringUtil.array2csv( htcnoArr );
		StringBuilder buf = new StringBuilder();
		buf.append( "UPDATE CB01 A" );
		buf.append( " SET A.HCDJ = '9'" );
		buf.append( " WHERE A.HCDJ in ('1','2')" ); // 既に実行PGで抜出済みに更新されている可能性がある
		buf.append( " AND A.HTCNO IN (" );
		buf.append( htcnos );
		buf.append( ")" );

		DBUtil.dbExecute( buf.toString(),null,appInfo ); // エラー更新はトランザクションを分けて処理する
	}

}
