//------------------------------------------------------------
// $Id: sysinfo.h,v 1.2 1999/12/07 03:49:57 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 : system information
//	1996/7/6 start as `dataCollection.h'
// 	SysInfo  : システムの情報 (PE 数など)
//	Copyright (C) 1996--1998 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
#ifndef _sysinfo_h
#define _sysinfo_h 1

#include <assert.h>
#include "mpi2.h"
#include "IntVec3.h"
#include "mpi2exit.h"

//------------------------------
// sysinfo : システム情報
//	mAllocScheme が ELSE_Alloc の時は初期化されていない
//------------------------------
class SysInfoClass {
protected:
    IntVec3 	mPEDim;			// PE が x,y,z 方向にいくつあるか
    int		mTotalPEnum;		// PE の数
    int 	mAllocScheme;		// subspace allocation scheme
    YorN	mDistributeRadiationHC;	// HemiCube からの放射の方式
    int 	mShadingScheme;		// shading の方法
    YorN	mDoRadiosity;		// Rendering の方法
    YorN	mDoRayTracing;
    // 情報のまとめ送りパラメータ
    int		mProcRadiositiesAtOnce; // radiosity rays/packet
    int		mSendVerIntAtOnce;	// 輝度情報を 1 packetにいくつ入れるか
    int		mProcRaysAtOnce;	// rays / packet
    int		mSendInt2FBAtOnce;	// GFB へ送る輝度情報
    // レイの発生の停止、再開のパラメータ
    int 	mSuspendRayGen;		// レイ発生停止のレイの数 (in a PE)
    int 	mResumeRayGen;		// レイ発生再開のレイの数 (in a PE)
    int 	mRayPropSkipMethod;	// レイの伝搬方法
    int 	mPRCMapGenerationMethod; // PRC 法における Map 生成方式
    int 	mSystemNetworkType;	 // システムのネットワーク形態
    // 初期光発生方式
    int 	mFirstRayGenMethod; 

public:
    SysInfoClass(void) 
    {
	// : による初期化は見難いのでこちらに関数内に書くことにする
	this->mPEDim.set(-1, -1, -1);
	this->mTotalPEnum		= -1;
	this->mAllocScheme		= ELSE_Alloc;
	this->mDistributeRadiationHC	= YES;
	this->mShadingScheme		= FlatShading; 
	this->mDoRadiosity		= NO;
	this->mDoRayTracing		= NO;
	this->mProcRadiositiesAtOnce	= -1;
	this->mSendVerIntAtOnce		= -1;
	this->mProcRaysAtOnce		= -1;
	this->mSendInt2FBAtOnce		= -1;
	this->mSuspendRayGen		= 10000;
	this->mResumeRayGen		= 5000;
	this->mRayPropSkipMethod	= ELSE_rayprop;
	this->mPRCMapGenerationMethod	= ELSE_mapgen;
	this->mSystemNetworkType	= ELSE_network;
	this->mFirstRayGenMethod	= ELSE_frgm;
    }

    SysInfoClass(const SysInfoClass &rhs)
    {
	this->mPEDim 		   	= rhs.mPEDim;
	this->mTotalPEnum	   	= rhs.mTotalPEnum;
	this->mAllocScheme	   	= rhs.mAllocScheme;
	this->mDistributeRadiationHC	= rhs.mDistributeRadiationHC;
	this->mShadingScheme		= rhs.mShadingScheme;
	this->mDoRadiosity		= rhs.mDoRadiosity;
	this->mDoRayTracing		= rhs.mDoRayTracing;
	this->mProcRadiositiesAtOnce	= rhs.mProcRadiositiesAtOnce;
	this->mSendVerIntAtOnce		= rhs.mSendVerIntAtOnce;
	this->mProcRaysAtOnce		= rhs.mProcRaysAtOnce;
	this->mSendInt2FBAtOnce		= rhs.mSendInt2FBAtOnce;
	this->mSuspendRayGen		= rhs.mSuspendRayGen;
	this->mResumeRayGen		= rhs.mResumeRayGen;
	this->mRayPropSkipMethod	= rhs.mRayPropSkipMethod;
	this->mPRCMapGenerationMethod	= rhs.mPRCMapGenerationMethod;
	this->mSystemNetworkType	= rhs.mSystemNetworkType;
	this->mFirstRayGenMethod	= rhs.mFirstRayGenMethod;
    }

    void setPEDim(const IntVec3& aPEDim)
    {
	int i;
	for(i = 0; i < 3; i++)
	{
	    if(aPEDim.get(i) <= 0)
	    {
		cout << "Error!: illegal PE num SysInfoClass::setPEDim"<< endl;
		commMpi2_exit(1);
	    }
	}
	this->mPEDim = aPEDim;
	this->mTotalPEnum = this->mPEDim.get(IntVec3::X) * 
	    this->mPEDim.get(IntVec3::Y) * this->mPEDim.get(IntVec3::Z);
	assert(this->mTotalPEnum > 0);
    }
    const IntVec3 getPEDim(void) const 
    {
	return(this->mPEDim); 
    }
    int   getTotalPENum(void) const
    {
	return(this->mTotalPEnum); 
    }

