//------------------------------------------------------------
// $Id: PE.h,v 1.3 2000/05/19 20:35:50 yamauchi Exp $
//------------------------------------------------------------
//	PE.h Processing Element
//	1996/7/10 
//	Copyright (C) 1996-1998 YAMAUCHI Hitoshi : 山内 斉
//------------------------------------------------------------
#ifndef _PEClass_h
#define _PEClass_h 1

#include "SLList.h"
#include "DLList.h"

#include "mySLQueue.h"
#include "materialArray.h"
#include "objectSet.h"
#include "sysinfo.h"
#include "viewdata.h"
#include "spc2PE.h"
#include "NetIntUnit.h"
#include "rayTrFRGUnit.h"
#include "searchNextSpcDDA.h"
#include "volumeSet.h"
#include "PRC_searchNextSpc.h"
#include "frustumSRG.h"
#include "PEpmarray.h"

class Ray;

//------------------------------------------------------------
// ray の空間スキップ数を数える
//------------------------------------------------------------
// class skipSpaceCounter {
// private:
//     skipSpaceCounter(const skipSpaceCounter& rhs);
//     const skipSpaceCounter& operator=(const skipSpaceCounter& rhs);
// protected:
//     double 		mSkipSpcOfRays;	      // ray が空間を skip した数
//     double 		mTravSpcOfRays;	      // ray が空間を通過した数
//     void   incTravSpcNum(void)	{ this->mTravSpcOfRays += 1.0;	}
//     void   incSkipSpcNum(void)	{ this->mSkipSpcOfRays += 1.0;	}
// public:
//     skipSpaceCounter(void);
//     ~skipSpaceCounter(void);
//     double getSkipSpcOfRays(void) const { return(this->mSkipSpcOfRays);}
//     double getTravSpcOfRays(void) const { return(this->mTravSpcOfRays);}
// };

//------------------------------------------------------------
// related functions with PE
//------------------------------------------------------------
extern double getTotalUnshotRadiosityEnergy(SLList < objBaseClass * >*pObList);

//------------------------------------------------------------
// PEClass PE の実装
//------------------------------------------------------------
class hemiCubeClass;		

class PEClass {
private:
    PEClass(const PEClass& rhs);
    const PEClass &operator=(const PEClass& rhs);
    
protected:
    //------------------------------
    // system, hardware, rendering parameters
    //------------------------------
    IntVec3 	     	mID;	// this processing element number
    int			mMyRank;
    SysInfoClass	mSysInfo; 	// system information
    ViewDataClass	mViewData;	// view point 
    SpaceParam		mSpcParam;	// space parameter

    //------------------------------
    // ray generator for radiosity delta-radiosity 
    //------------------------------
    hemiCubeClass      *mpHemiCube;
    Ray	     **mppRadiosityRays; 	// radiosity 時に hemicube との通信用

    //------------------------------
    // ray generator for ray-tracing 
    //------------------------------
    rayTrFRGUnitClass	mRayTrFRGUnit;

    //------------------------------
    // Local memory contents of this PE 
    //------------------------------
    SLList < objBaseClass * > 	mObjList;   // このPEの担当する空間のobject実体
    objectSetClass  		mObjectSet; // 高速にアクセスするための機構
    // この PE の担当する空間への volume 受信用．受信後は空になる．
    SLList < VolumeClass * > 	mVolList;  
    // volume へ高速にアクセスするための機構．こちらに実体がある．
    VolumeSetClass		mVolSet;    

    SLList < materialClass >  	mMatList;       // material の実体を保持
    materialArrayClass 		mMaterialSet;   // materials へアクセスする
    mySLQueue < Ray * > 	mRayPtrQueue;   // 処理する ray のキュー
    DLList < objBaseClass * > 	mRadPatchQueue; // 放射可能パッチリスト
    mySLQueue < VertexIntensity * > mVerIntPtrQueue;// 受信頂点輝度のキュー
    mySLQueue < HostCommClass * > mHostCommRecvQueue; // HostComm 受信用キュー
    //------------------------------
    // DDA 部分の分離 (FIXHERE)
    //------------------------------
    searchNextSpcDDA 		mDDAUnit;
    NetIntClass			mNIUnit;

    //------------------------------
    // processor status 
    //------------------------------
    YorN mIsMultiPassStageOver;    // 各ステージが終了かどうか
    YorN mIsPrepareShadingOver;	   // shadingの準備ステージは終了か
    YorN mIsIdle;		   // 仕事が無いか
    YorN mIsStopGenNewRay;	   // new rays を作成可能か(host の状態)
    YorN mSendingRayStopComToHost; // hostにray作成の停止を要求中(自己の状態) 


