/**
 * $Id: IntVec3.java.scaler,v 1.1.2.1 2000/06/15 14:11:43 yamauchi Exp $
 *     (M\pi)^2 Integer Vector class 
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	@author YAMAUCHI Hitoshi 山内 斉
 *
 * original source IntVec3.h, IntVec3.cc
 */

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

// import  mpi.MPI;

public final class IntVec3 
implements Encodable
{
    /**
     * indicate 1st element of IntVec3
     */
    public final static int X = 0;

    /**
     * indicate 2nd element of IntVec3
     */
    public final static int Y = 1;

    /**
     * indicate 3rd element of IntVec3
     */
    public final static int Z = 2;


    private final static int NElem = 3;	// Number of vector elements
    private int   mX;			// elements of this class
    private int   mY;			
    private int   mZ;			
    
    /**
     * zero 
     */
    public final static IntVec3 ZERO = new IntVec3(0, 0, 0);

 
    /**
     * Allocates a new IntVec3 object
     */
    public IntVec3()
    {
	this.set(0, 0, 0);
    }

    /**
     * Allocate a new IntVec3 object and initialize by x, y, z
     * 
     * @param x 
     * @param y
     * @param z
     */
    public IntVec3(int x, int y, int z)
    {
	this.set(x, y, z);
    }

    /**
     * Allocate a new IntVec3 object and initialize by ivec
     * ivec.length must be 3
     *
     * @param ivec
     */
    public IntVec3(int [] ivec)
    {
	this.setByArray(ivec);
    }

    /**
     * Allocate a new IntVec3 object and initialize by other IntVec3
     */
    public IntVec3(IntVec3 rhs)
    {
	this.mX = rhs.mX;
	this.mY = rhs.mY;
	this.mZ = rhs.mZ;    	
    }

    /**
     * これは危険あり．精度が落ちる
     */
//     public IntVec3(Vector3 rhs)
//     {
// 	this.mE = new int[NElem];
// 	this.mX = rhs.get(IntVec3.X);
// 	this.mY = rhs.get(IntVec3.Y);
// 	this.mZ = rhs.get(IntVec3.Z);    	
//     }


    /**
     * set contents of this vector
     */
    public void set(int x, int y, int z)
    {
	this.mX = x;
	this.mY = y;
	this.mZ = z;    
    }

    public void set(IntVec3 rhs)
    {
	this.mX = rhs.mX;
	this.mY = rhs.mY;
	this.mZ = rhs.mZ;    
    }


    /**
     * get nth element of this vector
     */
    public int get(int nth)
    {
	switch(nth)
	{
	case IntVec3.X:
	    return(this.mX);
	case IntVec3.Y:
	    return(this.mY);
	case IntVec3.Z:
	    return(this.mZ);
	default:
	    throw new RuntimeException("Error! : IntVec3.get, illegal nth");
	}
    }

    /**
     * set vector elements with int array
     */
    public void setByArray(int [] v)
    {
	this.mX = v[IntVec3.X];
	this.mY = v[IntVec3.Y];
	this.mZ = v[IntVec3.Z];
    }

    /**
     * get vector elements as int array
     */
    public int [] getNewAsArray()
    {
	int [] ret = new int[IntVec3.NElem];
	ret[IntVec3.X] = this.mX;
	ret[IntVec3.Y] = this.mY;
	ret[IntVec3.Z] = this.mZ;
	return(ret);
    }


    /** 
     * plus operator
     */
    public IntVec3 plusNew(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	ret.mX = this.mX + rhs.mX;
	ret.mY = this.mY + rhs.mY;
	ret.mZ = this.mZ + rhs.mZ;
	return(ret);	
    }

    public void plusHere(final IntVec3 rhs)
    {
	this.mX += rhs.mX;
	this.mY += rhs.mY;
	this.mZ += rhs.mZ;
    }

    /** 
     * minus operator
     */
    public IntVec3 minusNew(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	ret.mX = this.mX - rhs.mX;
	ret.mY = this.mY - rhs.mY;
	ret.mZ = this.mZ - rhs.mZ;
	return(ret);	
    }

    public void minusHere(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	this.mX -= rhs.mX;
	this.mY -= rhs.mY;
	this.mZ -= rhs.mZ;
    }

    /**
     * compare with rhs value
     *-- ここはハマった．Map のキーとして利用できるものは，hashCode() と 
     *-- equals の一貫性がとれていれば OK というにもかかわらず，どうして
     *-- もキーから引けない．前田さんが気付いたのであるが，私はここを，
     *--	    public boolean equals(IntVec3 rhs)
     *-- としていた．これでは，
     *--	    public boolean equals(Object  rhs);
     *--	    public boolean equals(IntVec3 rhs);
     *-- という2つの関数があるだけで，最初のものを overload していない．
     *-- 1 日悩んだバグだった． 1999年9月 6日(月) 山内 斉 
     */
    public boolean equals(Object obj)
    {
	if (obj instanceof IntVec3) 
	{
	    IntVec3 rhs = (IntVec3) obj;
	    return((this.mX == rhs.mX) &&
		   (this.mY == rhs.mY) &&
		   (this.mZ == rhs.mZ));
	} else 
	{
	    return false;
	}
    }
    
    /**
     * convert to String representation of this class
     */
    public String toString()
    {
	return(Integer.toString(this.mX) + "\t" + 
	       Integer.toString(this.mY) + "\t" + 
	       Integer.toString(this.mZ));
    }

    /**
     * return hash code for Space Subdivision
     * 	部分空間番号 -> Object List を返す
     *  単に Y を 8 lbit, Z を 16 bit ずらして bitwise or であるが，こ
     *  れで十分だと思う．
     */
    public int hashCode() 
    {
	return(this.mX + (this.mY << 8) + (this.mZ << 16));
    }


    /*
     * Implements Encodable
     */
    public int sizeInDouble() 
    {
	return(3);
    }
    public void encodeInDouble(double[] array, int offset) 
    {
	array[offset] 		= this.mX;
	array[offset + 1] 	= this.mY;
	array[offset + 2] 	= this.mZ;
    }

    /*
     * Implements ObjectDecoder
     */
    private static class IntVec3ObjectDecoder implements ObjectDecoder 
    {
    	public int sizeInDouble() 
	{
	    return(3);
	}
    	public Object decodeFromDouble(double[] array, int offset)
	{
	    return new IntVec3((int)(array[offset]), 
			       (int)(array[offset + 1]), 
			       (int)(array[offset + 2]));
	}
    }
    private final static ObjectDecoder mODInstance 
    	= new IntVec3ObjectDecoder();
    public static ObjectDecoder getObjectDecoder() 
    {
	return(mODInstance);
    }

    /*
     * test Encodable
     */
    public static void main(String [] arg)
    {
	// serialize
	IntVec3 [] iv = new IntVec3[16];
	for(int i = 0; i < iv.length; i++)
	{
	    iv[i] = new IntVec3(i, i * 2, i * 3);
	}
	EncodedData sendBuf = Marshal.createEncodedData(iv);
	System.out.println("sendBuf " + sendBuf.length());

	// deserialize
	EncodedData recvBuf = 
	    Marshal.createEncodedData(IntVec3.getObjectDecoder(), 24);
	double [] sendary = (double [])sendBuf.getArray();
	double [] recvary = (double [])recvBuf.getArray();
	for(int i = 0 ; i < sendBuf.length(); i++)
	{
	    System.out.println(sendary[i]);
	    recvary[i] = sendary[i];
	}

	IntVec3 [] recIV = new IntVec3[24];
	Decoder decoder = recvBuf.getDecoder();

	for (int i = 0; i < 16; i++) 
	{
	    recIV[i] = (IntVec3)decoder.decode(IntVec3.getObjectDecoder());
	}

	for (int i = 0; i < 16; i++) 
	{
	    System.out.println("deserialized " + recIV[i]);
	}	
	// System.out.println("true " + true + ", false " + false);	
	// Class c = IntVec3.class;
    }
}
