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

import java.io.PrintWriter;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.opengion.fukurou.system.HybsConst ;		// 6.1.0.0 (2014/12/26)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.HybsEntry;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBColumn;

/**
 * 区切り文字指定(初期値:タブ)ゼロカンマファイルの書き出しクラスです。
 *
 * ラベル，名前，データの出力部のみオーバーライドすれば，各種出力フォーマットに合わせた
 * サブクラスを実現する事が可能です。
 * ゼロカンマファイルとは、EXCELのゼロサプレス対策として、頭ゼロの文字型データを出力する
 * 時に、先頭にカンマ(')を付けて、ゼロが削除(見えなくなる)現象を抑止しているファイルです。
 *
 * このクラスは,可変長タブ区切り文字ファイルの出力機能を実現しています。
 *
 * @og.group ファイル出力
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public abstract class AbstractTableWriter implements TableWriter {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.2.0 (2016/01/29)" ;

	/** システムの改行コードを設定します。*/
	protected static final String CR		 = HybsConst.CR;			// 6.1.0.0 (2014/12/26) refactoring
	/** StringBilderなどの初期値を設定します。	{@value} */
	protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE;	// 6.1.0.0 (2014/12/26) refactoring

	/** dbType の簡易的な設定	{@value} */
	public static final int STRING  = 0;
	/** dbType の簡易的な設定	{@value} */
	public static final int NVAR    = 1;
	/** dbType の簡易的な設定	{@value} */
	public static final int NUMBER  = 2;

	protected int 	numberOfColumns		= -1;		// 4.0.0 (2005/01/31) 出力対象のカラム数
	protected DBTableModel	table 		;
	protected DBColumn[]	dbColumn	;			// table に対するカラムオブジェクト(キャッシュ)
	protected int[]			clmNo		;			// 出力対象のカラム番号配列
	protected int[]			dbType		;			// 5.1.6.0 (2010/05/01) dbType の簡易的な設定
	protected boolean[]		isKeyLbl	;			// 6.2.3.0 (2015/05/01) KeyLabel出力

	private String	separator		= TAB_SEPARATOR;	// 項目区切り文字
	private String	headerSequence	= HybsSystem.sys( "WRITER_HEADER_SEQUENCE" ) ;
	private boolean append			;				// 3.5.4.2 (2003/12/15)
	private String	lang			;
	private String	columns			;				// 4.0.0 (2005/11/30) 外部指定のカラム名
	// 6.1.0.0 (2014/12/26) 書き込み対象外のカラム列を、外部(タグ)より指定する。
	private String	omitNames		;				// 6.1.0.0 (2014/12/26)
	private String	encode			;				// 3.5.4.5 (2004/01/23) エンコード文字列指定

	private boolean	useNumber		= true;			// 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	private boolean	useRenderer		;				// 5.2.1.0 (2010/10/01)

	private boolean	  useDebug		;				// 6.1.0.0 (2014/12/26) デバッグ情報の出力するかどうか

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	protected AbstractTableWriter() {
		super();		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
	}

	/**
	 * DBTableModel から 各形式のデータを作成して,PrintWriter に書き出します。
	 * このメソッドは、EXCEL 書き出し時に使用します。
	 *
	 * @see #isExcel()
	 */
	public abstract void writeDBTable();

	/**
	 * DBTableModel から データを作成して,PrintWriter に書き出します。
	 *
	 * @param	writer PrintWriterオブジェクト
	 */
	public abstract void writeDBTable( final PrintWriter writer );

	/**
	 * numberOfColumns と DBColumn を初期化します。
	 * 内部的に、DBTableModel、lang , columns を使用して、
	 * numberOfColumns 、dbColumn、clmNo、dbType の値を初期化します。
	 * カラムが１項目もない場合、言語(lnag)が未指定、DBTableModelが未指定(null)
	 * の場合は、false を返します。その場合は、以下の処理は正常に行えません。
	 * データが０件の場合は、処理を行います。通常、ヘッダーのみのファイルを
	 * 作成することになります。(これを雛形として、取込データを登録する事が可能)
	 *
	 * 6.0.1.2 (2014/08/08)
	 *  clmNo 配列に、-1 がセットされた場合、DBTableModel に存在しないカラムとして
	 *  そのカラム列は、書き込みしません。,,,, などを指定する事で、カラムを
	 *  飛ばして書き込むことが可能です。
	 *  refFileURL、refFilename、refSheetName とともに使用すれば、ある程度の
	 *  レイアウト設定が可能です。
	 *
	 * @og.rev 4.0.0.0 (2005/12/31) 外部指定のカラム名を使用
	 * @og.rev 5.1.6.0 (2010/05/01) DbType の初期値を設定
	 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
	 * @og.rev 6.0.2.0 (2014/09/19) EXCEL新機能対応(２回呼ばれない様にする)
	 * @og.rev 6.1.0.0 (2014/12/26) omitNames 属性を追加
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 *
	 * @return	初期化成功：true / 失敗：false
	 */
	protected boolean createDBColumn() {
		if( numberOfColumns >= 0 ) { return true; }		// 6.0.2.0 (2014/09/19) EXCEL新機能対応(２回呼ばれない様にする)

		boolean rtnFlag = false;
		if( lang != null && table != null ) {
			// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
			if( columns == null ) {
				numberOfColumns = table.getColumnCount();
				clmNo = new int[numberOfColumns];
				for( int i=0; i<numberOfColumns; i++ ) {
					clmNo[i] = i;
				}
			}
			else {
//			if( columns != null ) {
				final String[] clms = StringUtil.csv2Array( columns );
				numberOfColumns = clms.length;
				clmNo = new int[numberOfColumns];
				for( int i=0; i<numberOfColumns; i++ ) {
					final int no = table.getColumnNo( clms[i],false );	// 6.0.1.2 (2014/08/08) カラム飛ばし
					clmNo[i] = no;
				}
			}
//			else {
//				numberOfColumns = table.getColumnCount();
//				clmNo = new int[numberOfColumns];
//				for( int i=0; i<numberOfColumns; i++ ) {
//					clmNo[i] = i;
//				}
//			}

			// 6.1.0.0 (2014/12/26) 書き込み対象外のカラム列を、外部(タグ)より指定する。(omitNames属性)
			if( omitNames != null ) {
				final String[] omit = StringUtil.csv2Array( omitNames );
				for( int j=0; j<omit.length; j++ ) {
					// omitNames は、カラム飛ばしの機能を利用
					final int no = table.getColumnNo( omit[j],false );
					if( no >= 0 ) {
						for( int i=0; i<numberOfColumns; i++ ) {
							if( clmNo[i] == no ) { clmNo[i] = -1 ; break; }		// omitカラムは、-1 を設定する。
						}
					}
				}
			}

			dbColumn = table.getDBColumns();
			rtnFlag  = numberOfColumns > 0 ;	// カラムが１項目以上あれば成功

			// 5.1.6.0 (2010/05/01) DbType の初期値を設定する。
			dbType   = new int[numberOfColumns];
			isKeyLbl = new boolean[numberOfColumns];		// 6.2.3.0 (2015/05/01) KeyLabel出力
			for( int i=0; i<numberOfColumns; i++ ) {
				final int clm = clmNo[i];					// 6.2.3.0 (2015/05/01) 
				// 6.0.1.2 (2014/08/08) カラム飛ばし の場合は、clmNo[i] には、-1 が設定されている。
				if( clm < 0 ) { continue; }

				final String type = dbColumn[clm].getDbType();
				if( "NVAR".equals( type ) ) {
					dbType[i] = NVAR;
				}
				else if( "S9".equals( type ) || "R".equals( type )  ) {
					dbType[i] = NUMBER;
				}
				else {
					dbType[i] = STRING;
				}

				// 6.2.3.0 (2015/05/01) KeyLabel出力
				isKeyLbl[i] = dbColumn[clm].isWriteKeyLabel();		// 6.2.3.0 (2015/05/01) KeyLabel出力
			}
		}
		return rtnFlag;
	}

	/**
	 * PrintWriter に DBTableModelのヘッダー情報を書き込みます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 *
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeHeader( final PrintWriter writer ) {
		// ここでは処理を行いません。
	}

	/**
	 * PrintWriter に DBTableModelのラベル情報を書き込みます。
	 * 第一カラム目は、ラベル情報を示す "#Label" を書き込みます。
	 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	 * @og.rev 4.0.0.0 (2005/12/31) 外部指定のカラム名を使用
	 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 * @og.rev 6.2.4.2 (2015/05/29) StringUtil#tagCut(String) をラベルに適用します。
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeLabel( final DBTableModel table,final PrintWriter writer ) {
		if( useNumber ) {
			writer.print( "#Label" );
			writer.print( separator );
		}
		else {
			writer.print( "#" );
		}

		for( int i=0; i<numberOfColumns; i++ ) {
			if( i != 0 ) { writer.print( separator ); }
			final int clm = clmNo[i];
			if( clm < 0 ) { continue; }			// 6.0.1.2 (2014/08/08) カラム飛ばし
			final String val = StringUtil.tagCut( dbColumn[clm].getLabel() );		// 6.2.4.2 (2015/05/29)
			writer.print( val );
			// keyLabelの場合は、後ろのカラムのラベルを付けません。
			if( isKeyLbl[i] ) { writer.print( separator ); }	// 6.2.3.0 (2015/05/01) writeKeyLabel 属性
		}
		writer.println();
	}

	/**
	 * PrintWriter に DBTableModelの項目名情報を書き込みます。
	 * 第一カラム目は、項目名情報を示す "#Name" を書き込みます。
	 * useNumber=fale の場合は、最初のカラム名の先頭に、# が書き込まれます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeName( final DBTableModel table,final PrintWriter writer ) {
		if( useNumber ) {
			writer.print( "#Name" );
			writer.print( separator );
		}
		else {
			writer.print( "#" );
		}

		for( int i=0; i<numberOfColumns; i++ ) {
			if( i != 0 ) { writer.print( separator ); }
			final int clm = clmNo[i];
			if( clm < 0 ) { continue; }			// 6.0.1.2 (2014/08/08) カラム飛ばし
			writer.print( table.getColumnName(clm) );
			// keyLabelの場合は、後ろのカラムの名前を付けません。
			if( isKeyLbl[i] ) { writer.print( separator ); }	// 6.2.3.0 (2015/05/01) writeKeyLabel 属性
		}
		writer.println();
	}

	/**
	 * PrintWriter に DBTableModelのサイズ情報を書き込みます。
	 * 第一カラム目は、サイズ情報を示す "#Size" を書き込みます。
	 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.5.5.5 (2004/04/23) DBColumn の size と maxlength の 意味を変更
	 * @og.rev 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeSize( final DBTableModel table,final PrintWriter writer ) {
		if( useNumber ) {
			writer.print( "#Size" );
			writer.print( separator );
		}
		else {
			writer.print( "#" );
		}

		for( int i=0; i<numberOfColumns; i++ ) {
			if( i != 0 ) { writer.print( separator ); }
			final int clm = clmNo[i];
			if( clm < 0 ) { continue; }			// 6.0.1.2 (2014/08/08) カラム飛ばし
			writer.print( dbColumn[clm].getTotalSize() );	// 4.0.0 (2005/01/31) メソッド名変更
			// keyLabelの場合は、後ろのカラムのサイズを付けません。
			if( isKeyLbl[i] ) { writer.print( separator ); }	// 6.2.3.0 (2015/05/01) writeKeyLabel 属性
		}
		writer.println();
	}

	/**
	 * PrintWriter に DBTableModelのクラス名情報を書き込みます。
	 * 第一カラム目は、サイズ情報を示す "#Class" を書き込みます。
	 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeClass( final DBTableModel table,final PrintWriter writer ) {
		if( useNumber ) {
			writer.print( "#Class" );
			writer.print( separator );
		}
		else {
			writer.print( "#" );
		}

		for( int i=0; i<numberOfColumns; i++ ) {
			if( i != 0 ) { writer.print( separator ); }
			final int clm = clmNo[i];
			if( clm < 0 ) { continue; }			// 6.0.1.2 (2014/08/08) カラム飛ばし
			writer.print( dbColumn[clm].getClassName() );
			// keyLabelの場合は、後ろのカラムのクラスを付けません。
			if( isKeyLbl[i] ) { writer.print( separator ); }	// 6.2.3.0 (2015/05/01) writeKeyLabel 属性
		}
		writer.println();
	}

	/**
	 * PrintWriter に セパレーターを書き込みます。
	 * 第一カラム目は、サイズ情報を示す "#----" を書き込みます。
	 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected void writeSeparator( final DBTableModel table,final PrintWriter writer ) {
		final String sep = "----" ;
		if( useNumber ) {
			writer.print( "#----" );
			writer.print( separator );
		}
		else {
			writer.print( "#" );
		}

		for( int i=0; i<numberOfColumns; i++ ) {
			if( i != 0 ) { writer.print( separator ); }
			writer.print( sep );
			// keyLabelの場合は、後ろのカラムのセパレーターを付けません。
			if( isKeyLbl[i] ) { writer.print( separator ); }	// 6.2.3.0 (2015/05/01) writeKeyLabel 属性
		}
		writer.println();
	}

	/**
	 * PrintWriter に DBTableModelのテーブル情報を書き込みます。
	 * このクラスでは，データを ダブルコーテーション(")で囲みます。
	 * PrintWriter に DBTableModelのテーブル情報を書き込みます。
	 *
	 * @og.rev 2.0.0.5 (2002/09/30) 先頭が0 でかつ数字タイプ(S9 or R)でない場合に ' を出力するように修正。
	 * @og.rev 2.3.1.2 (2003/01/28) データ出力時に、改行が余分に出される箇所を修正。
	 * @og.rev 3.1.0.0 (2003/03/20) DBColumn から、getDbType() キーを直接取り出す
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.3.3.1 (2003/07/18) ファイルリード/ライト時に後ろスペースの除去を行います。
	 * @og.rev 3.7.0.2 (2005/02/14) 行番号情報を、出力する(true)/しない(false)を指定
	 * @og.rev 3.8.0.1 (2005/06/17) DBTypeが NVAR の場合は、元のUnicodeに戻します。
	 * @og.rev 5.1.6.0 (2010/05/01) DbType の初期値(dbType)を利用する。
	 * @og.rev 5.2.1.0 (2010/10/01) このメソッドは、abstract 化します。
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	writer PrintWriterオブジェクト
	 */
	protected abstract void writeData( final DBTableModel table,final PrintWriter writer ) ;

	/**
	 * DBTableModel をセットします。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.5.4.2 (2003/12/15) lang 引数も同時に設定します。
	 *
	 * @param	table DBTableModelオブジェクト
	 * @param	lang 言語コード
	 */
	public void setDBTableModel( final DBTableModel table, final String lang ) {
		this.table = table;
		this.lang = lang;
	}

	/**
	 * 内部の DBTableModel を返します。
	 *
	 * @return	DBTableModelオブジェクト
	 */
	public DBTableModel getDBTableModel() {
		return table;
	}

	/**
	 * DBTableModelの出力順をセットします。
	 * Label,Name,Size,Class,Data の各フィールドの頭文字のアルファベットで
	 * 出力順を設定します。
	 *
	 * なお，出力順に指定しない項目は出力されません
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 *
	 * @param	hs 出力順 (LNSCD など)
	 */
	public void setHeaderSequence( final String hs ) {
		if( hs != null ) { headerSequence = hs ; }
	}

	/**
	 * DBTableModelの出力順を返します。
	 * Label,Name,Size,Class,Data の各フィールドの頭文字のアルファベットで
	 * 出力順を設定します。
	 *
	 * なお，出力順に指定しない項目は出力されません
	 *
	 * @return	出力順 (LNSCD など)
	 */
	public String getHeaderSequence() {
		return headerSequence ;
	}

	/**
	 * データを書き込む場合の,区切り文字をセットします。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 *
	 * @param	sep 区切り文字
	 */
	public void setSeparator( final String sep ) {
		if( sep != null ) { this.separator = sep; }
	}

	/**
	 * データを書き込む場合の,区切り文字を返します。
	 *
	 * @return	区切り文字
	 */
	public String getSeparator() {
		return separator;
	}

	/**
	 * DBTableModelのデータとして書き込むときに、追加モードで書き込むかどうかを設定します。
	 * 初期値は、false(新規モード)です。
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) 新規追加
	 *
	 * @param	flag	[true:追加モード/false:新規モード]
	 */
	public void setAppend( final boolean flag ) {
		append = flag;
	}

	/**
	 * DBTableModelのデータとして書き込むときに、追加モードで書き込むかどうかを取得します。
	 * 初期値は、false(新規モード)です。
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) 新規追加
	 *
	 * @return	true(追加モード)/false(新規モード)
	 */
	public boolean isAppend() {
		return append ;
	}

	/**
	 * DBTableModelのデータとして読み込むときのシート名を設定します。
	 * 初期値は、"Sheet1" です。
	 * これは、EXCEL追加機能として実装されています。
	 * ※ このクラスでは実装されていません。
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) 新規追加
	 * @og.rev 3.5.4.3 (2004/01/05) 実装廃止(TableWriter_Excel へ移動)
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param   sheetName シート名
	 */
	public void setSheetName( final String sheetName ) {
		final String errMsg = "sheetName は、EXCEL専用機能なので使用できません。[" + sheetName + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL雛型参考ファイルのシート名を設定します。
	 * これは、EXCEL追加機能として実装されています。
	 *
	 * EXCELファイルを書き出す時に、雛型として参照するシート名を指定します。
	 * これにより、複数の形式の異なるデータを順次書き出したり(appendモードを併用)する
	 * ことや、シートを指定して新規にEXCELを作成する場合にフォームを設定する事が可能になります。
	 * 初期値は、null(第一シート) です。
	 * ※ このクラスでは実装されていません。
	 *
	 * @og.rev 3.5.4.3 (2004/01/05) 新規追加
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param   sheetName シート名
	 */
	public void setRefSheetName( final String sheetName )  {
		final String errMsg = "refSheetName は、EXCEL専用機能なので使用できません。[" + sheetName + "]";
		System.err.println( errMsg );
	}

	/**
	 * このクラスが、EXCEL対応機能を持っているかどうかを返します。
	 *
	 * EXCEL対応機能とは、シート名のセット、雛型参照ファイル名のセット、
	 * 書き込み元ファイルのFileオブジェクト取得などの、特殊機能です。
	 * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の
	 * 関係があり、問い合わせによる条件分岐で対応します。
	 *
	 * @og.rev 3.5.4.3 (2004/01/05) 新規追加
	 *
	 * @return	EXCEL対応機能を持っているかどうか(ここでは、false固定です)
	 */
	public boolean isExcel() {
		return false;
	}

	/**
	 * 出力先ディレクトリとファイル名をセットします。
	 * これは、EXCEL追加機能として実装されています。
	 * ※ このクラスでは実装されていません。
	 * このメソッドでは、必ず、UnsupportedOperationException が、throw されます。
	 *
	 * @og.rev 3.5.4.3 (2004/01/05) 新規作成
	 * @og.rev 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理します。
	 *
	 * @param   directory 出力先ディレクトリ名
	 * @param   filename  出力先ファイル名
	 */
	public void setFilename( final String directory , final String filename ) {
		final String errMsg = "このメソッドは、EXCEL追加機能ですので、使用できません。";
		throw new UnsupportedOperationException( errMsg );
	}

	/**
	 * EXCEL雛型参考ファイル名をセットします。(DIR + Filename)
	 * これは、EXCEL追加機能として実装されています。
	 * ※ このクラスでは実装されていません。
	 * このメソッドでは、必ず、UnsupportedOperationException が、throw されます。
	 *
	 * @og.rev 3.5.4.3 (2004/01/05) 新規作成
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param   filename EXCEL雛型参考ファイル名
	 */
	public void setRefFilename( final String filename ) {
		final String errMsg = "refFilename は、EXCEL専用機能なので使用できません。[" + filename + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時のデフォルトフォント名を設定します。
	 * これは、EXCEL追加機能として実装されています。
	 *
	 * EXCELファイルを書き出す時に、デフォルトフォント名を指定します。
	 * フォント名は、EXCELのフォント名をそのまま使用してください。
	 * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontName( String )
	 * に設定されます。
	 * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_NAME です。
	 *
	 * ※ このクラスでは実装されていません。
	 * このメソッドでは、必ず、UnsupportedOperationException が、throw されます。
	 *
	 * @og.rev 3.8.5.3 (2006/08/07) 新規追加
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param   fontName フォント名
	 */
	public void setFontName( final String fontName ) {
		final String errMsg = "fontName は、EXCEL専用機能なので使用できません。[" + fontName + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時のデフォルトフォントポイント数を設定します。
	 * これは、EXCEL追加機能として実装されています。
	 *
	 * EXCELファイルを書き出す時に、デフォルトポイント数を指定します。
	 * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontHeightInPoints( short )
	 * に設定されます。
	 * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_POINTS です。
	 *
	 * ※ このクラスでは実装されていません。
	 * このメソッドでは、必ず、UnsupportedOperationException が、throw されます。
	 *
	 * @og.rev 3.8.5.3 (2006/08/07) 新規追加
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param	point	フォントポイント数
	 */
	public void setFontPoint( final short point ) {
		final String errMsg = "fontPoint は、EXCEL専用機能なので使用できません。[" + point + "]";
		System.err.println( errMsg );
	}

	/**
	 * 読み取り元ファイルのエンコード文字列を指定します。
	 * ファイルは、BufferedReader で受け取る為、本来は、エンコードは不要ですが、
	 * 固定長ファイルの読み取り時のバイトコード分割時に、指定のエンコードで
	 * 分割する必要があります。(例えば、半角文字は、Shift_JIS では、１バイト)
	 *
	 * @og.rev 3.5.4.5 (2004/01/23) 新規作成
	 *
	 * @param   enc ファイルのエンコード文字列
	 */
	public void setEncode( final String enc ) {
		encode = enc;
	}

	/**
	 * 読み取り元ファイルのエンコード文字列を取得します。
	 * ファイルは、BufferedReader で受け取る為、本来は、エンコードは不要ですが、
	 * 固定長ファイルの読み取り時のバイトコード分割時に、指定のエンコードで
	 * 分割する必要があります。(例えば、半角文字は、Shift_JIS では、１バイト)
	 *
	 * @og.rev 3.5.4.5 (2004/01/23) 新規作成
	 *
	 * @return	ファイルのエンコード文字列
	 */
	protected String getEncode() {
		return encode;
	}

	/**
	 * 行番号情報を、出力する(true)/しない(false)を指定します。
	 *
	 * 通常のフォーマットでは、各行の先頭に行番号を出力します。
	 * これは、#NAME 属性を使用する場合には、必ず出力する必要があります。
	 * (#NAME 属性は、読み取り時には、必須です。)
	 * この、先頭の行番号が不要な場合(つまり、他のシステムへのデータ出力、
	 * このシステムでは、#NAME 属性が出力されないため、読み込みできません。)
	 * この行番号を出力しないようにできます。
	 * 初期値は、true(出力する) です。
	 *
	 * @og.rev 3.7.0.2 (2005/02/14) 新規追加
	 *
	 * @param   useNumber 行番号情報を [true:出力する/false:しない]
	 */
	public void setUseNumber( final boolean useNumber ) {
		this.useNumber = useNumber;
	}

	/**
	 * 行番号情報を、出力する(true)/しない(false)を返します。
	 *
	 * 通常のフォーマットでは、各行の先頭に行番号を出力します。
	 * これは、#NAME 属性を使用する場合には、必ず出力する必要があります。
	 * (#NAME 属性は、読み取り時には、必須です。)
	 * この、先頭の行番号が不要な場合(つまり、他のシステムへのデータ出力、
	 * このシステムでは、#NAME 属性が出力されないため、読み込みできません。)
	 * この行番号を出力しないようにできます。
	 * 初期値は、true(出力する) です。
	 *
	 * @og.rev 3.7.0.2 (2005/02/14) 新規追加
	 *
	 * @return   行番号情報を、出力する(true)/しない(false)
	 */
	protected boolean isUseNumber() {
		return useNumber;
	}

	/**
	 * パラメーターリストをセットします。
	 * 内部は、HybsEntry クラスを持っています。
	 * 引数が、null の場合は、何もしません。
	 * ※ このクラスでは実装されていません。
	 *
	 * @og.rev 4.0.0.0 (2005/01/31) 新規追加
	 *
	 * @param   listParam	パラメーターリスト
	 */
	public void setParam( final List<HybsEntry> listParam ) {
		final String errMsg = "このメソッドは、XML追加機能ですので、使用できません。";
		throw new UnsupportedOperationException( errMsg );
	}

	/**
	 * 出力先ファイルのカラム列を、外部(タグ)よりCSV形式の文字列で指定します。
	 * ただし、指定のカラム名は、DBTableModel上に存在している必要があります。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規追加
	 *
	 * @param   clms 出力先ファイルのカラム列(CSV形式)
	 */
	public void setColumns( final String clms ) {
		columns = clms ;
	}

	/**
	 * 書き込み対象外のカラム列を、外部(タグ)よりCSV形式で指定します。
	 *
	 * 指定するカラム名に対して、書き込み処理を行いません。
	 * ここで指定するカラム名は、検索したDBTableModel上に含まれる必要はありません。
	 * その場合は、ここでの指定は無視されます。
	 *
	 * @og.rev 6.1.0.0 (2014/12/26) omitNames 属性を追加
	 *
	 * @param   clms 書き込み対象外のカラム列(CSV形式)
	 */
	public void setOmitNames( final String clms ) {
		omitNames = clms;
	}

	/**
	 * データの書き込み開始行番号を設定します(初期値:0)。
	 *
	 * TAB区切りテキストやEXCEL等のデータの書き込みの開始行番号を指定します。
	 * 属性名は、行を飛ばす処理ということで、readTable タグと同じ名称です。
	 * ファイルの先頭行が、０行としてカウントしますので、設定値は、読み飛ばす
	 * 件数になります。(１と指定すると、１件読み飛ばし、２行目から読み込みます。)
	 * 行の読み飛ばしと、カラムの読み飛ばし(columns)、refFileURL、refFilename、
	 * refSheetName とともに使用すれば、ある程度のレイアウト設定が可能です。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 5.7.9.0 (2014/08/08) 新規作成
	 * @og.rev 6.0.2.0 (2014/09/19) isExcel() で判定しているので、Exception は投げない。
	 *
	 * @param	skipRowCount 書き込み開始行番号
	 */
	public void setSkipRowCount( final int skipRowCount ) {
		if( skipRowCount != 0 ) {
			final String errMsg = "skipRowCount は、EXCEL専用機能なので使用できません。[" + skipRowCount + "]";
			System.err.println( errMsg );
		}
	}

	/**
	 * EXCEL出力時に、データを書き込んだ範囲に罫線を入れるかどうかを指定します。
	 *
	 * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている
	 * だけなので、ある程度加工が必要です。
	 * そこで、データのセットされたセルに罫線を入れることで、それなりのデータが
	 * 出力された感じになります。
	 * この設定と、useAutoCellSize="true" で、セルの幅を自動調整すれば、見栄えが良くなります。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	useCellStyle 罫線を入れるかどうか(true:入れる/false:入れない)
	 * @see		#setUseAutoCellSize( boolean )
	 */
	public void setUseCellStyle( final boolean useCellStyle ) {
		final String errMsg = "useCellStyle は、EXCEL専用機能なので使用できません。[" + useCellStyle + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、セルの幅をデータの幅に自動的に合わせるかどうかを指定します。
	 *
	 * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている
	 * だけなので、ある程度加工が必要です。
	 * そこで、データのセットされたセルの幅を自動調整することで、それなりのデータが
	 * 出力された感じになります。
	 * この設定と、useCellStyle="true" で、セルの罫線を自動設定すれば、見栄えが良くなります。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	useAutoCellSize データの幅に自動的に合わせるかどうか(true:自動調整/false:何もしない)
	 * @see		#setUseCellStyle( boolean )
	 */
	public void setUseAutoCellSize( final boolean useAutoCellSize ) {
		final String errMsg = "useAutoCellSize は、EXCEL専用機能なので使用できません。[" + useAutoCellSize + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、セルの有効範囲を設定するかどうかを指定します。
	 *
	 * セルの有効範囲というのは、EXCELでの 空行、空列の存在しない範囲を指します。
	 * 通常、空行でも、データとして残っている場合は、EXCELのセルオブジェクトは存在します。
	 * ここで、useActiveWorkbook="true" とすると、空行、空列を削除します。
	 * 
	 * 雛形を使用した場合は、データより多めに設定した計算などは、この処理で
	 * 削除されますので、データサイズにフィットさせることができます。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	useActiveWorkbook セルの有効範囲を設定するかどうか(true:設定する/false:そのまま)
	 */
	public void setUseActiveWorkbook( final boolean useActiveWorkbook ) {
		final String errMsg = "useActiveWorkbook は、EXCEL専用機能なので使用できません。[" + useActiveWorkbook + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、シート変更するキーとなるカラム名を指定します(このカラムの値がシート名になります)。
	 *
	 * EXCEL帳票では、帳票雛形に、PAGE_BRAKE キーを設定しましたが、TableWriterでは、
	 * メモリ上のカラムの値が変更したときに、シート変更させることができます。
	 * このカラムの値がキーブレイクすると、新しいシートに書き出し始めます。
	 * シート名は、このカラムの値（キーブレイクする値）です。
	 * 
	 * 雛形ファイルを使用する場合、雛形シートもキーブレイクに伴って、＋１されます。
	 * つまり、雛形シートとデータシートは同時に変更されます。
	 * ただし、雛形シートは、最後の雛形シートで止まります。
	 * これは、雛形シートにヘッダー雛形とボディ雛形を用意しておき、最初のキーブレイクで
	 * ヘッダーからボディの書き込みにチェンジするイメージで使用できます。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	pageBreakColumn シート変更するキーとなるカラム名を指定
	 * @see		#setFileBreakColumn( String )
	 */
	public void setPageBreakColumn( final String pageBreakColumn ) {
		final String errMsg = "pageBreakColumn は、EXCEL専用機能なので使用できません。[" + pageBreakColumn + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、ファイル名を変更するキーとなるカラム名を指定します(このカラムの値がファイル名になります)。
	 *
	 * EXCEL帳票では、メモリ上のカラムの値が変更したときに、ファイル名を変更することができます。
	 * このカラムの値がキーブレイクすると、新しいファイルに書き出し始めます。
	 * ファイル名は、このカラムの値（キーブレイクする値）＋ 元の出力ファイル名の拡張子(.xlsなど)です。
	 * この設定を使用する場合は、出力ファイル名は無視されますが、拡張子だけは使用されます。
	 * 
	 * 雛形ファイルを使用する場合、雛形ファイルもキーブレイクに伴って、再利用されます。
	 * 例えば、pageBreakColumn と併用する場合、キーブレイクで雛形シートも最初から適用になります。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	fileBreakColumn ファイル名を変更するキーとなるカラム名を指定
	 * @see		#setPageBreakColumn( String )
	 */
	public void setFileBreakColumn( final String fileBreakColumn ) {
		final String errMsg = "fileBreakColumn は、EXCEL専用機能なので使用できません。[" + fileBreakColumn + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定します。
	 *
	 * ここで、作成するハイパーリンクは、EXCELのシートに対するハイパーリンクです。
	 * それ以外のリンク(本当のURLやファイル等)のリンクは(今は)作成できません。
	 * ハイパーリンクを作成するには、①作成するカラム と ②作成する値 が必要です。
	 * このメソッドで設定するのは、「①:②」という形式でカラム名を指定します。
	 * ②がなければ、①と同じとします。
	 * ②の値のシートの存在有無は、無視します。ハイパーリンクを作成するシートを作成する前に
	 * ハイパーリンクを作成するケースが存在します。
	 * (例えば、各シートへのリンクを持った一覧を作成してから、明細の各シートを作成する様なケース)
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	hyperLinkColumn Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定
	 */
	public void setHyperLinkColumn( final String hyperLinkColumn ) {
		final String errMsg = "hyperLinkColumn は、EXCEL専用機能なので使用できません。[" + hyperLinkColumn + "]";
		System.err.println( errMsg );
	}

	/**
	 * EXCEL出力時に、Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します。
	 *
	 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。
	 * なお、この機能は、TableWriter_Excel のみに実装します。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
	 *
	 * @param	sheetName EXCELファイルのシート名
	 */
	public void setAddTitleSheet( final String sheetName ) {
		final String errMsg = "addTitleSheet は、EXCEL専用機能なので使用できません。[" + sheetName + "]";
		System.err.println( errMsg );
	}

	/**
	 * 書込処理でコードリソースのラベル変換を行うかどうか[true/false]を指定します。
	 *
	 * コードリソースをそのままの値で出力すると、数字や記号になり何が書かれているのか
	 * 不明になります。
	 * これは、コードリソースをラベルに変換して出力するかどうかを指定します。
	 * 当然、コードはユニークですが、ラベルはユニークになるかどうか保障はされていませんので
	 * TableReader 系で読み込む場合には、リスクが発生します。
	 * また、TableReader 系で読み込む場合にも、ラベルからコードを求める逆変換を行うように、
	 * setUseRenderer メソッドで指定する必要があります。
	 *
	 * 従来は、TableWriter 系に、TableWriter_Renderer 系のクラスを作って対応していましたが、
	 * このメソッドの属性値のフラグで、制御します。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規作成
	 *
	 * @param	useRenderer	コードリソースのラベル変換を行うかどうか [true:行う/false:行わない]
	 */
	public void setUseRenderer( final boolean useRenderer ) {
		this.useRenderer = useRenderer;
	}

	/**
	 * 書き出し処理でコードリソースのラベル変換を行うかどうかを返します。
	 * 初期値は、false(行わない) です。
	 *
	 * @og.rev 5.2.1.0 (2010/10/01) 新規作成
	 *
	 * @return	ラベル変換を行うかどうか(true:行う/false:行わない)
	 */
	protected boolean isUseRenderer() {
		return useRenderer ;
	}

	/**
	 * データを ダブルコーテーション(")で囲みます。
	 *
	 * この処理では、前後をダブルクオートで囲うため、改行の有無は判定する
	 * 必要はありません。
	 * ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加します。
	 *
	 * @param	 data 元のString文字列
	 *
	 * @return	 ダブルコーテーションで囲まれた文字列
	 * @og.rtnNotNull
	 */
	protected String quotation( final String data ) {
		return "\"" + StringUtil.replace( data,"\"","\"\"" ) + "\"" ;
	}

	/**
	 * データに対して 改行、ダブルクオート等の処理を行います。
	 *
	 * これは、データの前後をダブルクオートで括る quotation(String)と異なり
	 * 前後には、ダブルクオート を追加しません。
	 * ただし、以下の２つの条件で処理を行います。
	 * １．改行を含む場合は、ダブルクオートを強制的に前後に追加する。
	 * ２．ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加する。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
	 *
	 * @param	 data 元のString文字列
	 *
	 * @return	 改行、ダブルクオート等の処理
	 */
	protected String quotation2( final String data ) {
		String rtn = StringUtil.replace( data,"\"","\"\"" );
		if( rtn != null && rtn.indexOf( CR ) >= 0 ) {
			rtn = "\"" + rtn + "\"" ;
		}

		return rtn ;
	}

	/**
	 * keys の整合性チェックを行います。
	 *
	 * キーかkeysMapのどちらかが null の場合は、何もしません。
	 * チェックするキーは、内部で大文字に変換しておきます。
	 * keysMap に登録するキーは、大文字で登録しておいてください。
	 * ここのチェックでは、キーマップに存在しなければ、エラーになります。
	 *
	 * @og.rev 5.6.6.1 (2013/07/12) keys の整合性チェックを行います。
	 *
	 * @param   key チェックするキー文字列(null の場合は、処理しない)
	 * @param   keysMap 利用可能なキーのマップ(大文字に統一)
	 */
	protected void checkParam( final String key,final Map<String,String> keysMap ) {
		// key か keysMap かどちらかが null の場合は、処理を行わない。
		if( key == null || keysMap == null ) { return; }

		final String upKey = key.toUpperCase(Locale.JAPAN);

		if( ! keysMap.containsKey( upKey ) ) {
			final String BR = "<br />" + CR ;
			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE );
			// 6.0.2.5 (2014/10/31) char を append する。
			errMsg.append( BR )
				  .append( "指定のキーは、この tableWriter では、使用できません。" ).append( BR )
				  .append( "  class=[" ).append( getClass().getName() ).append( ']' ).append( BR )
				  .append( "  key  =[" ).append( key				  ).append( ']' ).append( BR )
				  .append( "  ======== usage keys ======== " ).append( BR ) ;
			for( final Map.Entry<String, String> entry : keysMap.entrySet() ) {
				errMsg.append( ' ' ).append( entry.getKey() ).append( ':' )
									.append( entry.getValue() ).append( BR ) ;
			}
			errMsg.append( "  ============================ " ).append( BR );

			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * デバッグ情報を出力するかどうか[true:する/false:しない]を指定します。
	 *
	 * EXCELなどを書き出す場合、シートブレイクやファイルブレイク時の行番号が、検索時の行番号と
	 * 異なる為、エラー時の判定が難しくなります。
	 * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
	 * 通常は使用しませんので、設定を無視します。
	 * 初期値は、false:デバッグ情報を出力しない です。
	 *
	 * @og.rev 6.1.0.0 (2014/12/26) デバッグ情報を出力するかどうかを指定
	 *
	 * @param	useDebug	デバッグ出力するか [true:する/false:しない]
	 */
	public void setDebug( final boolean useDebug ) {
		this.useDebug = useDebug;
	}

	/**
	 * デバッグ情報を出力するかどうか[true:する/false:しない]を取得します。
	 *
	 * EXCELなどを書き出す場合、シートブレイクやファイルブレイク時の行番号が、検索時の行番号と
	 * 異なる為、エラー時の判定が難しくなります。
	 * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
	 *
	 * @og.rev 6.1.0.0 (2014/12/26) デバッグ情報を出力するかどうかを指定
	 *
	 * @return	デバッグ出力 [true:する/false:しない]
	 */
	protected boolean isDebug() {
		return useDebug ;
	}
}