    YorN setAllocationScheme(int anAllocScheme)
    {
	if(anAllocScheme == ELSE_Alloc)	
	{
	    cout << "Warning! : setted unknown allocation scheme." << endl;
	    return(NO);
	}
	if(this->mAllocScheme != ELSE_Alloc)
	{
	    cout << "Warning! : override allocation scheme." << endl;
	    return(NO);
	}
	this->mAllocScheme = anAllocScheme;
	return(YES);
    }
    int getAllocationScheme(void) const 
    {
	return(this->mAllocScheme);
    }

    void setDistributeRadiation(void)	
    {
	this->mDistributeRadiationHC = YES;
    }
    void setContinuousRadiation(void)	
    {
	this->mDistributeRadiationHC = NO;
    }
    YorN isDistributedRadiation(void) const
    {
	return(this->mDistributeRadiationHC);	
    }
    void setShadingScheme(int s) 	
    { 
	if((s < 0) || (ELSE_Shading <= s))
	{
	    cout << "Illegal shading scheme" << endl; 
	    commMpi2_exit(1);
	}
	this->mShadingScheme = s; 
    }
    int  getShadingScheme(void) const 	
    {
	return(this->mShadingScheme); 
    }    
    void setProcRaysAtOnce(int procRadioNumAtOnce, int sendVerIntsAtOnce,
			   int procRayNumAtOnce, int SendInt2FBAtOnce)
    {
	if((procRadioNumAtOnce < 1) || (sendVerIntsAtOnce  < 1) || 
	   (procRayNumAtOnce   < 1) || (SendInt2FBAtOnce   < 1))
	{
	    cout << "Error! : illegal proccessing radio/ray num at once ("
		"radio, int, ray, int2FB) = (" <<
		    procRadioNumAtOnce << ", " << sendVerIntsAtOnce << ", " <<
			procRayNumAtOnce << ", " << SendInt2FBAtOnce <<
			    ")" << endl; 
	    commMpi2_exit(1);
	}
	this->mProcRadiositiesAtOnce	= procRadioNumAtOnce;
	this->mSendVerIntAtOnce		= sendVerIntsAtOnce;
	this->mProcRaysAtOnce		= procRayNumAtOnce;
	this->mSendInt2FBAtOnce		= SendInt2FBAtOnce;
    }
    int getProcRadioAtOnce(void) const 	
    {
	return(this->mProcRadiositiesAtOnce);
    }
    int getSendVerIntAtOnce(void) const 
    {
	return(this->mSendVerIntAtOnce);
    }
    int getProcRayTrAtOnce(void) const 	
    {
	return(this->mProcRaysAtOnce);
    }
    int getSendInt2FBAtOnce(void) const 
    {
	return(this->mSendInt2FBAtOnce);
    }
    void setSuspendRayNums(int suspendRayNum, int resumeRayNum)
    {
	// suspend の最低数は suspend > resume > 0 より (2 > 1 > 0)
	if((suspendRayNum <= 2) || (resumeRayNum <= 1))
	{
	    cout << "Error! : illegal {suspend|resume} number of rays.\n";
	    cout << " Number of suspend rays(>2) = " << suspendRayNum << 
		", Number of resume rays(>1) = " << resumeRayNum << endl;
	    commMpi2_exit(1);
	}
	if(suspendRayNum <= resumeRayNum)
	{
	    cout << "Error! : illegal suspend, resume number of rays. "
		"It must be suspend > resume." << endl;
	    cout << " Number of suspend rays  = " << suspendRayNum << 
		", Number of resume rays = " << resumeRayNum << endl;
	    commMpi2_exit(1);
	}
	this->mSuspendRayGen		= suspendRayNum;
	this->mResumeRayGen		= resumeRayNum;
    }
    int getSuspendRayNums(void) const 	
    {
	return(this->mSuspendRayGen);	
    }
    int getResumeRayNums(void)  const  	
    {
	return(this->mResumeRayGen);	
    }

    // ray 伝搬時のスキップ方法
    void setRayPropSkipMethod(int rpnet)
    {
	if((rpnet < 0) || (ELSE_rayprop <= rpnet))
	{
	    cout << "Internal Error!: illegal val at setRayPropSkipMethod "
		<< rpnet << endl; 
	    commMpi2_exit(1);
	}
	this->mRayPropSkipMethod = rpnet;
    }
    int getRayPropSkipMethod(void) const 
    {
	return(this->mRayPropSkipMethod); 
    }

