// 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 static net.cellcomputing.himawari.library.EqCSGNodeType.CSGNodeType_Primitive;
import static net.cellcomputing.himawari.library.EqCSGNodeType.CSGNodeType_Union;

import java.util.ArrayList;
import java.util.Iterator;

import net.cellcomputing.himawari.accessory.STLVector;


/**
 *   
 *	Base CSG node class.
 *	Handles all linkage and basic processing, derived classes provide operation specific details.
 *  全てのリンケージと基本のプロセスを舵取りする。 派生しているクラスは操作の特定の詳細を明らかにします。
 *
 * @author NTT DATA Corporation
 */
public abstract strictfp class CqCSGTreeNode {


	private CqCSGTreeNode m_pParent;	//Pointer to the parent CSG node.			
	private ArrayList<CqCSGTreeNode> m_lChildren = new ArrayList<CqCSGTreeNode>();	//List of children nodes.
	private static boolean m_bCSGRequired; //Tell imagebuffer the processing for CSG is not required
	

	/** default constructer */
	public CqCSGTreeNode()
	{}
	
	/** destructer */
	public void destruct()
	{}
	
    /**
     *  Get a reference to the list of children of this node.
     *  子どものノードリストを返す。
     *  @return m_lChildren 子どものノード(リスト)
     */
    public ArrayList<CqCSGTreeNode> lChildren()
    {
        return ( m_lChildren );
    }
    
	/**
	 *  Get the type identifier for this CSG node, overridded per derived node.
	 *  CSGのタイプ識別子を得る。 > EqCSGNodeType
	 *  実際の機能は、派生クラスによりオーバーライドされている。
	 *  
	 * @return　null
	 */
	public abstract EqCSGNodeType NodeType();

	/**
	 *  Add a child to this node.
	 *  Takes care of unreferencing the parent if not already done.
	 *  ノードリストに子どもを加える。
	 *  
	 * @param node　リストに追加するノード
	 */
	public void AddChild( final CqCSGTreeNode pChild ) {
		lChildren().add( pChild );
		pChild.m_pParent = this;
	}
	
	/**
	 *	Determine if the given node is a child of this one. <br>
	 *	If the node is a child, the index is returned, else -1.
	 *
	 *　　与えられたノードが自分の子どもかどうかを調べる。
	 *
	 *	@param	pNode	調べるCSGノード
	 *	@return			子どもの場合　	：　該当するノードリスト番号<br>
	 *					子どもでない場合： -1
	 */
	public int isChild( final CqCSGTreeNode pNode )
	{
		if ( pNode == null )
			return ( -1 );
		
		int iChild = 0;
		for( CqCSGTreeNode pChild : lChildren() ){
			if( pChild.equals( pNode ) )
				return ( iChild );
			iChild++;
		}		
		return ( -1 );
	}
	
	/** 
	 * 
	 * Get the pointer to the parent CSG node for this node.
	 * 親のCSGノードを返す。
	 * 
	 * @return m_pParent
	 */
	public CqCSGTreeNode pParent()
	{
		return ( m_pParent );
	}

	/**
	 *	Get the number of children.
	 *　　子どもの数を返す。
	 *  
	 *	@return	lChildren().size()　子を格納するリストの要素数
	 */
	public int cChildren()
	{
		return lChildren().size();
	}
    
	/** 
	 *  Evaluate the state of the CSG operation for the given in/out states.
     *  CSG処理が内部　or 外部かを示す状態を返す。
     *  
     * @param abChildStates　状態を示す情報をもった配列
     */
	public abstract boolean EvaluateState( boolean[] abChildStates );
	//Given an array of in/out booleans for each of the children of this node,
    // evaluate the resulting in/out state after applying the operation.
	
	
	/**
	 *　　Pass the sample list through the CSG node.
	 *  The sample list will contain only the relevant entry and exit points for
	 *  the resulting surface for this operation, and they will be promoted to
	 *  this node for further processing up the tree.
	 *
	 *	@param	samples	表面の結合点(入口出口)の配列
	 */
    public void ProcessSampleList( STLVector<SqImageSample> samples ){
    	
    	// First process any children nodes. Process all nodes depth first.
    	for ( CqCSGTreeNode pChild : lChildren() ) //末端の親まで再帰的に呼び出し。
    	{
    		// If the node is a primitive, no need to process it.
    		// In fact as the primitive, just nulls out its owned samples
    		// this would break the CSG code.
    		if ( pChild != null && pChild.NodeType().getValue() != CSGNodeType_Primitive )
    			pChild.ProcessSampleList( samples );
    	}
    	
    	boolean abChildState[] = new boolean[ cChildren() ];
    	int aChildIndex[] = new int[ samples.size() ];
    	
    	// Find out if the camera is starting inside a solid. This is the case if you
    	// see an odd number of walls for that solid when looking out.
    	boolean bCurrentI = false; 
    	int j = 0;
    	for ( SqImageSample i : samples )
    	{
    		if ( ( aChildIndex[ j ]= isChild( i.m_pCSGNode ) ) >= 0 )
    		{
    			//XXX: 保留。入ることはない。Aqsisサイトでの更新待ち。nttdata
    			if (( i.m_pCSGNode.NodeType().getValue() == CSGNodeType_Primitive ) &&
    					( i.m_pCSGNode.NodeType().getValue() == CSGNodeType_Union ) ) 
    			{
    				abChildState[ aChildIndex[ j ]] = !( abChildState[ aChildIndex[ j ]] );
    			}
    		}
    		j++;
    	}
    	bCurrentI = EvaluateState( abChildState );
    	
    	// Now go through samples, clearing any where the state doesn't change, and
    	// promoting any where it does to this node.
    	Iterator<SqImageSample> i = samples.iterator();
    	for( j = 0; i.hasNext(); ++j )
    	{
    		SqImageSample image = i.next();
    		// Find out if sample is in out children nodes, if so are we entering or leaving.
    		if ( aChildIndex[ j ] >= 0 )
    			abChildState[ aChildIndex[ j ]] = !( abChildState[ aChildIndex[ j ]] );
    		else
    			continue;
    		
    		// Work out the new state
    		boolean bNewI = EvaluateState( abChildState );
    		
    		// If it hasn't changed, remove the sample.
    		if ( bNewI == bCurrentI ){
    			i.remove();
    		}
    		else{	
    			// Otherwise promote it to this node unless we are a the top.
    			bCurrentI = bNewI;
    			if ( pParent() != null ){
    				image.m_pCSGNode = this;
    			}
    			else{
    				image.m_pCSGNode = null;
    			}
    		}
    	}    	
    }
	
    
	/**
	 *  Process the CSG tree over the given sample list.
	 *  First goes back up the tree to the top, then starts processing nodes from
	 *  there using ProcessSampleList.
	 *	CSG木の処理。　一番上の親からノードの分類を行う。
	 *
	 *	@param	samples		Array of samples to pass through the CSG tree.
	 */
	public void ProcessTree(STLVector<SqImageSample> samples) {
		//Follow the tree back up to the top, then process the list from there
		CqCSGTreeNode pTop = this;
		
		while ( pTop.pParent() != null ){
			pTop = pTop.pParent();
		}
		pTop.ProcessSampleList( samples );
	}
	
	
	/**
	 *　Static function to create a CSG node from the name.
	 * Used to create a node type from just the name.
	 *  CSG処理の演算名からCSGノードを作成する
	 * 
	 *	@param	type	処理演算を示唆する名前　<br>
	 *                  "primitive","union","intersection","difference" のどれか。
	 *	@return			作成されたノードのインスタンス
	 **/
	public static CqCSGTreeNode CreateNode( String type )
	{
		SetRequired(true);
		if(type == null )
			return null;
		if ( type.equalsIgnoreCase( "primitive" )){
			CqCSGTreeNode csg = new CqCSGNodePrimitive();
			return csg;
		}
		else if ( type.equalsIgnoreCase( "union" )){
			CqCSGTreeNode csg = new CqCSGNodeUnion();
			return csg;
		}
		else if ( type.equalsIgnoreCase( "intersection" ) ){
			CqCSGTreeNode csg = new CqCSGNodeIntersection();
			return csg;
		}
		else if ( type.equalsIgnoreCase( "difference" ) ){
			CqCSGTreeNode csg = new CqCSGNodeDifference();
			return csg;
		}
		else{
			return null;
		}
	}
	
	/**
	 * Get the state of the flag indicating if CSG processing is required at all.
	 * CSG処理の必要性を示すフラグの状態を取得する。
	 * 
	 * @return　m_bCSGRequired　CSG処理の必要性を示す。
	 */
    public static boolean IsRequired(){
    	return m_bCSGRequired;
    }
    
    /**
     * Set the flag indicating CSG is now required.
     * CSG処理の必要性を示すフラグを設定する。
     * 
     * @param value　必要(true) / 不必要(false)  
     */
    public static void SetRequired( boolean value ){
    	 m_bCSGRequired = value;
    }



	
}
