/**
 * $Id: IntVec3.java,v 1.9.4.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   mE[];		// elements of this class

    
    /**
     * zero 
     */
    public final static IntVec3 ZERO = new IntVec3(0, 0, 0);

 
    /**
     * Allocates a new IntVec3 object
     */
    public IntVec3()
    {
	this.mE = new int[NElem];
    }

    /**
     * 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.mE = new int[NElem];
	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.mE = new int[NElem];
	this.setByArray(ivec);
    }

    /**
     * Allocate a new IntVec3 object and initialize by other IntVec3
     */
    public IntVec3(IntVec3 rhs)
    {
	this.mE = new int[NElem];
	this.mE[IntVec3.X] = rhs.mE[IntVec3.X];
	this.mE[IntVec3.Y] = rhs.mE[IntVec3.Y];
	this.mE[IntVec3.Z] = rhs.mE[IntVec3.Z];    	
    }

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


    /**
     * set contents of this vector
     */
    public void set(int x, int y, int z)
    {
	this.mE[X] = x;
	this.mE[Y] = y;
	this.mE[Z] = z;    
    }

    public void set(IntVec3 rhs)
    {
	this.mE[X] = rhs.mE[X];
	this.mE[Y] = rhs.mE[Y];
	this.mE[Z] = rhs.mE[Z];    
    }


    /**
     * get nth element of this vector
     */
    public int get(int nth)
    {
	return(this.mE[nth]);
    }

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

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


    /** 
     * plus operator
     */
    public IntVec3 plusNew(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	ret.mE[IntVec3.X] = this.mE[IntVec3.X] + rhs.mE[IntVec3.X];
	ret.mE[IntVec3.Y] = this.mE[IntVec3.Y] + rhs.mE[IntVec3.Y];
	ret.mE[IntVec3.Z] = this.mE[IntVec3.Z] + rhs.mE[IntVec3.Z];
	return(ret);	
    }

    public void plusHere(final IntVec3 rhs)
    {
	this.mE[IntVec3.X] += rhs.mE[IntVec3.X];
	this.mE[IntVec3.Y] += rhs.mE[IntVec3.Y];
	this.mE[IntVec3.Z] += rhs.mE[IntVec3.Z];
    }

    /** 
     * minus operator
     */
    public IntVec3 minusNew(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	ret.mE[IntVec3.X] = this.mE[IntVec3.X] - rhs.mE[IntVec3.X];
	ret.mE[IntVec3.Y] = this.mE[IntVec3.Y] - rhs.mE[IntVec3.Y];
	ret.mE[IntVec3.Z] = this.mE[IntVec3.Z] - rhs.mE[IntVec3.Z];
	return(ret);	
    }

    public void minusHere(final IntVec3 rhs)
    {
	IntVec3 ret = new IntVec3();
	this.mE[IntVec3.X] -= rhs.mE[IntVec3.X];
	this.mE[IntVec3.Y] -= rhs.mE[IntVec3.Y];
	this.mE[IntVec3.Z] -= rhs.mE[IntVec3.Z];
    }

    /**
     * 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.mE[IntVec3.X] == rhs.mE[IntVec3.X]) &&
		   (this.mE[IntVec3.Y] == rhs.mE[IntVec3.Y]) &&
		   (this.mE[IntVec3.Z] == rhs.mE[IntVec3.Z]));
	} else 
	{
	    return false;
	}
    }
    
    /**
     * convert to String representation of this class
     */
    public String toString()
    {
	return(Integer.toString(this.mE[IntVec3.X]) + "\t" + 
	       Integer.toString(this.mE[IntVec3.Y]) + "\t" + 
	       Integer.toString(this.mE[IntVec3.Z]));
    }

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


    /*
     * Implements Encodable
     */
    public int sizeInDouble() 
    {
	return(3);
    }
    public void encodeInDouble(double[] array, int offset) 
    {
	array[offset] 		= this.mE[Vector3.X];
	array[offset + 1] 	= this.mE[Vector3.Y];
	array[offset + 2] 	= this.mE[Vector3.Z];
    }

    /*
     * 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;
    }
}
