/*
 Global.java
 Copyright (C) 2003 Gerardo Horvilleur Martinez

 This program 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 program 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 program; 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.parser;

import java.util.HashMap;
import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.primitive.p_int;
import net.cellcomputing.himawari.library.EqVariableType;
import net.cellcomputing.himawari.util.HimawariLogger;
import static net.cellcomputing.himawari.parser.Parser.*;
import static net.cellcomputing.himawari.library.RendermanInterface.*;
import static net.cellcomputing.himawari.library.EqVariableType.*;
import static java.lang.Math.max;
import static java.lang.Math.min;


/**
 * Parse部分のグローバルなメソッド、およびフィールド変数
 * 
 * 
 * @author NTT DATA Corporation
 */
public strictfp class Global {
	
	
	/**
	 * 定義済みのパラメータとパラメータ型をマップにセットする。
	 * 
	 */
	public static void StandardDeclarations(  )
	{
		int i = 0;
		while(  StandardParameters[ i ][ 0 ] != null ){
			String name =  StandardParameters[ i ][ 0 ] ;
			String type =  StandardParameters[ i ][ 1 ] ;
			Parser.ParserDeclare( name, type );
			i++;
		}
	}
	
	/**
	 * フレームの呼び飛ばし
	 * 
	 * 
	 * @param number	読み飛ばしする数
	 * @return	読み飛ばしの可/不可
	 */
	public static STLVector<Integer>	FrameList = new STLVector<Integer>(Integer.class);
	public static boolean IsFrameSkipped(int number)
	{
		// Check the frame list to see if the requested frame is included.
		if(FrameList.size() == 0)
			return(false);
		else if(FrameList.size() <= number)
			return(true);
		else if(FrameList.get(number) != 0 )
			return(false);
		else
			return(true);
	}

	/**
	 * フレームリストをクリア
	 * 
	 */
	public static void ClearFrames()
	{
		FrameList.clear();
	}

	/**
	 * フレームを追加
	 * 
	 * 
	 * @param frames
	 * @return
	 */
	public static int AppendFrames(String frames)
	{
		int n=0;
		int length = frames.length();
		p_int endptr = new p_int();
		int nptr = 0;
		while(n < length)
		{
			int f1, f2;
			f1 = strtol( frames.substring(nptr), endptr );
			// if(endptr.value != nptr)
			if(endptr.value != 0)
			{
				n += endptr.value;
				// Check for a range.
				if(endptr.value<length && frames.charAt(endptr.value) == '-'){
					nptr = endptr.value+1;
					n+=1;
					f2 = strtol( frames.substring(nptr), endptr );
					if(endptr.value != 0)
					{
						n += endptr.value;
						// Store the range between f1 and f2;
						if(FrameList.size() <= max(f1, f2))
							// FrameList.resize(max(f1, f2)+1, 0);
							FrameList.resize(max(f1, f2)+1);
						int start = min(f1, f2);
						int end = max(f1, f2);
						int i;
						
						//Check start >=0
						if( start < 0 ){
							HimawariLogger logger = HimawariLogger.getLogger();
							logger.error("Invalid frame number "+start+" was specified. \n");
							continue;
						}
						
						for(i = start; i <= end; i++)
							FrameList.set( i, 1 );
						nptr = endptr.value;
					}
				}
				else{
					//Check start >=0
					if( f1 < 0 ){
						HimawariLogger logger = HimawariLogger.getLogger();
						logger.error("Invalid frame number "+f1+" was specified. \n");
						FrameList.resize(1);
						continue;
					}
					
					// store the single frame value
					if(FrameList.size() <= f1)
						// FrameList.resize(f1+1, 0);
						FrameList.resize(f1+1);
					FrameList.set( f1, 1 );
					nptr += endptr.value;
				}
			}
			else if(frames.charAt(nptr + endptr.value) == ','){
				n += 1;
				nptr += 1;
			}
			else{
				return(-1);
			}
		}
		return 0;
	}
	
	private static int strtol( String str, p_int endpos  )
	{
		int ret = 0;
		
		// 前後の空白を削除
		String p = str.trim();
		String ch = "";
        int length		= p.length();
        int end_index	= length;
        int start_index	= 0;
        
        boolean sign_found = false;
        
        for( int i=0; i<length; i++ ){
        	// １文字ずつ取り出して
        	ch = p.substring( i, i+1 );
        	
            // 数値として認識できる最初の文字の位置を探す
            if( ch.matches("[0-9]") || (!sign_found && ch.equals("-")) ){
            	if( !sign_found ){
            		sign_found = true;
            		start_index = i;
            	}
            }
            // 数値として認識できる最後の文字の位置を探す
            else{
                if( sign_found ){
                    end_index = i;
                    break;
                }
                else{
                	break;
                }
            }
            
        }// end of for(p)
     
        // 数値に変換
        try {
            ret = Integer.parseInt( p.substring(start_index,end_index) );
            endpos.value = start_index + end_index;
            
            int sp_index = str.indexOf(' ');
            if( sp_index!=-1 && sp_index<end_index ) endpos.value += sp_index+1;
            return ret;

        } catch (NumberFormatException e) {
        	// e.printStackTrace();
        	endpos.value = 0;
            return 0;
        }
		
	}


	//光源ハンドル、およびオブジェクトハンドル格納用のハッシュマップ
	public static HashMap<Integer, Object> LightMap = new HashMap<Integer, Object>();
	public static HashMap<String, Object> LightMapString = new HashMap<String, Object>();
	public static HashMap<Integer, Object> ObjectMap = new HashMap<Integer, Object>();
	public static HashMap<String, Object> ObjectMapString = new HashMap<String, Object>();
	
	//パラメータタイプ格納用ハッシュマップ
	private static HashMap<String, EqVariableType> TypeMap = new HashMap<String, EqVariableType>();
	private static HashMap<String, Integer> ValueMap = new HashMap<String, Integer>();
	private static HashMap<String, Boolean> TipMap = new HashMap<String, Boolean>();
	
	/**
	 * 光源ハンドルのセッタ。
	 * keyが数字(int)のとき
	 * 
	 * @param ID	マップのkey
	 * @param Handle	セットするハンドル
	 * @throws Exception
	 */
	public static void DeclareLightHandle( final int ID, final Object Handle) throws Exception
	{
		if( Handle == null )
			throw new Exception("NULL Light Handle");
		
		LightMap.put( ID, Handle );
	}

	/**
	 * 光源ハンドルのゲッタ。
	 * keyが数字(int)のとき
	 * 
	 * @param ID	マップのkey
	 * @return	keyに対応するハンドル
	 * @throws Exception
	 */
	public static Object LookupLightHandle( final int ID) throws Exception
	{
		Object handler = LightMap.get( ID );
		if( handler == null )
				throw new Exception("Undeclared Light ID");
	
		return handler;
	}

	/**
	 * 光源ハンドルのセッタ。
	 * keyが文字列(String)のとき
	 * 
	 * @param ID	マップのkey
	 * @param Handle	セットするハンドル
	 * @throws Exception
	 */
	public static void DeclareLightHandleString( final String ID, final Object Handle) throws Exception
	{
		if( Handle == null )
			throw new Exception("NULL Light Handle");
		
		LightMapString.put( ID, Handle );
	}

	/**
	 * オブジェクトハンドルのゲッタ
	 * keyが文字列(String)のとき
	 * 
	 * @param ID	マップのkey
	 * @return	keyに対応するハンドル
	 * @throws Exception
	 */
	public static Object LookupLightHandleString( final String ID) throws Exception
	{
		Object handler = LightMapString.get( ID );
		if( handler == null )
				throw new Exception("Undeclared Light name");
	
		return handler;
	}

	/**
	 * オブジェクトハンドルのセッタ。
	 * keyが数字(int)のとき
	 * 
	 * @param ID	マップのkey
	 * @param Handle	セットするハンドル
	 * @throws Exception
	 */
	public static void DeclareObjectHandle( final int ID, final Object Handle) throws Exception
	{
		if( Handle == null )
			throw new Exception("NULL Object Handle");
		
		ObjectMap.put( ID, Handle );
	}

	/**
	 * オブジェクトハンドルのゲッタ。
	 *  keyが数字(int)のとき
	 * 
	 * @param ID	マップのkey
	 * @return	keyに対応するハンドル
	 * @throws Exception
	 */
	public static Object LookupObjectHandle( final int ID) throws Exception
	{
		Object handler = ObjectMap.get( ID );
		if( handler == null )
				throw new Exception("Undeclared Object ID");
	
		return handler;
	}

	/**
	 * オブジェクトハンドルのセッタ。
	 * keyが文字列(String)のとき
	 * 
	 * @param ID	マップのkey
	 * @param Handle	keyに対応するハンドル
	 * @throws Exception
	 */
	public static void DeclareObjectHandleString( final String ID, final Object Handle) throws Exception
	{
		if( Handle == null )
			throw new Exception("NULL Object Handle");
		
		ObjectMapString.put( ID, Handle );
	}

	/**
	 * オブジェクトハンドルのゲッタ。
	 * keyが文字列(Stringのとき)
	 * 
	 * @param ID	マップのkey
	 * @return	keyに対応するハンドル
	 * @throws Exception
	 */
	public static Object LookupObjectHandleString( final String ID) throws Exception
	{
		Object handler = ObjectMapString.get( ID );
		if( handler == null )
				throw new Exception("Undeclared Object name");
	
		return handler;
	}

	/**
	 * パラメータタイプのセッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名
	 * @param type	パラメータ型
	 * @return	パラメータ型。
	 * @throws Exception
	 */
	public static EqVariableType DeclareParameterType( final String Name, final String Type )
	{
		if( Name == null || Name.length() == 0 )
			HimawariLogger.getLogger().error ("Cannot Declare Unnamed Type\n");

		EqVariableType type = ParseParameterType( Type );
		if( DeclareParameterValue( Name ) <= 0 )
			return new EqVariableType( type_invalid );
		
		if( type.getValue() != type_invalid )
			TypeMap.put( Name, type );
		
		return type;
	}

	/**
	 * パラメータタイプのゲッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名	
	 * @return	keyの対応するパラメータタイプ
	 * @throws Exception
	 */
	public static EqVariableType LookupParameterType( final String name ) 
	{
		if( name == null || name.length() == 0 ){
			HimawariLogger.getLogger().error ("Cannot Lookup Unnamed Type\n");
			return new EqVariableType( type_invalid );
		}
		
		EqVariableType type = TypeMap.get( name );
		if( type != null )
			return type;
	
		return	Parser.ParseParameterType( name ); 
	}
	
	/**
	 * パラメータバリューのセッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名。
	 * @return	パラメータ数。
	 * @throws Exception
	 */
	public static int DeclareParameterValue( final String Name )
	{	
		int size = getParameterSize();
		if( size > 0 ) {
			ValueMap.put( Name, size );
			DeclareParameterTip( Name );
		}
		
		return size;
	}

	/**
	 * パラメータバリューのゲッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名	
	 * @return	keyの対応するパラメータ数
	 * @throws Exception
	 */
	public static int LookupParameterValue( final String name ) 
	{
		if( name == null || name.length() == 0 ){
			HimawariLogger.getLogger().error ("Cannot Lookup Unnamed Value\n");
			return -1;
		}
		
		Integer value = ValueMap.get( name );
		if( value != null )
			return value.intValue();
		
		return	getParameterSize(); 
	}

	/**
	 * パラメータクラスのセッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名。
	 * @return	パラメータクラスを示すboolean。
	 * @throws Exception
	 */
	private static void DeclareParameterTip( final String Name )
	{	
		TipMap.put( Name, getParameterTip() );
	}


	/**
	 * パラメータバリューのゲッタ。
	 * keyは文字列。
	 * 
	 * @param name	パラメータ名	
	 * @return	keyの対応するパラメータパラメータクラスを示すboolean
	 * @throws Exception
	 */
	public static boolean LookupParameterTip( final String name ) 
	{
		Boolean tip = TipMap.get( name );
		if( tip != null )
			return tip.booleanValue();
		
		return	getParameterTip(); 
	}
	
	/**
	 * パラメータタイプのハッシュマップをクリア。
	 * プライベートメソッド呼び出し
	 * 
	 */
	public static void CleanupDeclarations(  )
	{
		ClearDeclarations();
	}

	/**
	 * パラメータタイプのハッシュマップをクリア。
	 * 
	 */
	private static void ClearDeclarations(  )
	{
		TypeMap.clear();
	}

	/**
	 * 引数に与えられた文字列に対応するフィルタ関数の名前を返す。
	 * 
	 * 
	 * @param type	フィルタ関数を示唆する文字列
	 * @return	フィルタ関数名
	 */
	public static String GetFilterFunction( String type )
	{
		if ( type.equals( "box" ) )
			return "RiBoxFilter";
		else if ( type.equals( "gaussian" ) )
			return "RiGaussianFilter";
		else if ( type.equals( "triangle" ) )
			return "RiTriangleFilter";
		else if ( type.equals( "catmull-rom" ) )
			return "RiCatmullRomFilter";
		else if ( type.equals( "sinc" ) )
			return "RiSincFilter";
		else if ( type.equals( "bessel" ) )
			return "RiBesselFilter";
		else if ( type.equals( "disk" ) )
			return "RiDiskFilter";
		else 
			return "RiBoxFilter";
	}

}