    //------------------------------
    // Statistics : 統計情報
    //------------------------------
    GeneralStatistics 		mGStat;
public:    
    void printStatInfo(const char *pStageName);


protected:		
    //------------------------------
    // for PRC method
    //------------------------------
    searchNextSpcPRC		mPRCUnit;
    
protected:
    //----- initialize 
    // initialize after receiving sysinfo, viewdata, spaceparam
    void initRankNID(void); 		// child of initInternalUnits()
    void initInternalUnits(void);	// 
    
    // initialize after receiving object data
    void getHavingSubSpcNum(int *spcnum); // 各 PE の持つ実際の部分空間の数
    void initObjectSet(void);		  // child of initObjectMaterialSet
    void initObjectMaterialSet(void);	  // init after material received
    void initRecvVolumeSet(void);	  // init after volume received
    void getSetOfSameSpcIDVolume(SLList < VolumeClass * > *pSameSpIdVlist,
				 SLList < VolumeClass * > *pVolPtrListCopy);

    void outRecvObjectInfo(void);	  // output object   information
    //    void outRecvMaterialInfo(void);	// output material information
    
    void exitprog(void)
    {
	cout << "<< PE:: " << this->mID << " : exit" << endl;
	commMpi2_exit(1);
    }

    // load balancing
    void globalLoadBalance(void);

protected:
    // radiosity and raytracing common method
    void initBusyIdleStat(void) 
    { 
	this->mIsIdle = YES; 	// idle -> busy へ変化させる
	this->toBusy();		// 初期状態は働く状態
    }
    void toBusy(void);
    void toIdle(void);    
    YorN isIdle(void) const 	{ return(this->mIsIdle);	}
    // HitPoint が部分空間内部にあるか．球の時などは外で hit することあり．
    YorN checkHitPosIsInThisSpcPos(const Vector3& hitpoint, 
				   const IntVec3& spcidx) const;
   
    YorN isMultiPassStageEnd(void) 
#ifndef FOR_STANDALONE	
	const {	return(this->mIsMultiPassStageOver); 	}
#endif
    ;
    // hostにこの PE の stat を伝達。これは利用しないこと。toBusy,
    // toIdle を利用すると余計な通信を減少できる  
    void sendHostToThisPEIsBusy(YorN isBusy); 
    int  probNgetHostCommand(void); 	// hostからの命令をprobe,受信,解釈
    //  2 次レイ作成
    YorN newSecondaryRadiosityRays(Ray *pRay, const materialClass *pMat,
				   objBaseClass * pHitObj);

    
    YorN newSecondaryRayTracingRays(Ray *pRay, const materialClass *pMat,
				    objBaseClass * pHitObj);

    // 次空間探索とレイの移動 PEGetNextSpace.cc
    YorN moveRayToNextSubspace(Ray *pRay); 

protected:
    // radiosity method
    void initForRadiosity(void); 	  // 
    void initializePatches(void);	  // calcRadioFRG.cc 
    void finalizeForRadiosity(double totalinitNonRadEnergy); // PERadiosity.cc
    void radiateRadFromMaxRadPatch(void); // calcRadioFRG.cc
    void processingRadiosities(void); 
    void processingOneRadiosity(Ray *pRay); 
    void calcNsetIntensityRadio(Ray *pRay, // calclRadioIC.cc
				const materialClass *const pMat,
				objBaseClass *pHitPat);

protected:
    // shading
    void initPrepareShadingStage(void);
    YorN isPrepareShadingStageOver(void) 
#ifndef FOR_STANDALONE
	const { return(this->mIsPrepareShadingOver);	}
#endif
    ;
    // below functions in prepareShading.cc
    YorN checkInSpc(const IntVec3 &sppos);// 定義空間内か
    void prepareGouroudShading(void);	  // gouroud shading 準備

    // 一つの空間の輝度の処理
    void sendVerIntOfThisSpc(objectsArrayClass *pOAry, const IntVec3& srcspc, 
 			     const Vector3& spmin,     const Vector3& spmax,
 			     const double tolerance);
    // この輝度情報が送信すべきものかどうか判定し、送信する
    void testOneIntNsendVerInt(const VertexIntensity& vint,
			       const IntVec3& srcspc, const Vector3& spmin,
			       const Vector3& spmax,  const double tolerance);
    // 次空間へ輝度情報の送信を行う。受信も行う。(送信先のPEは自分かもしれない)
    void sendVerIntToOtherSpcNrecv(const VertexIntensity& verint); 
    void addIntensity(const VertexIntensity& verint); // 輝度加算
    void finalizePrepareShadingStage(void);	 // 通信輝度平均

protected:
    // ray tracing method
    void initForRayTracing(void);