    // PRC 法で利用する Map の生成方法
    void setPRCMapGenerationMethod(int PRCMapGenMethod)
    {
	if((PRCMapGenMethod < 0) || (ELSE_mapgen <= PRCMapGenMethod))
	{
	    cout << "Internal Error!:illegal val at setPRCMapGenerationMethod "
	    	<< PRCMapGenMethod << endl; 
	    commMpi2_exit(1);
	}
	this->mPRCMapGenerationMethod = PRCMapGenMethod;
    }
    int  getPRCMapGenerationMethod(void) const
    {
	return(this->mPRCMapGenerationMethod);
    }

    void setSystemNetworkType(int nettype)
    {
	if((nettype < 0) || (ELSE_network <= nettype))
	{
	    cout << "Internal Error!: illegal val at setSystemNetoworkType "
		<< nettype << endl; 
	    commMpi2_exit(1);
	}
	this->mSystemNetworkType = nettype;
    }
    int getSystemNetworkType(void) const 
    {
	return(this->mSystemNetworkType);
    }


    // add first ray generation method 1998年5月31日(日)
    void setFirstRayGenerationMethod(int scanMethod)
    {
	if((scanMethod < 0) || (ELSE_frgm <= scanMethod))
	{
	    cout << "Internal Error! : no such first ray generation method." 
		<< endl;
	    commMpi2_exit(1);	    
	}
	this->mFirstRayGenMethod = scanMethod;
    }
    int getFirstRaysGenerationMethod(void) const 
    {
	return(this->mFirstRayGenMethod);
    }
    
    const SysInfoClass& operator=(const SysInfoClass& rhs)
    {
	if(this != &rhs)
	{
	    this->mPEDim 		= rhs.mPEDim;
	    this->mTotalPEnum	   	= rhs.mTotalPEnum;
	    this->mAllocScheme 		= rhs.mAllocScheme;
	    // this->mIsImmediateOutImage 	= rhs.mIsImmediateOutImage;
	    this->mDistributeRadiationHC= rhs.mDistributeRadiationHC;
	    this->mShadingScheme	= rhs.mShadingScheme;
	    this->mDoRadiosity		= rhs.mDoRadiosity;
	    this->mDoRayTracing		= rhs.mDoRayTracing;
	    this->mProcRadiositiesAtOnce= rhs.mProcRadiositiesAtOnce;
	    this->mSendVerIntAtOnce	= rhs.mSendVerIntAtOnce;
	    this->mProcRaysAtOnce	= rhs.mProcRaysAtOnce;
	    this->mSendInt2FBAtOnce	= rhs.mSendInt2FBAtOnce;
	    this->mSuspendRayGen	= rhs.mSuspendRayGen;
	    this->mResumeRayGen		= rhs.mResumeRayGen;
	    this->mRayPropSkipMethod	= rhs.mRayPropSkipMethod;
	    this->mSystemNetworkType	= rhs.mSystemNetworkType;
	    this->mFirstRayGenMethod	= rhs.mFirstRayGenMethod;
 	}
	return(*this);
    }
    
    void setRadiosityCalc(void)		
    {
	this->mDoRadiosity = YES;	
    }
    YorN isRadiosityCalc(void) const	
    {
	return(this->mDoRadiosity);	
    }
    void setRayTracingCalc(void)	
    { 
	this->mDoRayTracing = YES;	
    }
    YorN isRayTracingCalc(void) const	
    {
	return(this->mDoRayTracing);	
    }

