/*
 * $Id: ViewData.java,v 1.6.4.1 2000/06/18 20:05:10 yamauchi Exp $
 *     (M\pi)^2 : FileInfo (file information) 
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *      Copyright 1999 MAEDA Atusi
 *	@author YAMAUCHI Hitoshi 山内 斉
 *
 * 	ViewData : 視線の情報・radiosity情報
 *
 * original source viewdata.h
 * 
 * 1999年7月31日(土)
 */

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

import java.lang.Math;
import jp.ac.tohoku.is.archi.mpi2.util.Vector3;
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;
import jp.ac.tohoku.is.archi.mpi2.jdk12src.Map;

/**
 * ViewData : 視線の情報・radiosity情報
 */
public final class ViewData 
implements Serializable, Mpi2Constants 
{
    private Vector3 mViewPoint;		// 視点
    private Vector3 mViewVector;	// 視線方向ベクトル
    private Vector3 mViewUpVector;	// 上方ベクトル
    private double  mVfovRad;		// 垂直 field of view radian
    private double  mHfovRad;		// 水平 field of view radian
    private int	    mScreenX, mScreenY;	// screen size
    // radiosity 法
    private double  mMinRadiationEnergy;// radiosity 法における最小放射エネルギ
    private int     mHemres;		// hemi cube の解像度
    
    // ray tracing 法
    private int	    mMaxRayRefNum;	// 最大反射回数
    private double  mMinRefCoeffNorm;	// 最小減衰率
    private int	    mDistributedRayNum;	// distributed ray num
    private int     mFrustumResX;	// 四角錐の底面の解像度 X
    //     int     mFrustumResY;	// 四角錐の底面の解像度 Y
    //     double  mFrustumFOVRad;	// 四角錐の field of view
    //     double  mFrustumCosN;	// 四角錐での発生レイの phone 則

    public ViewData()
    {
	final double DEFAULT_FOV_RAD = 30.0 * Math.PI / 180.0;
	final int    DEFAULT_SCREEN_X = 100;
	final int    DEFAULT_SCREEN_Y = 100;
	this.mViewPoint		= null;
	this.mViewVector	= null;
	this.mViewUpVector	= null;
	this.mVfovRad		= DEFAULT_FOV_RAD;
	this.mHfovRad		= DEFAULT_FOV_RAD;
	this.mScreenX		= DEFAULT_SCREEN_X;
	this.mScreenY		= DEFAULT_SCREEN_Y;

	this.mMinRadiationEnergy	= DEFAULT_MIN_RAD_ENERGY;
	this.mHemres			= DEFAULT_HEMRES;

	this.mMaxRayRefNum		= DEFAULT_MAX_REFLECTION_RAY_NUM;
	this.mMinRefCoeffNorm		= DEFAULT_MIN_REFLECTION_COEFF_NORM2;
	this.mDistributedRayNum		= DEFAULT_DIST_RAY_NUM;
	this.mFrustumResX		= DEFAULT_FRUSTUM_RES;
	// 	this.mFrustumResY		= DEFAULT_FRUSTUM_RES;
	// 	this.mFrustumFOVRad		= DEFAULT_FRUSTUM_FOV;
	// 	this.mFrustumCosN		= DEFAULT_FRUSTUM_COSN;
    }

    public ViewData(ViewData rhs)
    {
	this.mViewPoint		= new Vector3(rhs.mViewPoint);
	this.mViewVector	= new Vector3(rhs.mViewVector);
	this.mViewUpVector	= new Vector3(rhs.mViewUpVector);
	this.mVfovRad		= rhs.mVfovRad;
	this.mHfovRad		= rhs.mHfovRad;
	this.mScreenX		= rhs.mScreenX;
	this.mScreenY		= rhs.mScreenY;

	this.mMinRadiationEnergy= rhs.mMinRadiationEnergy;
	this.mHemres		= rhs.mHemres;

	this.mMaxRayRefNum	= rhs.mMaxRayRefNum;
	this.mMinRefCoeffNorm	= rhs.mMinRefCoeffNorm;
	this.mDistributedRayNum	= rhs.mDistributedRayNum;
	this.mFrustumResX	= rhs.mFrustumResX;
	// 	this.mFrustumResY		= rhs.mFrustumResY;
	// 	this.mFrustumFOVRad		= rhs.mFrustumFOVRad;
	// 	this.mFrustumCosN		= rhs.mFrustumCosN;
    }
    public boolean setViewPoint(Vector3 vp)
    { 
	if(vp.getNorm() != 0.0)
	{
	    this.mViewPoint = vp;	
	    return(true);
	}else
	{
	    return(false);
	}
    }
    public Vector3 peekViewPoint()  	{ return(this.mViewPoint);	}
    public boolean setViewVector(Vector3 vv)
    {
	if(vv.getNorm() != 0.0)
	{
	    this.mViewVector = vv; 	
	    this.mViewVector.normalize(); 	
	    return(true);
	}else
	{
	    return(false);
	}
    }
    public Vector3 peekViewVector() 	{ return(this.mViewVector); 	}
    public boolean setViewUpVector(Vector3 vup)
    {
	if(vup.getNorm() != 0.0)
	{
	    this.mViewUpVector = vup;	
	    this.mViewUpVector.normalize();	
	    return(true);
	}else
	{
	    return(false);
	}
    }
    public Vector3 peekViewUpVector()  	{ return(this.mViewUpVector);	}
    public boolean setFov(double vfovRad, double hfovRad)
    {
	if((vfovRad <=  0.0)     || (hfovRad <=  0.0) ||
	   (vfovRad >= Math.PI)  || (hfovRad >= Math.PI))
	{
	    String s = "Warning! : illegal field of view (rad)(vfov, hfov) = "+
		vfovRad + ", " + hfovRad + " : unchanged";
	    throw new RuntimeException(s);
	    // return(false);
	}
	this.mVfovRad	= vfovRad;
	this.mHfovRad	= hfovRad;
	return(true);
    }
    public double getV_FOV() 
    {
	return(this.mVfovRad);
    }
    public double getH_FOV() 
    {
	return(this.mHfovRad);
    }
    public void setScreenSize(int scrX, int scrY)
    {
	if((scrX <= 0) || (scrY <= 0))
	{
	    String s = "Error! : illegal screen size (" +scrX+", "+scrY+")";
	    throw new RuntimeException(s);	    
	    // commMpi2_exit(1);
	}
	this.mScreenX = scrX;
	this.mScreenY = scrY;	
    }
    public int getScreenSizeX() 
    {
	return(this.mScreenX);
    }
    public int getScreenSizeY() 
    {
	return(this.mScreenY);
    }
    public void setMinRadEnergy(double anEnergy)
    {
	if(anEnergy <= 0.0)
	{
	    String s = "Error ! : illegal min radiation energy " + anEnergy;
	    throw new RuntimeException(s);	    	    
	    // commMpi2_exit(1);
	}
	this.mMinRadiationEnergy	= anEnergy;
    }
    public double getMinRadEnergy()  	{ return(this.mMinRadiationEnergy); }
    public void setHemres(int hemicubeResolution)
    {
	if((hemicubeResolution < 2) || ((hemicubeResolution % 2) != 0))
	{
	    String s = "Error! : hemicube resolution must be > 1 and % 2 == 0"
		+ " : hemres = " + hemicubeResolution;
	    throw new RuntimeException(s);	    	    	    
	    // commMpi2_exit(1);	    
	}
	this.mHemres = hemicubeResolution;
    }
    public int  getHemres() 		{ return(this.mHemres);		}
    public void setMaxRayRefParam(int aRefnum, double aCoefNorm)
    {
	if((aRefnum <= 0) || (aCoefNorm <= 0.0))
	{
	    String s = "Error ! : illegal max ray reflection param, num = " + 
		aRefnum + ", coeff = " + aCoefNorm;
	    throw new RuntimeException(s);	    	    	    	    
	    // commMpi2_exit(1);
	}
	this.mMaxRayRefNum		= aRefnum;
	this.mMinRefCoeffNorm		= aCoefNorm;
    }
    public int    getMaxRayRefNum() 	   { return(this.mMaxRayRefNum);   }
    public double getMinRayRefCoeffNorm()  { return(this.mMinRefCoeffNorm);}
    public void   setDistributedRayNum(int aDistRayNum)
    {
	if(aDistRayNum <= 0)
	{
	    String s = "Error ! : illegal distributted ray num " + aDistRayNum;
	    throw new RuntimeException(s);
	    // commMpi2_exit(1);
	}
	this.mDistributedRayNum	= aDistRayNum;
    }
    public int    getDistributedRayNum() { return(this.mDistributedRayNum);}
    public void   setFrustumParam(int resolutionX)
    {
	if(resolutionX <= 0)
	{
	    String s = "Error! : illegal frustum param res("+resolutionX+")";
	    throw new RuntimeException(s);	    
	    // commMpi2_exit(1);
	}
	this.mFrustumResX	= resolutionX;
	// 	this.mFrustumResY 	= resY;
	// 	this.mFrustumFOVRad	= fovrad;
	// 	this.mFrustumCosN 	= cosN;
    }
    public int    getFrustumResX() 	{ return(this.mFrustumResX);	}
    // int    getFrustumResY() { return(this.mFrustumResY);	}
    // double getFrustumFOV()  { return(this.mFrustumFOVRad);	}
    // double getFrustumCosN() { return(this.mFrustumCosN);	}

    public String toStringWithHead(String head)  
    {
	String s = head + "viewPoint\t" + this.mViewPoint   + "\n";
	s += head + "viewVector\t" 	+ this.mViewVector  + "\n";
	s += head + "viewUpVector\t"	+ this.mViewUpVector+ "\n";
	s += head + "fovVHRad\t" + this.mVfovRad + " " + this.mHfovRad + "\n";
	s += head + "screenSize\t("+this.mScreenX+" " + this.mScreenY + ")\n"; 
	s += head + "maxRayReflectionNum\t"  + this.mMaxRayRefNum +     "\n";
	s += head + "minRayReflectionCoef\t" + this.mMinRefCoeffNorm+   "\n";
	s += head + "distributedRayNum\t"    + this.mDistributedRayNum+ "\n";
	s += head + "frustum resolution = " + this.mFrustumResX + "\n";
	// ", " + this.mFrustumResY  + ")"+ "\n";
	// s += head + "frustum fov\t" + this.mFrustumFOVRad + "\n";
	// s += head + "frustumCosN\t" + this.mFrustumCosN   + "\n";
	s += head + "minRadioEnergy\t"+ this.mMinRadiationEnergy + "\n";
	s += head + "hemres\t" 	+ this.mHemres;
	return(s);
    }

  static LineParser.Element[] params = {
    new LineParser.Number("viewpoint", 3),
    new LineParser.Number("viewvector", 3),
    new LineParser.Number("viewupvector", 3),
    new LineParser.Number("viewfov", 2),
    new LineParser.Number("screensize", 2),
    new LineParser.Number("maxRayReflectionParam", 2),
    new LineParser.Number("distributedRayNum", 1),
    new LineParser.Number("frustum", 1),
    new LineParser.Number("minRadiationEnergy", 1),
    new LineParser.Number("hemres", 1)
  };

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

      double[] viewpoint = (double[])param.get("viewpoint");
      mViewPoint = new Vector3(viewpoint[0], viewpoint[1], viewpoint[2]);
      double[] viewvector = (double[])param.get("viewvector");
      mViewVector = new Vector3(viewvector[0], viewvector[1], viewvector[2]);
      double[] viewupvector = (double[])param.get("viewupvector");
      mViewUpVector = new Vector3(viewupvector[0], viewupvector[1], viewupvector[2]);
      double[] fov = (double[])param.get("viewfov");
      mVfovRad = fov[0];
      mHfovRad = fov[1];
      double[] size = (double[])param.get("screensize");
      mScreenX = (int)size[0];
      mScreenY = (int)size[1];
      double[] reflex = (double[])param.get("maxRayReflectionParam");
      mMaxRayRefNum = (int)reflex[0];
      mMinRefCoeffNorm = reflex[1];
      double[] distRayNum = (double[])param.get("distributedRayNum");
      mDistributedRayNum = (int)distRayNum[0];
      double[] frustum = (double[])param.get("frustum");
      mFrustumResX = (int)frustum[0];
      double[] energy = (double[])param.get("minRadiationEnergy");
      mMinRadiationEnergy = energy[0];
      double[] hemres = (double[])param.get("hemres");
      mHemres = (int)hemres[0];
    }

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