/*
 * 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.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

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

/**
 * 伝送要求に対して旧伝送DB(CB01)に登録を行います。
 *
 * 旧伝送DB登録時のデータコード、送り先、テキスト種別は、伝送定義マスタの実行対象で指定します。
 * 具体的には以下の形式で定義します。
 *   (データコード) (送り先) (テキスト種別) [(レコード長)] 例):"3 D9 B119 [400]"
 * 4番目のパラメーターであるレコード長は任意です。レコード長が指定されない場合、
 * デフォルト値として 400 が定義されます。
 * 
 * CB01の各項目のセット基準は以下の通りです。
 *
 *						ヘッダーデータ		明細データ
 *  ---------------------------------------------------
 *  HCDJ(状況)			1					5
 *  HCDD(カードコード)	[実行対象]			[実行対象]
 *  HTO(送り先)			[実行対象]			[実行対象]
 *  HSYU(テキスト種別)	[実行対象]			[実行対象]
 *  HLDAY(登録日)		システム日付		システム日付
 *  HLTIME(登録時間)	システム日付		システム日付
 *  HDPDAY(削除日)		システム日付+14日	システム日付+14日
 *  HFROM(送り元)		[システムリソース]	[システムリソース]	※TRANSFER_HOST_CODEの値
 *  HTCNO(通番NO)		CB010001.NEXTVAL	CB010001.NEXTVAL
 *  HTC(通番)			CB010002.NEXTVAL	CB010002.NEXTVAL
 *  HTEXT(データ)		送り先+登録件数		データ
 *  DYUNYOU(運用日)		CJ03>DYUNYOU		CJ03>DYUNYOU
 *  RECL(レコード長)	[実行対象]			[実行対象]			※初期値400
 *  
 *  この_CB01を利用する場合CB01テーブル以外に次のテーブル及びシーケンスが必要です
 *  テーブル：CB02
 *  シーケンス：CB010001,CB010002
 *
 * @og.rev 5.4.4.1 コメント修正
 * @og.group 伝送システム
 *
 * @version  5.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public class TransferExec_CB01 implements TransferExec {

	// 旧伝送DB(CB01)登録
	private static final String CB01_INSERT = 
		"INSERT INTO CB01 ("
		+ "HCDJ,HCDD,HTO,HSYU,HLDAY,HLTIME,HDPDAY,HTEXT1,HTEXT2"
		+ ",HPASS,HFROM,HNAME,HTCNO,HTC,HTEXT,DYUNYOU,RECL"
		+ ") VALUES ("
		+ "?,?,?,?,?,?,?,null,null"
		+ ",null,?,null,?,?,?,?,?"
		+ ")";

	// 通番NO取得
	private static final String HTCNO_GET = "SELECT CB010001.NEXTVAL FROM DUAL";

	// 通番取得
	private static final String HTC_GET = "SELECT CB010002.NEXTVAL FROM DUAL";

	// 運用日取得
	private static final String DYUNYOU_GET = "SELECT DYUNYOU FROM CJ03";

	// 削除日付基準日数
	private static final int HDAY = 14;

	// レコード長の初期値
	private static final String DEFAULT_RECL = "400";

	/**
	 * CB01に登録します。
	 * 
	 * @param vals 伝送データ(配列)
	 * @param config 伝送設定オブジェクト
	 * @param tran トランザクションオブジェクト
	 */
	@Override
	public void execute( final String[] vals, final TransferConfig config, final Transaction tran ) {
		if( vals == null || vals.length == 0 ) { return; }

		String execObj = config.getExecObj();
		String[] obj = StringUtil.csv2Array( execObj, ' ' );
		if( obj.length < 3 ) {
			String errMsg = "実行対象は、(データコード) (送り先) (テキスト種別) の形式で指定して下さい。"
							+ "EXECOBJ=[" + execObj + "]";
			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 = "実行対象は、(データコード) (送り先) (テキスト種別) は必須です。"
							+ "EXECOBJ=[" + execObj + "]";
			throw new RuntimeException( errMsg );
		}
		String recl = ( obj.length > 3 ) ? obj[3] : DEFAULT_RECL;

		String execDbid = config.getExecDbid();

		String htcno = getHtcno( tran, execDbid );
		String hlday = getDate( "yyyyMMdd" );
		String hltime = getDate( "HHmm" );
		String hdpday = getDate( hlday, HDAY );

		// ヘッダー行追加
		String[] headerArgs = new String[] {
				"1",								// HCDJ
				hcdd ,								// HCDD
				hto,								// HTO
				hsyu,								// HSYU
				hlday.substring( 2 ),				// HLDAY
				hltime,								// HLTIME
				hdpday.substring( 2 ),				// HDPDAY
				config.getHfrom(),					// HFROM
				htcno,								// HTCNO
				getHtc( tran, execDbid ),			// HTC
				getHeaderText( hto, vals.length ),	// HTEXT
				getDyunyou( tran, execDbid ),		// DYUNYOU
				recl								// RECL
			};
		DBUtil.dbExecute( CB01_INSERT, headerArgs, tran, execDbid );

		// 明細行追加
		for( String text : vals ) {
			String[] dataArgs = new String[] {
					"5",								// HCDJ
					hcdd ,								// HCDD
					hto,								// HTO
					hsyu,								// HSYU
					hlday.substring( 2 ),				// HLDAY
					hltime,								// HLTIME
					hdpday.substring( 2 ),				// HDPDAY
					config.getHfrom(),					// HFROM
					htcno,								// HTCNO
					getHtc( tran, execDbid ),			// HTC
					text,								// HTEXT
					getDyunyou( tran, execDbid ),		// DYUNYOU
					recl								// RECL
				};
			DBUtil.dbExecute( CB01_INSERT, dataArgs, tran, execDbid );
		}
	}

	/**
	 * ヘッダーデータのテキストを返します。
	 * (CSP00007と同じ仕様で実装)
	 * 
	 * @param hto 送り先
	 * @param cnt 登録件数
	 * @return ヘッダーデータのテキスト
	 */
	private static String getHeaderText( final String hto, final int cnt ) {
		return StringUtil.stringFill( hto, 8, "UTF-8" )
						+ " 登録件数 = " + String.valueOf( cnt );
	}

	/**
	 * 通番NOを採番します。
	 * (CSP00007と同じ仕様で実装)
	 * 
	 * @param tran トランザクションオブジェクト
	 * @param execDbid 実行接続先DBID
	 * @return 通番NO
	 */
	private static String getHtcno( final Transaction tran, final String execDbid ) {
		String[][] rtn = DBUtil.dbExecute( HTCNO_GET, new String[0], tran, execDbid );
		return rtn[0][0];
	}

	/**
	 * 通番を採番します。
	 * (CSP00007と同じ仕様で実装)
	 * 
	 * @param tran トランザクションオブジェクト
	 * @param execDbid 実行接続先DBID
	 * @return 通番
	 */
	private static String getHtc( final Transaction tran, final String execDbid ) {
		String[][] rtn = DBUtil.dbExecute( HTC_GET, new String[0], tran, execDbid );
		return rtn[0][0];
	}

	/**
	 * 運用日を取得します。(CJ03>運用日)
	 * (CSP00007と同じ仕様で実装)
	 * 
	 * @param tran トランザクションオブジェクト
	 * @param execDbid 実行接続先DBID
	 * @return 運用日
	 */
	private static String getDyunyou( final Transaction tran, final String execDbid ) {
		String[][] rtn = DBUtil.dbExecute( DYUNYOU_GET, new String[0], tran, execDbid );
		return rtn[0][0];
	}

	/**
	 * 現在日付、時刻をフォーマットを指定して、所得します。
	 * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
	 *
	 * @param	form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss.SSS" )
	 * @return	現在日付、時刻
	 */
	private static String getDate( final String form ) {
		DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN );
		return formatter.format(new Date());
	}

	/**
	 * 指定の引数の日付け文字列（YYYYMMDDHHMMSS）より、カレンダオブジェクトを作成します。
	 * 引数は、YYYYMMDD の８文字か、YYYYMMDDHHMMSS の１４文字のどちらかです。
	 *
	 * @param value 日付け文字列（YYYYMMDD または YYYYMMDDHHMMSS）
	 * @return	String カレンダオブジェクト
	 */
	private static Calendar getCalendar( final String value ) {
		if ( value == null || ( value.length() != 8 && value.length() != 14 ) ) {
			String errMsg = "引数は、YYYYMMDD または YYYYMMDDHHMMSS 形式の日付け文字列のみです。"
					+ " value=[" + value + "]" ;
			throw new RuntimeException( errMsg );
		}

		Calendar cal = Calendar.getInstance();
		cal.clear();

		int hour=0,minute=0,second=0;

		int year   = Integer.parseInt( value.substring( 0,4 ) );
		int month  = Integer.parseInt( value.substring( 4,6 ) ) - 1;
		int date   = Integer.parseInt( value.substring( 6,8 ) );

		if( value.length() == 14 ) {
			hour   = Integer.parseInt( value.substring( 8,10 ) );
			minute = Integer.parseInt( value.substring( 10,12 ) );
			second = Integer.parseInt( value.substring( 12,14 ) );
		}

		cal.set( year,month,date,hour,minute,second );

		return cal;
	}

	/**
	 * 指定の引数の日付け文字列（YYYYMMDD）より、差分の日付を計算して返します。
	 * 引数は、YYYYMMDD と 差分の日数。
	 *
	 * @param baseDate 日付け文字列（YYYYMMDD）
	 * @param diff     差分の日数（過去の日付[+]、将来の日付は[-]）
	 * @return	String 結果の日付（YYYYMMDD）
	 */
	private static String getDate( final String baseDate,final int diff ) {
		if ( baseDate == null || ( baseDate.length() != 8 ) ) {
			String errMsg = "引数 baseDate は、YYYYMMDD 形式の日付け文字列のみです。"
					+ " baseDate=[" + baseDate + "]" ;
			throw new RuntimeException( errMsg );
		}

		Calendar cal = getCalendar( baseDate );
		cal.add( Calendar.DATE,diff );
		String rtn = null;

		int calYear		= cal.get( Calendar.YEAR );
		int calMonth	= cal.get( Calendar.MONTH ) + 1;
		int calDay		= cal.get( Calendar.DATE );
		rtn = String.valueOf( calYear );
		if( calMonth < 10 ) {
			rtn = rtn + "0" + calMonth;
		}
		else {
			rtn = rtn + calMonth;
		}
		if( calDay < 10 ) {
			rtn = rtn + "0" + calDay;
		}
		else {
			rtn = rtn + calDay;
		}
		return rtn;
	}

}