    void print(const char *pHead) const 
    {
	cout << pHead << "sysinfo: PEDim ( " << this->mPEDim << ") = " <<
	    this->mTotalPEnum << endl;
	const char *allocScheme[] = { 
	    "Block", "Distributed", "Skewed-Distributed", "Random", NULL, 
	};
	const char *shadeScheme[] = { 
	    "Flat", "Gouroud", NULL, 
	};
	const char *rayPropskip[] = { 
	    "NoSkip", "SobokuSkip", "ProximityClouds", NULL, 
	};
	const char *PRCMapGenMethod[] = {
	    "NoPRC", "ReadMap", "GenerateMap", NULL,
	};
	const char *systemNetwork[] = { 
	    "Torus", "MultiStage", NULL, 
	};
	const char *firstRayGenMethod[] = {
	    "AllScan", "Skip by Scanline", "Distributed Type Scan", NULL, 
	};
	
	cout << pHead << "Allocation scheme             = " << 
	    allocScheme[this->mAllocScheme] << endl;
	cout << pHead << "Distributed radiation from HC = " <<
	    ((this->mDistributeRadiationHC == YES) ? "Yes" : "NO") << endl;
	cout << pHead << "Shading Scheme                = " <<
	    shadeScheme[this->mShadingScheme] << endl;
	cout << pHead << "Rendering Scheme              = " <<
	    ((this->mDoRadiosity == YES) ? "Radiosity, " : "")<<
	    ((this->mDoRayTracing == YES) ? "Ray-Tracing" : "") << endl;
	cout << pHead << "ProcRaysAtOnce(radiosity, "
	    "intensityinfo, ray-tracing, intensity to GFB) = (" <<
	    this->mProcRadiositiesAtOnce << ", " <<  
	    this->mSendVerIntAtOnce << ", "  <<
	    this->mProcRaysAtOnce << ", " <<
	    this->mSendInt2FBAtOnce << ")" << endl;
	cout << pHead << "SuspendRayGenParam "
	    "(suspend, resume) = (" << this->mSuspendRayGen << ", " <<
	    this->mResumeRayGen << ")" << endl;
	cout << pHead << "RayPropSkipMethod = " << 
	    rayPropskip[this->mRayPropSkipMethod] << endl;
	cout << pHead << "PRCMapGenerationMethod = " << 
	    PRCMapGenMethod[this->mPRCMapGenerationMethod] << endl;
	cout << pHead << "SystemNetwork = " << 
	    systemNetwork[this->mSystemNetworkType] << endl;
	cout << pHead << "FirstRaysGenMethod = " << 
	    firstRayGenMethod[this->mFirstRayGenMethod] << endl;
    }

    YorN isContentsOK(void)
    {
	YorN isOK = YES;
	char *pErrHead = "Error! : There is a lack of contents of a sysinfo: ";
	if(this->mPEDim.get(IntVec3::X) < 0)
	{
	    cout << pErrHead << "NumberOfPEs" << endl;		
	    isOK = NO;
	}
	if(this->mAllocScheme == ELSE_Alloc)
	{
	    cout << pErrHead << "AllocationScheme" << endl;	
	    isOK = NO;
	}
	// this->mIsImmediateOutImage	default = NO
	// this->mDistributeRadiationHC	default = YES
	// this->mShadingScheme 	default = FlatShading
	if((this->mDoRadiosity == NO) && (this->mDoRayTracing == NO))
	{
	    cout << pErrHead << "radiosity or raytracing must be set" << endl;
	    cout << "radiosity   = " << 
		((this->mDoRadiosity  == YES) ? "YES" : "NO") << endl;
	    cout << "ray-tracing = " << 
		((this->mDoRayTracing == YES) ? "YES" : "NO") << endl;
	    isOK = NO;
	}
	if((this->mProcRadiositiesAtOnce < 1) ||
	   (this->mSendVerIntAtOnce 	 < 1) ||
	   (this->mProcRaysAtOnce 	 < 1) ||
	   (this->mSendInt2FBAtOnce	 < 1))
	{
	    cout << pErrHead << "ProcRaysAtOnce" << endl;
	    isOK = NO;
	}
	if((this->mSuspendRayGen < 1) ||
	   (this->mResumeRayGen  < 1))
	{
	    cout << pErrHead << "SuspendRayGenParam" << endl;
	    isOK = NO;
	}else if(this->mResumeRayGen >= this->mSuspendRayGen)
	{
	    cout << "Error! :illegal SuspendRayGenParam: (suspend, resume) = ("
		<< this->mSuspendRayGen << ", " << this->mResumeRayGen << ")"
		    << endl;
	    cout << "It must be resume < suspend" << endl;
	    isOK = NO;
	}	    
	if(this->mRayPropSkipMethod == ELSE_rayprop)
	{
	    cout << pErrHead << "RayPropSkipMethod" << endl;
	    isOK = NO;
	}
	if(this->mPRCMapGenerationMethod == ELSE_mapgen)
	{
	    cout << pErrHead << "PRCMapGenerationMethod" << endl;
	    isOK = NO;
	}
	if(this->mSystemNetworkType == ELSE_network)
	{
	    cout << pErrHead << "SystemNetworkType" << endl;
	    isOK = NO;
	}
	if(this->mFirstRayGenMethod == ELSE_frgm)
	{
	    cout << pErrHead << "FirstRaysGenMethod" << endl;
	    isOK = NO;
	}

	// 初期光分散時には空間 skip 法を適用すること
	if(this->mFirstRayGenMethod != AllScan_frgm)
	{
	    // AllScan でない場合には制限あり : No skip は許されない
	    if(this->mRayPropSkipMethod == NoSkip_rayprop)
	    {
		cout << "Error! : if first ray generation method is "
		"distributed, \n""subspace skip method must be applied.\n"
		"(Noskip can be used with Allscan only.)" << 
		endl;
		isOK = NO;
	    }
	}
	return(isOK);
    }
};

#endif				// #define _sysinfo_h 1

