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

import org.opengion.fukurou.system.OgRuntimeException ;		// 6.4.2.0 (2016/01/29)

/**
 * DataModel の実装クラスです。
 * Formatter で使用されるDataModelインターフェースに、対応する
 * 実データを管理します。
 * データ設定時に、コピーしますので、基本的には、オリジナルの書き換えは
 * できません。
 * 実データも、１行分のみ持っています。
 *
 * @og.group 画面表示
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ArrayDataModel implements DataModel<String> {
	private final boolean useThrow ;			// 6.9.5.0 (2018/04/23) getColumnNo のカラム名が存在しない場合に、Exception を throw するかどうか
	private final String[] names ;
	private String[] values ;

	/**
	 * 引数に名前配列を指定したコンストラクター
	 *
	 * @og.rev 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw するかどうかを指定可能にする。
	 *
	 * @param	nms		名前配列
	 * @throws  IllegalArgumentException 引数の名前配列が null の場合
	 */
	public ArrayDataModel( final String[] nms ) {
		this( nms , false );			// 6.9.5.0 (2018/04/23) カラム名が存在しない場合は、-1 を返す設定。
	}

	/**
	 * 引数に名前配列を指定したコンストラクター
	 *
	 * getColumnNoメソッドで、カラム名が存在しない場合に、Exception を throw するかどうかを、
	 * 第２パラメータで指定します。true で、Exception を throw するです。
	 * このメソッドは、Formatter から呼ばれるため、インスタンス生成時にﾌﾗｸﾞ設定を行っておく必要があります。
	 *
	 * @og.rev 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw するかどうかを指定可能にする。
	 *
	 * @param	nms			名前配列
	 * @param   useThrow	カラム名が存在しない場合に、Exception を throw するかどうか [true:throw する/false:-1 を返す]
	 * @throws  IllegalArgumentException 引数の名前配列が null の場合
	 */
	public ArrayDataModel( final String[] nms , final boolean useThrow ) {
		if( nms == null ) {
			final String errMsg = "引数の名前配列に、null は設定できません。";
			throw new IllegalArgumentException( errMsg );
		}

		final int size = nms.length ;
		names = new String[size] ;
		System.arraycopy( nms,0,names,0,size );
		this.useThrow = useThrow;					// 6.9.5.0 (2018/04/23)
	}

	/**
	 * row にあるセルの設定値を置き換えます。
	 *
	 * @param   vals  新しい配列値。
	 * @param   row   値が変更される行(無視されます)
	 */
	@Override
	public void setValues( final String[] vals, final int row ) {
		final int size = vals.length;
		values = new String[size];
		System.arraycopy( vals,0,values,0,size );
	}

	/**
	 * カラム名に対応する カラム番号を返します。
	 *
	 * 特殊なカラムが指定された場合は、負の値を返します。
	 * 例えば、[KEY.カラム名]、[I]、[ROW.ID] など、特定の負の値を返します。
	 * また、カラム名が元のデータモデルに存在しない場合も、負の値か、
	 * Exception を返します。負の値なのか、Exception なのかは、
	 * 実装に依存します。
	 *
	 * @og.rev 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw するかどうかを指定可能にする。
	 *
	 * @param	columnName	値が参照されるカラム名
	 *
	 * @return  指定されたセルのカラム番号。存在しなければ、-1
	 * @throws  IllegalArgumentException 引数のカラム名が null の場合
	 */
	@Override
	public int getColumnNo( final String columnName ) {
		if( columnName == null ) {
			final String errMsg = "引数のカラム名に、null は設定できません。";
			throw new IllegalArgumentException( errMsg );
		}

		int address = -1;
		for( int i=0; i<names.length; i++ ) {
			if( columnName.equalsIgnoreCase( names[i] ) ) {
				address = i;
				break;
			}
		}

		// 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw するかどうか
		if( useThrow && address < 0 ) {
			final String errMsg = "カラム名が存在しません:[" + columnName + "]" ;
			throw new OgRuntimeException( errMsg );
		}

		return address;
	}

	/**
	 * カラム名配列に対応する カラム番号配列を返します。
	 *
	 * これは、#getColumnNo( String ) に対する 複数のカラム名を検索した
	 * 場合と同じです。
	 *
	 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の１か所にすべきです(PMD)。
	 * @og.rev 6.8.6.0 (2018/01/19) 可変長引数から、通常配列に変更。
	 * @og.rev 6.9.5.0 (2018/04/23) #getColumnNo(String)を呼ぶように修正
	 *
//	 * @param	clmNms 	値が参照されるカラム名配列(可変長引数)
	 * @param	clmNms 	値が参照されるカラム名配列
	 *
	 * @return  指定されたセルのカラム番号配列。
	 * @og.rtnNotNull
	 */
//	public int[] getColumnNos( final String... clmNms ) {
	public int[] getColumnNos( final String[] clmNms ) {

		final int size = clmNms == null ? 0 : clmNms.length ;

		final int[] clmNos = new int[size];
		for( int j=0; j<size; j++ ) {
			// 6.9.5.0 (2018/04/23) #getColumnNo(String)を呼ぶように修正
			clmNos[j] = getColumnNo( clmNms[j] );
//			int address = -1;
//			for( int i=0; i<names.length; i++ ) {
//				if( clmNms[j].equalsIgnoreCase( names[i] ) ) {
//					address = i;
//					break;
//				}
//			}
//			clmNos[j] = address;
		}

		return clmNos;
	}

	/**
	 * カラム名配列を返します。
	 *
	 * @return	カラム名配列
	 * @og.rtnNotNull
	 */
	@Override
	public String[] getNames() {
		return names.clone();
	}

	/**
	 * row にあるセルの属性値を配列で返します。
	 *
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 *
	 * @param   row     値が参照される行(無視されます)
	 *
	 * @return  指定されたセルの属性値
	 * @og.rtnNotNull
	 */
	@Override
	public String[] getValues( final int row ) {
		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( values == null ) {
			final String errMsg = "#setValues(String[],int)を先に実行しておいてください。";
			throw new OgRuntimeException( errMsg );
		}

		return values.clone();
	}

	/**
	 * row および clm にあるセルの属性値をStringに変換して返します。
	 *
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 *
	 * @param   row     値が参照される行(無視されます)
	 * @param   clm     値が参照される列
	 *
	 * @return  指定されたセルの値
	 *
	 */
	@Override
	public String getValue( final int row, final int clm ) {
		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( values == null ) {
			final String errMsg = "#setValues(String[],int)を先に実行しておいてください。";
			throw new OgRuntimeException( errMsg );
		}

		return values[clm];
	}

	/**
	 * clm のNativeタイプを返します。
	 * Nativeタイプはorg.opengion.fukurou.model.NativeTypeで定義されています。
	 *
	 * @og.rev 4.1.1.2 (2008/02/28) 新規追加
	 * @og.rev 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソッドを使用するように変更。
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 *
	 * @param  clm      値が参照される列
	 *
	 * @return Nativeタイプ
	 * @see org.opengion.fukurou.model.NativeType
	 */
	@Override
	public NativeType getNativeType( final int clm ) {
		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( values == null ) {
			final String errMsg = "#setValues(String[],int)を先に実行しておいてください。";
			throw new OgRuntimeException( errMsg );
		}

		return NativeType.getType( values[clm] );
	}
}