    // calcRayTrIC.cc
    void calcNsetIntensityRayTr(Ray *pRay, objBaseClass *pHitObj);

    void processingRayTraces(void);		     
    void processingOneRayTrace(Ray *pRay);		     
    objBaseClass *calcInterSectionWithRayAndObj(Ray *pRay);
    void calcRayTrNextSpace(Ray *pRay);
    YorN isObjectInSpc(const IntVec3 &spcpos);    

    void shotSomeFRGRays(void);

protected:
    //---------- network interface unit ----------
    YorN isRayInValidSpace(const Ray *pChkRay, int callpos); // debug用

    //----- send ray
    YorN flushSendRaysBuffer(void);
    // void sendRays(void);

    //----- recv rays
    void recvRaysIfItCan(int buffnum);
    void recvRays(void);
    void setRayToNI(Ray* pRay);

    //----- 輝度送信
    void insertIntensityIntoBuffer(Ray *pRay);
    void sendRayIntensityToFB(void);
    
public:
    // PE stat
    PEClass(void);    
    ~PEClass(void);    
    IntVec3 getID(void) const	{ return(this->mID);	}
    int  getMyRank(void) const;
    int  getRank(const IntVec3& id) const; // id -> rank 
    void setViewData(const ViewDataClass& aViewdata);

    // object and material
    void addOneMaterial(materialClass *);
    // void delOneMaterial(material *);
    void addOneObject(objBaseClass *);
    // void delOneObject(object *);

    // communication
#ifdef FOR_STANDALONE
    // for stand alone
    void receiveSysinfoNinitSpaceInfo(const SysInfoClass&    sys,
				      const ViewDataClass&   vw,
				      const SpaceParam&	     sp); 
    void receiveMaterials(const materialClass &mat);
    void receiveObjects(objBaseClass* pObj);    
    void receiveVolume(VolumeClass* pVolume);    
    void receiveObjInSpcMap(int bytesize,  OBJINSPC_IMPLEMENT_TYPE *pDatArray);
    int  sendOutRadioResultToHost(void){ return(0); } // no mean at standalone

    // output intermediate result
    void outRadiosityMpi2Data(const char* pBasename, YorN isShotRad);
    void writeGeometryFile(FILE *pFp, YorN isShotRad);
    void outRadiosityIntermediateResult(void); // 中間結果の出力用

    // for PRC method (see PRC_RecvStandAlone.cc)
    void receivePRCSkipMap(int bytesize, OBJINSPC_IMPLEMENT_TYPE *pDatAry);
#else
    void receiveSysInfoNinitSpaceInfo(void);
    void receiveMaterials(void);
    void receiveObjects(void);
    void receiveVolume(void);    
    void receiveObjInSpcMap(void);        
    void sendOutRadioResultToHostAccordHostComm(void); 
    void sendOutRadioResultToHost(void); // この関数が呼ばれればそのまま送信

    // output intermediate result
    void outRadiosityMpi2Data(const char* pBasename, YorN isShotRad);
    void writeGeometryFile(FILE *pFp, YorN isShotRad);
    void outRadiosityIntermediateResult(void); // 中間結果の出力用

    // for PRC method
    void receivePRCSkipMap(void); 
#endif

    void doRadiosity(void);
    void doPrepareShading(void);
    void doRayTracing(void);
    void barrierSync(void);	// 全体のバリア同期 time out あり失敗するとexit

    void setRayPtrToThisPE(Ray* pRay)
    {				// set ray to PE(from otherPE or generate rays)
	assert(pRay->isOK());
	this->mRayPtrQueue.enq(pRay);	
    }
    // void setRayPtrToOtherPE(int recvRank, Ray* pRay);

    IntVec3 getLocalIdxFromSpcPos(const IntVec3& spcpos)
    {
	return(this->mNIUnit.mpSpc2PE->getLocalIdxFromSpcPos(spcpos));
    }
    
    void printSysInfo(const char *pHead); // pHead は各行頭に出力する文字列 
    void printObjects(const char *pHead);
    void printMaterials(const char *pHead);
    void printObjInSpcMap(const char *pHead);

    // network interface unit
    YorN isDealSpace(const IntVec3& spcpos) const; // この PE の担当空間か
    void initSpc2PE(void); 		// child of initInternalUnits()

protected:
    //tokunaga distribute Rays
    frustumSRGClass mFrustum;	
    YorN secondRayGenWithDistrbute(Ray *pRay, const materialClass *pMat,
				   objBaseClass * pHitObj);
    YorN secondRayGenWithoutDistribute(Ray *pRay, const materialClass *pMat,
				       objBaseClass * pHitObj);
public:    
    void makeDDMap(void);
};

#endif				// _PEClass_h
