/*
 * $Id: DDAInfo.java,v 1.5 1999/09/28 13:48:01 yamauchi Exp $
 *     (M\pi)^2 : DDAInfo (Digital Difference Analyzer) 
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	@author YAMAUCHI Hitoshi 山内 斉
 *	
 * original source ddaInfo.h
 * 
 * 1999年7月30日(金)
 * 
 */

package jp.ac.tohoku.is.archi.mpi2.dda;

import  jp.ac.tohoku.is.archi.mpi2.dda.DIR_3D;
import  jp.ac.tohoku.is.archi.mpi2.util.Assert;
import  jp.ac.tohoku.is.archi.mpi2.util.Encodable;
import  jp.ac.tohoku.is.archi.mpi2.util.Vector3;
import  jp.ac.tohoku.is.archi.mpi2.util.ObjectDecoder;

/**
 * DDA のための情報を保持するクラス
 */
public class DDAInfo 
implements DIR_3D, Encodable
{
    // DDAの計算がなされたか mDDAsetVolID >= 0 の時には計算されている 
    // volume の場合には volume ID が入っている。 
    private boolean    	  mIsInit;	// false の時には初期化されていない
    private Vector3 	  mRelativePos;	// セル中心からの相対座標
    private Vector3 	  mDDAVec;	// DDAの進行ベクトル
    private int     	  mTraverseAxis;// 進行軸 (Vector3::Direction)
    private int   	  mGoingdir;	// 実際に進む方向を 6 方向で示す

    public DDAInfo()
    {
	this.mIsInit		= false;
	this.mRelativePos	= new Vector3();
	this.mDDAVec		= new Vector3();
	this.mTraverseAxis	= -1;
	this.mGoingdir		= DIR_3D.ILLEGAL; 
    }

    public DDAInfo(DDAInfo rhs)
    {
	this.mIsInit		= rhs.mIsInit;
	this.mRelativePos	= new Vector3(rhs.mRelativePos);
	this.mDDAVec		= new Vector3(rhs.mDDAVec);
	this.mTraverseAxis	= rhs.mTraverseAxis; 
	this.mGoingdir		= rhs.mGoingdir;
    }

    // for decorder 
    private DDAInfo(boolean isinit, 
		    Vector3 relativepos,
		    Vector3 ddavec,
		    int     traverseaxis,
		    int     goingdir)
    {
	this.mIsInit		= isinit;
	this.mRelativePos	= relativepos;
	this.mDDAVec		= ddavec;
	this.mTraverseAxis	= traverseaxis; 
	this.mGoingdir		= goingdir;
    }

    public boolean equals(Object obj)
    {
	if(obj instanceof DDAInfo)
	{
	    DDAInfo rhs = (DDAInfo)obj;
	    return((this.mIsInit	== rhs.mIsInit)		  &&
		   (this.mRelativePos.	equals(rhs.mRelativePos)) &&
		   (this.mDDAVec.	equals(rhs.mDDAVec))	  &&
		   (this.mTraverseAxis	== rhs.mTraverseAxis)	  &&
		   (this.mGoingdir	== rhs.mGoingdir));
	}else
	{
	    return(false);
	}
    }

    public void invalidateInit()	
    {
	this.mIsInit		= false;
	this.mRelativePos.set(-1.0, -2.0, -3.0);	
	this.mDDAVec.set(-1.0, -2.0, -3.0);	
	this.mTraverseAxis	= -2;
	this.mGoingdir		= DIR_3D.ILLEGAL;
    }

    //----- get functions
    public boolean    isDDAinited() 	{ return(this.mIsInit);		}
    public Vector3 peekRelativePos()	{ return(this.mRelativePos);	}
    public Vector3 peekDDAVec()  	{ return(this.mDDAVec);		}
    public int     getTravAxis()  	{ return(this.mTraverseAxis);	}
    public int     getGoingDir()  	{ return(this.mGoingdir);	}
    
    //----- set functions
    public void setDDAset()
    {
	if(this.mIsInit == true)
	{
	    throw new RuntimeException("Warning: 3DDDAA Info is already " +
				       "initialized.");
	}
	this.mIsInit = true;	
    }
    public void setRelativePos(Vector3 rpos){ this.mRelativePos = rpos;	}


    /**
     * 相対位置の変更(進行方向に直交するセル平面との交わり位置)
     * 方向 dir1 に d1 の相対位置,  dir2 の方向に d2 の位置
     */
    public void changeRelativePos(double d1,  int dir1,
				  double d2,  int dir2)
    {
	final String msg = "Error!: illegal Vector3 direction dir at " +
	    "DDAInfo::changeRelativePos";

	double [] p = new double[3];
    
	p[Vector3.X] = this.mRelativePos.get(Vector3.X);
	p[Vector3.Y] = this.mRelativePos.get(Vector3.Y);
	p[Vector3.Z] = this.mRelativePos.get(Vector3.Z);
    
	// ここは何故
	//  p[dir1] = d1;
	//  p[dir2] = d2;
	// にしなかったんだろうか．忘れた dir1 と配列の添え字が一致す
	// ると限らないからかな． FIXHERE
	switch(dir1)
	{
	case Vector3.X: 
	    p[Vector3.X] = d1;	break;
	case Vector3.Y:
	    p[Vector3.Y] = d1;	break;
	case Vector3.Z:
	    p[Vector3.Z] = d1;	break;
	default:
	    throw new RuntimeException(msg + "1");
	}
    
	switch(dir2)
	{
	case Vector3.X:
	    p[Vector3.X] = d2;	break;
	case Vector3.Y:
	    p[Vector3.Y] = d2;	break;
	case Vector3.Z:
	    p[Vector3.Z] = d2;	break;
	default:
	    throw new RuntimeException(msg + "2");
	}
	this.mRelativePos.setByArray(p);
    }

    public void setDDAVec(Vector3 aDDA) { this.mDDAVec = aDDA;		}
    public void setTravAxis(int aV)	{ this.mTraverseAxis = aV; 	}
    public void setGoingDir(int goingdir)
    {
	Assert.out(goingdir <=  DIR_3D.ILLEGAL, "Error! : setGoingDir");
	    
	this.mGoingdir = goingdir;
    }
    
    public String  toString(String head)
    {
	String s = head + "----- 3DDDA Info. ----- calc is already do:" 
	    + ((this.mIsInit == true) ? "YES " : "NO ");
	s += head + "relPos(" + this.mRelativePos + ")\n";
	s += head + "DDAVec(" + this.mDDAVec      + ")\n";    
	s += head + "travAxis:" + this.mTraverseAxis 
	    + " goingDir:" + this.mGoingdir;
	return(s);
    }

    /**------------------------------------------------------------
     * Encodable implementation
     *------------------------------------------------------------*/
    private static final int mSizeInDouble = 
      1 +				// boolean mIsInit;
      Vector3.ZERO.sizeInDouble() + 	// Vector3 mRelativePos;
      Vector3.ZERO.sizeInDouble() + 	// Vector3 mDDAVec;
      1 +				// int     mTraverseAxis;
      1;				// int     mGoingdir;

    public int sizeInDouble()
    {
	return(mSizeInDouble);
    }
    
    public void encodeInDouble(double[] array, int offset)
    {
	int idx = 0;

	// mIsInit
	array[offset + idx] = (this.mIsInit == true) ? 1 : 0; // true = 1
	idx += 1;
	
	// mRelativePos 
	this.mRelativePos.encodeInDouble(array, offset + idx);
	idx += this.mRelativePos.sizeInDouble();
	
	// mDDAVec
	this.mDDAVec.encodeInDouble(array, offset + idx);
	idx += this.mDDAVec.sizeInDouble();
	
	// mTraverseAxis;
	array[offset + idx] = (double)(this.mTraverseAxis);
	idx += 1;
	
	// mGoingdir;
	array[offset + idx] = (double)(this.mGoingdir);
	// idx += 1;	
    }

    /*
     * Implements ObjectDecoder for DDAInfo
     */
    private static class DDAInfoObjectDecoder implements ObjectDecoder 
    {
    	public int sizeInDouble() 
	{
	    return(mSizeInDouble);
	}
    	public Object decodeFromDouble(double[] array, int offset)
	{
	    int idx = 0;

	    // mIsInit
	    boolean isinit = (array[offset] == 1) ? true : false;
	    idx += 1;

	    // mRelativePos
	    Vector3 relativepos = (Vector3)
		Vector3.getObjectDecoder().decodeFromDouble(array, 
							    offset + idx);
	    idx += relativepos.sizeInDouble();
	    
	    // mDDAVec
	    Vector3 ddavec = (Vector3)
		Vector3.getObjectDecoder().decodeFromDouble(array, 
							    offset + idx);
	    idx += ddavec.sizeInDouble();

	    // mTraverseAxis
	    int traverseaxis = (int)array[offset + idx];
	    idx += 1;
	    
	    // mGoingdir
	    int goingdir = (int)array[offset + idx];
	    
	    // new DDAInfo
	    return(new DDAInfo(isinit, relativepos, ddavec, 
			       traverseaxis, goingdir));
	}
    }
    private final static ObjectDecoder mODInstance =new DDAInfoObjectDecoder();
    public static ObjectDecoder getObjectDecoder() 
    {
	return(mODInstance);
    }
}



