/*
 * 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.DBColumn;
import org.opengion.hayabusa.db.DBTableModel;

import org.opengion.hayabusa.resource.ResourceFactory;
import org.opengion.hayabusa.resource.ResourceManager;

import org.opengion.fukurou.util.ErrorMessage;
import org.opengion.fukurou.util.StringUtil;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * <p>TableFilter_DBARG は、TableFilter インターフェースを継承した、DBTableModel 処理用の
 * 実装クラスです。<br />
 *
 * ここでは、キーのCLM,LBL と、LANG より、ラベルリソースに変換した値を設定します。
 *  CLM :ラベルリソースのキーとなる値が設定されているカラム名を指定します。
 *  LBL :CLMで指定されたカラム名から値を取り出し、ラベルリソースに変換した結果をセットします。
 *  LANG:ラベルリソースの言語を指定します。無指定時は、日本語になります。
 *
 * CLM と LBL に同じカラムを指定すると、このフィルターを通過するたびに、変換後のラベルが
 * 再びキーとして変換しようと試みることになります。不測の事態に陥る可能性があるため、
 * その様な設定は出来なくなっています。
 *
 * また、CLM または LBL で指定したカラムが DBTableModel に存在しない場合は、処理そのものを
 * 無視します。その場合は、警告も出力されませんので、ご注意ください。
 *
 * @version  0.9.0  2000/10/17
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.1,
 */
public class TableFilter_DBARG extends AbstractTableFilter {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "4.0.0 (2005/08/31)" ;

	private static final String[] KEYS = new String[] { "TEXT","CLM","CLS_NAME","USE_LENGTH","CLM_NAME","MAX_LENGTH" };
	private static final int TEXT		= 0;
	private static final int CLM		= 1;
	private static final int CLS_NAME	= 2;
	private static final int USE_LENGTH	= 3;
	private static final int CLM_NAME	= 4;
	private static final int MAX_LENGTH	= 5;

	/**
	 * DBTableModel処理を実行します。<br />
	 *
	 * @return 処理結果のDBTableModel
	 */
	public DBTableModel execute() {
		String lang = getValue( "LANG" );
		ResourceManager resource = ResourceFactory.newInstance( lang );

		int size = KEYS.length;
		int[] clmNo = new int[size];
		for( int i=0; i<size; i++ ) {
			String clm = getValue( KEYS[i] );
			clmNo[i]  = table.getColumnNo( clm,false );	// 存在しない場合は、-1
			if( clmNo[i] < 0 ) {
				String errMsg = "検索結果に、[" + clm + "]を含めてください。" ;
				throw new HybsSystemException( errMsg );
			}
		}

		String[] data  = null;
		int rowCnt = table.getRowCount();
		DBTableModel rtnTbl = table.newModel();
		for( int row=0; row<rowCnt; row++ ) {
			try {
				data = table.getValues( row );
				String text = data[clmNo[TEXT]] ;
				String[] temp = textSeparate( text );
				if( temp != null ) {
					data[clmNo[CLM]]		= temp[0];
					data[clmNo[CLS_NAME]]	= temp[1];
					data[clmNo[USE_LENGTH]]	= temp[2];
			//		data[clmNo[CLM_NAME]]	= resource.getLabel( temp[0] ) ;

					DBColumn dbClm = resource.getDBColumn( temp[0] );
					if( dbClm != null ) {
						data[clmNo[CLM_NAME]]	= dbClm.getLabel() ;
						String len = data[clmNo[MAX_LENGTH]] ;
						if( len == null || len.length() == 0 ) {
							data[clmNo[MAX_LENGTH]] = dbClm.getMaxlength() ;
						}
					}
			//		else {
			//			data[clmNo[CLM_NAME]]	= temp[0] ;	// ラベルが存在しない
			//		}
					rtnTbl.addColumnValues( data );
				}
			}
			catch( RuntimeException ex ) {
				ErrorMessage errMessage = makeErrorMessage( "TableFilter_DBARG Error",ErrorMessage.NG );
				errMessage.addMessage( row+1,ErrorMessage.NG,"ERR MSG",ex.getMessage() );
				errMessage.addMessage( row+1,ErrorMessage.NG,"ERR Data",StringUtil.array2csv( data ) );
			}
		}

		return rtnTbl;
	}

	private static final Pattern pt = Pattern.compile( "[^\\w]*([\\w]*)[^\\w]*(VARCHAR2|NUMBER)[^\\w]*\\(([^\\)]*)\\)",Pattern.CASE_INSENSITIVE );
												//			   (______)       (_______________)          (_______)

	/**
	 * ソースのテキスト部を分割します。<br />
	 *
	 * ソースのテキスト部は、",NAME_JA VARCHAR2(100) " という形式のテキストになっています。
	 * これを、カラム部、クラス名部、使用桁数部に分解します。上記の例では、
	 * それぞれを、NAME_JA、VARCHAR2、100 に分解して、文字列配列に格納します。
	 * また、これらのソースに、"--" や "/ * ･･･ * /" などのコメントが含まれるケースが
	 * あります。"--" コメントは、それ以降を無視しますが、"/ *" コメントは、複数行に
	 * またがる為、今回は処理対象から外します。
	 * ソースのテキスト部には、それら以外に、OBJECT_NAME に相当する行や、");" などの
	 * ソースの最初や最後の無効な部分があります。無効な部分は、null を返すことで
	 * 登録処理から省いてください。
	 *
	 * @param  text String ソースのテキスト部
	 * @return String[] 分割後の文字列配列(CLM,CLS_NAME,USE_LENGTHの順)、無効なデータは null
	 */
	private String[] textSeparate( final String text ) {

		int adrs = text.indexOf( "--" );
		String text2 = (adrs<0) ? text : text.substring( 0,adrs ) ;

		String[] rtnTxt = null ;
		Matcher mt = pt.matcher( text2 );
		if( mt.lookingAt() ) {
			String clm = mt.group( 1 );		// カラムの名称:パターンとして、空白は含まない
			String cls = mt.group( 2 );		// クラスの名称(VARCHAR2|NUMBER)
			String len = mt.group( 3 );		// 桁数:パターンとして、前後に空白を含む

			if( clm != null && cls != null && len != null ) {
				len = len.trim();
				if( len.length() > 0 ) {
					rtnTxt = new String[] { clm,cls,len };
				}
			}
		}

		// マッチしない または 条件を満たさない場合は、null
		return rtnTxt ;
	}
}
