// 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.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;
import net.cellcomputing.himawari.util.HimawariLogger;

/**
 * 値のタイプと、Idのタイプでテンプレート化された、パラメータの一つのタイプ
 * @author NTT DATA Corporation
 */
public strictfp class CqParameterTypedConstant<T,SLT> extends CqParameterTyped<T,SLT> {

	private EqVariableType I;
	private T m_aValues;
	/**
	 * コンストラクタ
	 * 
	 * @param strName 名前
	 * @param count カウント
	 * @param I Generics I
	 * @param TClass Generics TのClass
	 * @param SLTClass Generics SLTのClass
	 */
	public CqParameterTypedConstant(final String strName,int count,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass){
		super(strName,count,TClass,SLTClass);
		this.I = I;
		
		try{
			m_aValues = TClass.newInstance();
		}catch(IllegalAccessException e){
			HimawariLogger.outputException( e );
			assert(false);
		}catch(InstantiationException ie){
			HimawariLogger.outputException( ie );
			assert(false);
		}
	}
	
	/**
	 * コンストラクタ
	 * 
	 * @param strName 名前
	 * @param I Generics I
	 * @param TClass Generics TのClass
	 * @param SLTClass Generics SLTのクラス
	 */
	public CqParameterTypedConstant(final String strName,EqVariableType I,Class<? extends T> TClass,Class<? extends SLT> SLTClass){
			this(strName,1,I,TClass,SLTClass);
	}
	/**
	 * コピーコンストラクタ
	 * @param From コピー元
	 * @param I Generics I
	 */
	public CqParameterTypedConstant(final CqParameterTypedConstant<T,SLT> From,EqVariableType I){
		super(From);
		this.I = I;
		try{
			m_aValues = (T)TClass.newInstance();
			
	        if(m_aValues instanceof CqVector3D){

	                ((CqVector3D)m_aValues).assignment((CqVector3D)(From.m_aValues));
	        	
	        }else if(m_aValues instanceof CqVector4D){
	                ((CqVector4D)m_aValues).assignment((CqVector4D)(From.m_aValues));
	        	
	        }else if(m_aValues instanceof CqColor){
	                ((CqColor)m_aValues).assignment((CqColor)(From.m_aValues));
	        	
	        }else if(m_aValues instanceof CqMatrix){
	                ((CqMatrix)m_aValues).assignment((CqMatrix)(From.m_aValues));
	        	
	        }else if(m_aValues instanceof p_float){
	                ((p_float)m_aValues).value = ((p_float)(From.m_aValues)).value;
	        	
	        }else if(m_aValues instanceof p_int){
	                ((p_int)m_aValues).value = ((p_int)(From.m_aValues)).value;
	        	
	        }else if(m_aValues instanceof p_String){
	                ((p_String)m_aValues).value = ((p_String)(From.m_aValues)).value;
        	
	        }

		
		}catch(IllegalAccessException e){
			HimawariLogger.outputException( e );
			assert(false);
		}catch(InstantiationException ie){
			HimawariLogger.outputException( ie );
			assert(false);
		}

	}
	/**
	 * イコール演算子
	 * 代入元が持つVectorの値を全て自分自身のVectorにコピーする
	 * 
	 * @param From 代入元インスタンス
	 * @return 自分自身
	 */
	public  CqParameterTypedConstant<T,SLT> assignment(CqParameterTypedConstant<T,SLT> From){
		if(m_aValues instanceof CqVector3D){
			
			((CqVector3D)m_aValues).assignment((CqVector3D)(From.m_aValues));
			
		}else if(m_aValues instanceof CqVector4D){
			((CqVector4D)m_aValues).assignment((CqVector4D)(From.m_aValues));
			
		}else if(m_aValues instanceof CqColor){
			((CqColor)m_aValues).assignment((CqColor)(From.m_aValues));
			
		}else if(m_aValues instanceof CqMatrix){
			((CqMatrix)m_aValues).assignment((CqMatrix)(From.m_aValues));
			
		}else if(m_aValues instanceof p_float){
			((p_float)m_aValues).value = ((p_float)(From.m_aValues)).value;
			
		}else if(m_aValues instanceof p_int){
			((p_int)m_aValues).value = ((p_int)(From.m_aValues)).value;
			
		}else if(m_aValues instanceof p_String){
			((p_String)m_aValues).value = ((p_String)(From.m_aValues)).value;
			
		}
		

		return this;
	}
	/**
	 * デストラクタ
	 */
	public void destruct(){
		super.destruct();
	}
	
	/**
	 * 自分が持つ値m_aValuesを返す
	 * 配列は１つの値しか持たない
	 */
	public Object[] pValue() {
		Object[] retval = new Object[1];
		retval[0] = m_aValues;
		return retval;
	}

	/**
	 * 自分が持つ値m_aValuesを返す
	 * 配列は１つの値しか持たない
	 */
	public Object[] pValue(final int Index) {
		Object[] retval = new Object[1];
		retval[0] = m_aValues;
		return retval;
	}

	//nttdata chenge
	public T pValue_get(final int Index ,final int arrayIndex)
	{
		return m_aValues;
	}
	/**
	 * Typeの同じインスタンスを生成して返す
	 * 
	 * @param Name 名前
	 * @param Count カウント
	 * @return 新しいCqParameter
	 */
	public CqParameter CloneType(final String Name, int Count) {
		return ( new CqParameterTypedConstant<T,SLT>( Name, Count,I,TClass,SLTClass) );
	}
	
	/**
	 * 自分自身の複製を生成して返す
	 */
	public CqParameter Clone() {
		return ( new CqParameterTypedConstant<T,SLT>( this , I ) );		
	}
	/**
	 * 自分のEqVariableClassを返す
	 *
	 * @return 自分のEqVariableClass
	 */

	public EqVariableClass Class() {
		return new EqVariableClass(EqVariableClass.class_constant);
	}

	/**
	 * 自分のEqVariableTypeを返す
	 * @return 自分のEqVariableType
	 */
	public EqVariableType Type() {
		return I;
	}

	/**
	 * 空メソッド
	 */
	public void SetSize(int size) {

	}
	/**
	 * 常に１を返す
	 */
	public int Size() {
		
		return 1;
	}
	/**
	 * 空メソッド
	 */
	public void 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() );

        CqParameterTypedConstant<T,SLT> pTResult1 = (CqParameterTypedConstant<T,SLT>)( pResult1 );
        CqParameterTypedConstant<T,SLT> pTResult2 = (CqParameterTypedConstant<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 constant 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.
        int i;
        long max = Math.max( (long)(u * v), pResult.Size() );
        
        //Genericsに入る型によって場合わけを行う
        if(m_aValues instanceof CqMatrix){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqMatrix)m_aValues, i );
            }
        }else if(m_aValues instanceof CqVector3D){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqVector3D)m_aValues, i );
            }
        }else if(m_aValues instanceof CqVector4D){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( new CqVector3D(((CqVector4D)(m_aValues))), i );
            }
        }else if(m_aValues instanceof CqColor){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( (CqColor)m_aValues, i );
            }
        }else if(m_aValues instanceof p_float){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_float)m_aValues).value, i );
            }
        }else if(m_aValues instanceof p_int){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_int)m_aValues).value, i );
            }
        }else if(m_aValues instanceof p_String){
            for ( i = 0; i < max; i++ ){
                pResult.SetValue( ((p_String)m_aValues).value, i );
            }
        }
	}
	
	/**
	 * 常に失敗する関数
	 */
	public void DiceOne(int u, int v, IqShaderData pResult, IqSurface pSurface,
			int ArrayIndex) {
		assert( false );

	}
	
	/**
	 * 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 CqParameterTypedConstant<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 CqParameterTypedConstant.<T,SLT>Create(strName,1,I,TClass,SLTClass);
     }
	
	/**
	 * 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( idxTarget )[0];//ポインタなので値を取り出す
//        if(tmp instanceof CqMatrix){
//        	((CqMatrix)tmp).assignment((CqMatrix)(pFromTyped.pValue( idxSource )[0]));
//        }else if(tmp instanceof CqVector3D){
//        	((CqVector3D)tmp).assignment((CqVector3D)(pFromTyped.pValue( idxSource )[0]));
//        }else if(tmp instanceof CqVector4D){
//        	((CqVector4D)tmp).assignment((CqVector4D)(pFromTyped.pValue( idxSource )[0]));
//        }else if(tmp instanceof CqColor){
//        	((CqColor)tmp).assignment((CqColor)(pFromTyped.pValue( idxSource )[0]));
//        }else if(tmp instanceof p_float){
//        	((p_float)tmp).value = ((p_float)(pFromTyped.pValue(idxSource)[0])).value;
//        }else if(tmp instanceof p_int){
//        	((p_int)tmp).value = ((p_int)(pFromTyped.pValue(idxSource)[0])).value;
//        }else if(tmp instanceof p_String){
//        	((p_String)tmp).value = ((p_String)(pFromTyped.pValue(idxSource)[0])).value;
//        }
//	}
     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(idxSource)[0])).value;
         }else if(tmp instanceof p_int){
         	((p_int)tmp).value = ((p_int)(pFromTyped.pValue(idxSource)[0])).value;
         }else if(tmp instanceof p_String){
         	((p_String)tmp).value = ((p_String)(pFromTyped.pValue(idxSource)[0])).value;
         }
 	}
}
