/*
 * $Id: SpaceParam.java,v 1.11 2000/06/15 13:55:51 yamauchi Exp $
 *     (M\pi)^2 : SpaceParam (parameters for space) 空間の情報
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	Copyright 1999 MAEDA Atusi
 *	@author YAMAUCHI Hitoshi 山内 斉
 *
 * original source spaceparam.h
 * 
 * 1999年7月30日(金)
 */

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

import jp.ac.tohoku.is.archi.mpi2.util.Vector3;
import jp.ac.tohoku.is.archi.mpi2.util.IntVec3;
import jp.ac.tohoku.is.archi.mpi2.util.LineParser;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.Serializable;
// import java.util.Map; Can not use this useful class by IBM hpj
import jp.ac.tohoku.is.archi.mpi2.jdk12src.Map;

/**
 * Space Parameter
 *  	subdivnum が set されたかで初期化されたかを見る
 */
public final class SpaceParam 
implements Serializable
{
    private Vector3 mDefSpcMin;
    private Vector3 mDefSpcMax;
    private Vector3 mPartVolMin;
    private Vector3 mPartVolMax;
    private int     mSubDivNum;
    private double  mCellLen;
    // define space の指標の最大値 + 1 (指標はこれ未満)  (= 空間数)
    private IntVec3 mMaxDefSpcNumPlusOne; 

    public SpaceParam()
    {
	this.mDefSpcMin    = null;
	this.mDefSpcMax    = null;
	this.mPartVolMin   = null;
	this.mPartVolMax   = null;
	this.mSubDivNum    = 0;
	this.mCellLen      = 0.0;
	this.mMaxDefSpcNumPlusOne = null;
    }

    public SpaceParam(SpaceParam rhs)
    {
	this.mDefSpcMin		= new Vector3(rhs.mDefSpcMin);
	this.mDefSpcMax		= new Vector3(rhs.mDefSpcMax);
	this.mPartVolMin	= new Vector3(rhs.mPartVolMin);
	this.mPartVolMax	= new Vector3(rhs.mPartVolMax);
	this.mSubDivNum		= rhs.mSubDivNum;
	this.mCellLen		= rhs.mCellLen;
	this.mMaxDefSpcNumPlusOne = new IntVec3(rhs.mMaxDefSpcNumPlusOne);
    }

    public void setDefSpace(Vector3 defspcmin, Vector3 defspcmax)
    {
	if((defspcmin.get(Vector3.X) >= defspcmax.get(Vector3.X)) ||
	   (defspcmin.get(Vector3.Y) >= defspcmax.get(Vector3.Y)) ||
	   (defspcmin.get(Vector3.Z) >= defspcmax.get(Vector3.Z)))
	{
	    throw new RuntimeException("Error! : illegal define space. min " +
				       defspcmin + ", max " + defspcmax);
	    // commMpi2_exit(1);
	}
	this.mDefSpcMin = defspcmin;
	this.mDefSpcMax = defspcmax;
    }
    
    public void setPartVolume(Vector3 partvolmin, Vector3 partvolmax)
    {
	if((partvolmin.get(Vector3.X) >= partvolmax.get(Vector3.X)) ||
	   (partvolmin.get(Vector3.Y) >= partvolmax.get(Vector3.Y)) ||
	   (partvolmin.get(Vector3.Z) >= partvolmax.get(Vector3.Z)))
	{
	    throw new RuntimeException("Error! : illegal partvolume. min " +
				       partvolmin + ", max " + partvolmax);
	}
	Vector3 volsize = partvolmax.minusNew(partvolmin);
	if((volsize.get(Vector3.X) != volsize.get(Vector3.Y)) || 
	   (volsize.get(Vector3.X) != volsize.get(Vector3.Z)))
	{
	    throw new RuntimeException("Error!:illegal partition volume. not "
				       + "cubic at SpaceParam.setPartVolume");
	    // commMpi2_exit(1);
	}
	this.mPartVolMin = partvolmin;
	this.mPartVolMax = partvolmax;
    }

    public void setSubDivNumNinitCellLen(int subdivnum)
    {
	if(subdivnum <= 0)
	{
	    throw new RuntimeException("Error! : illegal subdivnum. " +
				       subdivnum);
	}
	this.mSubDivNum = subdivnum;
	this.mCellLen 	= 
	    (this.mPartVolMax.get(Vector3.X) - 
	     this.mPartVolMin.get(Vector3.X)) / (double)(this.mSubDivNum);

	if(this.mCellLen <= 0.0)
	{
	    throw new RuntimeException("Error! : partition volume is not " +
				       "setted. at SpaceParam.setSubDivNum");
	    // commMpi2_exit(1);
	}
	Vector3 defSpcSize =  this.mDefSpcMax.minusNew(this.mDefSpcMin);
	if(defSpcSize.getNorm() == 0.0)
	{
	    throw new RuntimeException("Error! : define space is not setted."+
				       " at SpaceParam.setSubDivNum");
	    // commMpi2_exit(1);
	}
	int [] defspcmax = new int[3];
	for(int i = 0; i < 3; i++)
	{			// + 0.1 は誤差対策
	    defspcmax[i] = (int)((defSpcSize.get(i) / this.mCellLen) + 0.1);
	    if(!((0 < defspcmax[i]) && (defspcmax[i] <= this.mSubDivNum)))
	    {
		throw new RuntimeException("Error! : There is a gap between "+
					   "definespace and partvol");
		// commMpi2_exit(1);
	    }
	}
	this.mMaxDefSpcNumPlusOne = new IntVec3(defspcmax);
    }
    public double  getCellLen()		{ return(this.mCellLen);	}
    public IntVec3 peekMaxDefSpcIdxPlusOne()
    {
	return(this.mMaxDefSpcNumPlusOne);
    }
    public Vector3 peekDefSpaceMin()  	{ return(this.mDefSpcMin);	}
    public Vector3 peekDefSpaceMax()  	{ return(this.mDefSpcMax);	}
    public Vector3 peekPartVolumeMin() 	{ return(this.mPartVolMin);	}
    public Vector3 peekPartVolumeMax() 	{ return(this.mPartVolMax);	}
    public int     getSubDivNum()  	{ return(this.mSubDivNum);	}
    
    public String toStringWithHead(String head) 
    {
	String s = 
	    head + " defspace (" + this.mDefSpcMin + ")-(" + 
	    this.mDefSpcMax + ")\n" +
	    head + " partition volume ("  + this.mPartVolMin + ")-(" +
	    this.mPartVolMax + ")\n" + 
	    head + " number of subdivision " + this.mSubDivNum + "\n" +
	    head + " cell length " + this.mCellLen;
	return s;
    }

    /**
     * positioning funcs
     */
    public Vector3 getNewMinPosOfSpcIdx(IntVec3 spcpos) 
    {
	// this.mCellLen * spcpos + this.mDefSpcMin
	Vector3 ret = new Vector3(spcpos);
	ret.mulScalerHere(this.mCellLen);
	ret.plusHere(this.mDefSpcMin);
	return(ret);
    }

    public Vector3 getNewMaxPosOfSpcIdx(IntVec3 spcpos) 
    {
	// this.mCellLen * (spcpos + (1, 1, 1))+ this.mDefSpcMin
	Vector3 ret = new Vector3((double)(spcpos.get(0) + 1), 
				  (double)(spcpos.get(1) + 1),
				  (double)(spcpos.get(2) + 1));
	ret.mulScalerHere(this.mCellLen);
	ret.plusHere(this.mDefSpcMin);
	return(ret);
    }

  static LineParser.Element[] params = {
    new LineParser.Number("definespace", 6),
    new LineParser.Number("partvol", 6),
    new LineParser.Number("partnum", 1)
  };

    public void readFromStream(InputStream in) throws IOException
    {
      LineParser lp = new LineParser(params);
      Map param = lp.parseAll(in);

      double[] defSpace = (double[])param.get("definespace");
      setDefSpace(new Vector3(defSpace[0], defSpace[1], defSpace[2]),
		  new Vector3(defSpace[3], defSpace[4], defSpace[5]));
      double[] partVolume = (double[])param.get("partvol");
      setPartVolume(new Vector3(partVolume[0], partVolume[1], partVolume[2]),
		    new Vector3(partVolume[3], partVolume[4], partVolume[5]));
      double[] subDivNum = (double[])param.get("partnum");
      setSubDivNumNinitCellLen((int)subDivNum[0]);
    }

    public void readFromFile(String fileName) throws IOException
    {
      FileInputStream fin = new FileInputStream(fileName);
      readFromStream(fin);
      fin.close();
    }
}
