/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.accessory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;

import net.cellcomputing.himawari.util.HimawariLogger;

/**
 * 
 * C++のSTLのvectorのように動作するArrayListを実現するためのクラス。
 * 
 * @author NTT DATA Corporation
 */
@SuppressWarnings("unchecked")
public strictfp class STLArrayList<T> extends ArrayList<T> {
	
	private static final long serialVersionUID = -7542680781499126519L;

	private Class<? extends T> myClass;
	
	
	/**
	 * 
	 * 基底クラスの動作に加え、内部を指定クラスのインスタンスで埋める。
	 * 
	 * @param cls	リストの中身となるクラス。Generics指定の代わり。
	 * @param initialCapacity	ArrayListの初期容量
	 * @see java.util.ArrayList#ArrayList(int)
	 */
	public STLArrayList( Class<? extends T> cls, int initialCapacity ) {
		super(initialCapacity);
		this.myClass = cls;
		
		fillInstance(0, initialCapacity);
	}
	
	/**
	 * 基底クラスと同動作。
	 * 
	 * @param cls	リストの中身となるクラス。Generics指定の代わり。
	 * @see java.util.ArrayList#ArrayList()
	 */
	public STLArrayList( Class<? extends T> cls ) {
		super();
		this.myClass = cls;
	}

	
	/**
	 * 基底クラスと同動作。
	 * 
	 * @param cls	ベクタの中身となるクラス。Generics指定の代わり。
	 * @param c	要素がVectorに配置されるコレクション 
	 * @see java.util.ArrayList#ArrayList(java.util.Collection)
	 */
	public STLArrayList( Class<? extends T> cls, Collection<? extends T> c ) {
		super(c);
		this.myClass = cls;
	}
	
	
	/**
	 * 
	 * このリストの中身をインスタンスで埋める。
	 * 引数なしコンストラクタでインスタンス化できない場合は、nullで埋める。
	 * 
	 * @param start	埋める範囲の開始位置
	 * @param end		埋める範囲の終了位置
	 */
	private void fillInstance( int start, int end ){
		
		for( int i=start; i<end; i++ ){
			
			try {
				
				T t = newInstance(myClass); 
				this.add( i, t );
				
			} catch (Exception e) {
//				e.printStackTrace();
				this.add( null );
			}
			
		}//end of for
		
	}
	
	
	/**
	 * 
	 * 指定クラスのインスタンスを生成する。
	 * 
	 * @param cls	インスタンス化したいクラス
	 * @return	指定クラスのインスタンス
	 */
	private T newInstance( Class<? extends T> cls ){
		try {
			
			//プリミティブのラッパか？
			Class superClass = cls.getSuperclass();
			if( superClass.equals( Number.class) ){
				
				//ラッパクラスならそのプリミティブ型を示すClassを取得
				Class primitiveClass = (Class)cls.getField("TYPE").get(cls);
				
				//プリミティブを引数に持つコンストラクタを取得	
				Constructor<? extends T> cnst = cls.getConstructor(primitiveClass);
				
				//そのコンストラクタでインスタンス化
				return cnst.newInstance( (byte)0 );
			}
			//はたまたBooleanか？
			else if( cls.equals( Boolean.class ) ){
				
				//コンストラクタの取得
				Constructor<? extends T> cnst = cls.getConstructor(boolean.class);
				
				//インスタンス化
				return cnst.newInstance( false );
			}
			
			//その他は普通にインスタンス化
			return cls.newInstance();
			
		} catch (Exception e) {
			
			//インターフェースや抽象クラス以外でExceptionが発生した場合、エラー内容を表示。
			int mod = cls.getModifiers();
			if( !Modifier.isInterface(mod) && !Modifier.isAbstract(mod) ) HimawariLogger.outputException( e );
			
			//なんかエラーがあればnull
			return null;
		}
	}

	public void resize( int newSize ) {
		
		int oldSize = size();
		
		if( newSize > oldSize ){
			fillInstance( oldSize, newSize );
		}
	}
}

