// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

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

import net.cellcomputing.himawari.accessory.STLArray;
import net.cellcomputing.himawari.accessory.STLArrayList;
import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.primitive.p_String;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.accessory.primitive.p_int;
import net.cellcomputing.himawari.library.types.CqColor;
import net.cellcomputing.himawari.library.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector3D;
import net.cellcomputing.himawari.library.types.CqVector4D;

/**
 * 値のタイプと、idのタイプでテンプレート化された、一定のパラメータタイプ。
 * @author NTT DATA Corporation
 */
public strictfp class CqParameterTypedUniform <T,SLT>extends CqParameterTyped<T,SLT> {
	
	 //private STLVector<T>		m_aValues;
	 private STLArray<T>		m_aValues;
	 private EqVariableType 	I;			//C++ではGenericsとして指定されている値
	
	 /**
	  * コンストラクタ
	  * @param str 名前
	  * @param count サイズ
	  * @param I Generics I
	  * @param TClass Generics TのClass
	  * @param SLTClass Generics SLTのClass
	  */
	 public CqParameterTypedUniform(final String str,int count,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass){
		 super(str,count,TClass,SLTClass);
		 
		 //m_aValues = new STLVector<T>(TClass);
		 m_aValues = new STLArray<T>(TClass);
		 m_aValues.setSize(1);
		 this.I = I;
	 }
	 
	 /**
	  * コピーコンストラクタ
	  * @param From コピー元
	  * @param I Generics I
	  */
	 public CqParameterTypedUniform(CqParameterTypedUniform<T,SLT> From,EqVariableType I){
		 super(From);
//		m_aValues = new STLVector<T>(TClass);
		 m_aValues = new STLArray<T>(TClass);
		 m_aValues.setSize(1);
		 this.I = I;
		 
		 this.assignment(From);
	 }
	 
	 /**
	  * コンストラクタ
	  * Countが省略されている
	  * 
	  * @param name 名前
	  * @param I Genrics I
	  * @param TClass Generics SのClass
	  */
	 public CqParameterTypedUniform(final String name,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass){
		 this(name,1,I,TClass,SLTClass);
	 }
	 
	/**
	 * デストラクタ
	 */
	public void destruct(){
		super.destruct();
	}
		
	/**
	 * 自分の持つVectorの値を配列として全て返す。
	 * 
	 */
	public Object[] pValue() {
		assert( 0 < m_aValues.size() );
		
		return m_aValues.toArray();
	}
	
	/**
	 * イコール演算子
	 * 代入元が持つVectorの値を全て自分自身のVectorにコピーする
	 * 
	 * @param From 代入元インスタンス
	 * @return 自分自身
	 */
	public  CqParameterTypedUniform<T,SLT> assignment(CqParameterTypedUniform<T,SLT> From){
		int size = From.m_aValues.size();
		
        m_aValues.resize( size );

        T t =m_aValues.elementAt(0);
        if(t instanceof CqVector3D){
            for ( int j = 0; j <  size; j++ )
            {
                ((CqVector3D)m_aValues.elementAt(j)).assignment((CqVector3D)(From.m_aValues.get(j)));
            }
        	
        }else if(t instanceof CqVector4D){
            for ( int j = 0; j <  size; j++ )
            {
                ((CqVector4D)m_aValues.elementAt(j)).assignment((CqVector4D)(From.m_aValues.get(j)));
            }
        	
        }else if(t instanceof CqColor){
            for ( int j = 0; j <  size; j++ )
            {
                ((CqColor)m_aValues.elementAt(j)).assignment((CqColor)(From.m_aValues.get(j)));
            }
        	
        }else if(t instanceof CqMatrix){
            for ( int j = 0; j <  size; j++ )
            {
                ((CqMatrix)m_aValues.elementAt(j)).assignment((CqMatrix)(From.m_aValues.get(j)));
            }
        	
        }else if(t instanceof p_float){
            for ( int j = 0; j <  size; j++ )
            {
                ((p_float)m_aValues.elementAt(j)).value = ((p_float)(From.m_aValues.get(j))).value;
            }
        	
        }else if(t instanceof p_int){
            for ( int j = 0; j <  size; j++ )
            {
                ((p_int)m_aValues.elementAt(j)).value = ((p_int)(From.m_aValues.get(j))).value;
            }
        	
        }else if(t instanceof p_String){
            for ( int j = 0; j <  size; j++ )
            {
                ((p_String)m_aValues.elementAt(j)).value = ((p_String)(From.m_aValues.get(j))).value;
            }
        	
        }

        return ( this );
	}
	/**
	 * 自分の持つVectorに対して、指定された位置以降の値を
	 * 配列として返却する。
	 * 
	 * 返却した値をセットしなおすことでVectorの持つ値も変化する。
	 * 
	 * @param Index Vectorの値の開始位置
	 * @exception Vectorのサイズより大きい数値を指定するとNegativeArraySizeExceptionが発生する
	 */
//	nttdata 高速化
//	public Object[] pValue(int Index) {
//		assert( Index < m_aValues.size() );//変更 本家のバグと思われる 0< m_aValues.size()
//		Object[] retval = new Object[m_aValues.size()-Index];
//		
//		//retvalに現在のVectorの中身をコピーしていく
//		for(int i=0;i< m_aValues.size() -Index;i++){
//			retval[i] = m_aValues.elementAt(Index + i);
//		}
//		return retval;
//	}
	public Object[] pValue(final int Index) {
		assert( Index < m_aValues.size()  );
			//　ただしSTLVecterにも変更している。
		return m_aValues.toArray(Index);
		}
	
	public T pValue_get(final int Index ,final int arrayIndex)
	{
		return m_aValues.elementAt(Index+arrayIndex);
	}
//	nttdata 高速化 終了
	/**
	 * Typeの同じクローンを生成して返す
	 * 
	 * @param Name 名前
	 * @param Count カウント
	 * @return 新しいCqParameter
	 */
	public CqParameter CloneType(final String Name, int Count) {
		return ( new CqParameterTypedUniform<T,SLT>( Name, Count,I,TClass,SLTClass ) );
	}

	/**
	 * 自分自身と同じ値を持つインスタンスを生成する。
	 */
	public CqParameter Clone() {
		return ( new CqParameterTypedUniform<T,SLT>( this , I ) );
	}

	/**
	 * EqVariableClassを返す
	 *
	 * @return 自分のEqVariableClass
	 */
	public EqVariableClass Class() {
		return ( new EqVariableClass(EqVariableClass.class_uniform) );
	}

	/**
	 * 自分のもつEqVariableTypeを返す
	 * (C++ではGenericsで利用されている)
	 * @return EqVariableType
	 */
	public EqVariableType Type() {
		return I;
	}

	/**
	 * Vectorのサイズを指定の大きさに変更する
	 * @param size 変更するサイズ
	 */
	public void SetSize(int size) {
		m_aValues.setSize(size);
	}

	/**
	 * 自分の持つVectorのサイズ返却する	
	 * @return 現在のVectorのサイズ
	 */
	public int Size() {
		return m_aValues.size();
	}

	/** 
	 * Vectorの中身を全てクリアする
	 */
	public void Clear() {
		m_aValues.clear();
	}

	/**
	 * 指定された引数に対してSubdivideを行う。
	 * 引数のTypeとClassをチェックして、同じであれば
	 * 自分自身を引数に代入(assignment)する。<br>
	 * (親クラスの説明)<br>
	 * u の方向の値を、半分に分割する。他の値を指定の変数で分割する。
	 * 
	 * @param pResult1 
	 * @param pResult2 
	 * @param u 利用しない
	 * @param pSurface 利用しない
	 */
	public void Subdivide(CqParameter pResult1, CqParameter pResult2, boolean u,
			IqSurface pSurface) {
		
        assert( pResult1.Type().getValue() == Type().getValue() && pResult2.Type().getValue() == Type().getValue() &&
                pResult1.Class().getValue() == Class().getValue() && pResult2.Class().getValue() == Class().getValue() );

        CqParameterTypedUniform<T,SLT> pTResult1 = (CqParameterTypedUniform<T,SLT>)( pResult1 );
        CqParameterTypedUniform<T,SLT> pTResult2 = (CqParameterTypedUniform<T,SLT>)( pResult2 );
        pTResult1.assignment(pTResult2.assignment( this ));
	}
	/**
	 * IqShaderDataに値を代入する<br>
	 * (親クラスでの説明)<br>
	 * 配列の単一の要素値をそのクラスの適切な補完を用いてグリッドに切り出す(Dice)
	 * @param u
	 * @param v
	 * @param pResult 
	 * @param pSurface 使用しない
	 */
	public void Dice(int u, int v, IqShaderData pResult, IqSurface pSurface) {
        // Just promote the uniform value to varying by duplication.
        //
		assert( pResult.Type().getValue() == Type().getValue() );
        // Note it is assumed that the variable has been
        // initialised to the correct size prior to calling.
        // Also note that the only time a Uniform value is diced is when it is on a single element, i.e. the patchmesh
        // has been split into isngle patches, or the polymesh has been split into polys.
        int i;
        long max = Math.max( (long)(u * v), pResult.Size() );
        
        T tmp = m_aValues.elementAt(0);
        //Genericsに入る型によって場合わけを行う
        if(tmp instanceof CqMatrix){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqMatrix)m_aValues.elementAt(0), i );
            }
        }else if(tmp instanceof CqVector3D){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqVector3D)m_aValues.elementAt(0), i );
            }
        }else if(tmp instanceof CqVector4D){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( new CqVector3D(((CqVector4D)(m_aValues.elementAt(0)))), i );
            }
        }else if(tmp instanceof CqColor){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqColor)m_aValues.elementAt(0), i );
            }
        }else if(tmp instanceof p_float){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_float)m_aValues.elementAt(0)).value, i );
            }
        }else if(tmp instanceof p_int){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_int)m_aValues.elementAt(0)).value, i );
            }
        }else if(tmp instanceof p_String){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_String)m_aValues.elementAt(0)).value, i );
            }
        }
	}
	
	/**
	 * 常に失敗するメソッド
	 */
	public void DiceOne(int u, int v, IqShaderData pResult, IqSurface pSurface,
			int ArrayIndex) {
        assert( false );
        return;

	}
	
	/**
	 * CqParameterTypedで定義されているもの
	 * 引数で指定したインスタンスのVectorから、指定した値を
	 * 自分自身のVectorの指定した位置にコピーを行う
	 * 
	 * @param pFrom コピー元インスタンス
	 * @param idxTarget コピー先の配列番号。
	 * @param idxSource コピー元の配列番号
	 */
	public void SetValue(CqParameter pFrom, int idxTarget, int idxSource){
		assert( pFrom.Type().getValue() == Type().getValue() );
		
        CqParameterTyped<T, SLT> pFromTyped = (CqParameterTyped<T, SLT>)( pFrom );
        T tmp = (T)pValue_get( idxTarget , 0 );//ポインタなので値を取り出す
        if(tmp instanceof CqMatrix){
        	((CqMatrix)tmp).assignment((CqMatrix)(pFromTyped.pValue_get( idxSource , 0 )));
        }else if(tmp instanceof CqVector3D){
        	((CqVector3D)tmp).assignment((CqVector3D)(pFromTyped.pValue_get( idxSource , 0 )));
        }else if(tmp instanceof CqVector4D){
        	((CqVector4D)tmp).assignment((CqVector4D)(pFromTyped.pValue_get( idxSource , 0 )));
        }else if(tmp instanceof CqColor){
        	((CqColor)tmp).assignment((CqColor)(pFromTyped.pValue_get( idxSource , 0 )));
        }else if(tmp instanceof p_float){
        	((p_float)tmp).value = ((p_float)(pFromTyped.pValue_get( idxSource , 0 ))).value;
        }else if(tmp instanceof p_int){
        	((p_int)tmp).value = ((p_int)(pFromTyped.pValue_get( idxSource , 0 ))).value;
        }else if(tmp instanceof p_String){
        	((p_String)tmp).value = ((p_String)(pFromTyped.pValue_get( idxSource , 0 ))).value;
        }
	}
	
	/**
	 * static コンストラクタ
	 * コンストラクタと同様に利用できる
	 * @param strName 名前
	 * @param Count カウント
	 * @param I Generics I
	 * @param myClass Generics TのClass
	 */
     public static	<T,SLT> CqParameter	Create( final String strName, int Count,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass)
    {
        return ( new CqParameterTypedUniform<T,SLT>( strName, Count ,I,TClass,SLTClass) );
    }

     /**
 	 * static コンストラクタ
 	 * コンストラクタと同様に利用できる(count省略系)
	 * @param strName 名前
	 * @param I Generics I
	 * @param TClass Generics TのClass
	 * @param SLTClass Generics SLTのClass
 	 */
     public static	<T,SLT> CqParameter	Create( final String strName,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass)
     {
    	 return CqParameterTypedUniform.<T,SLT>Create(strName,1,I,TClass,SLTClass);
     }

}
