//------------------------------------------------------------
// $Id: PErecv.cc,v 1.2.2.1 2000/06/14 15:00:11 yamauchi Exp $ 
//------------------------------------------------------------
//	PE.cc Processing Element
//	1996/3/22
//	(C) Copyright Hitoshi YAMAUCHI
//	1997/1/21
//------------------------------------------------------------
#ifdef FOR_STANDALONE
# error "This file is for multi-PE (parallel) version."
#endif

#include <string.h>
#include "mpi2_funcs.h"
#include "mpi2communication.h"
#include "Option.h"
#include "PE.h"

//------------------------------------------------------------
// This is the part of multi-PE (parallel) version.
//------------------------------------------------------------
// get sysinfo and initialize ID and this Spc2PE
//------------------------------
void PEClass::
receiveSysInfoNinitSpaceInfo(void)
{
    if(this->mObjList.empty() == Q_NOT_EMPTY) // なにかある
    {
	cerr << "Error! : there are objects in list PE(" << this->mID << 
	    ") at PEClass::receiveSysinfo" << endl;
	this->exitprog();
    }
    commMpi2_BroadSysinfo(&(this->mSysInfo), 
 			  &(this->mViewData), 
 			  &(this->mSpcParam));

    // initialize after receiving sysinfo, viewdata, spaceparam
    this->initInternalUnits();
}

//------------------------------------------------------------
// 材質の受信
//------------------------------------------------------------
void PEClass::
receiveMaterials(void)
{
    materialClass mat;
    YorN isEnd = NO;
    while(isEnd == NO)
    {
	commMpi2_BroadMaterial(&mat);
	if(strncmp(mat.getName(), NULLMaterialName, 
		   MAX_MATERIAL_NAME_LEN - 1) != 0)
	{
	    this->mMatList.append(mat);	// null material ではない
	}else
	{
	    if(Option::getInstance()->getVerboseMode() == YES)
	    {
		cout << "## PE:: r " << this->getMyRank() << 
		    " : get null material " << endl;
	    }
	    isEnd = YES;
	    // break;		// null material で終了
	}
    }
    // this->outRecvMaterialInfo(); とりたてて有益な情報ではないので出力しない
}

//------------------------------
// volume の受信
//------------------------------
void PEClass::
receiveVolume(void)
{
    VolumeClass *pVolume = NULL;
    YorN isEnd = NO;
    while(isEnd == NO)
    {
	commMpi2_recvVolume(SysStat::getInstance()->getHostRank(), 
			    this->getMyRank(), &pVolume);
	if(pVolume->isNullVolume() == YES)
	{
	    cout << "// PE : " << this->mID << " : r " << this->getMyRank()
		<< " get null volume" << endl;
	    isEnd = YES;
	}else
	{
	    this->mVolList.append(pVolume);
	}
    }
    // already got null volume, initialize now
    this->initRecvVolumeSet();
}

//------------------------------------------------------------
// 物体(sizeof = 一定)の受信
//------------------------------------------------------------
void PEClass::
receiveObjects(void)
{
    objBaseClass *pObj = NULL;
    YorN isEnd = NO;
    while(isEnd == NO)
    {
	commMpi2_recvObject(SysStat::getInstance()->getHostRank(), 
			    this->getMyRank(), &pObj);
	if(pObj->who() == NULL_OBJ_E)
	{
	    cout << "// PE : " << this->mID << " : r " << this->getMyRank()
		<< " get null object" << endl;
	    isEnd = YES;
	}else
	{
	    this->mObjList.append(pObj);
	}
    }
    this->initObjectMaterialSet();
    this->outRecvObjectInfo();
}

//------------------------------------------------------------
// 空間内物体存在情報を受信する。クラスの実装と独立させるために情
// 報は一次元の配列になって送信されてくるのでそれを objInSpcClass 
// に格納する.
// (ref. host.cc : hostComputerClass::readAndDeliverGeoData())  
//------------------------------------------------------------
void PEClass::
receiveObjInSpcMap(void)
{
    int size[3];
    size[0] = size[1] = size[2] = this->mSpcParam.getSubDivNum();
    const int totalSize = size[0] * size[1] * size[2];
    assert(totalSize > 0);	// 既に SpcParam は受信済みのはず

    OBJINSPC_IMPLEMENT_TYPE *pDatArray = 
	new OBJINSPC_IMPLEMENT_TYPE [totalSize];
    commMpi2_BroadObjInSpc(sizeof(OBJINSPC_IMPLEMENT_TYPE) * totalSize, 
			   pDatArray);     

    // Map 領域作成と初期化
    this->mDDAUnit.mObjInSpcMap.initBySizeWithBaseZero(size); 

    // 受信内容のコピー
    for(int i = 0; i < this->mDDAUnit.mObjInSpcMap.getTotalSize(); i++)
    {
	objectExistInASpaceClass oeias(pDatArray[i]);
	this->mDDAUnit.mObjInSpcMap.setAsOneDimArray(i, oeias);
    }
}


//------------------------------
// host に radiosity の結果を送信しなくてはいけないことがわかっている
// 時にこの関数で待つ．host から命令が来たら送信する．
// radiosity の計算結果を host に送信する
//------------------------------
void PEClass::
sendOutRadioResultToHostAccordHostComm(void)
{
    while(1)
    {
	this->mNIUnit.mRecvHostCommBuf.recv(); // 受信
	if(this->mHostCommRecvQueue.length() == 0)
	{
	    retrySleep();	// ホストからのコマンドはない
	}
	else
	{
	    // Host のコマンドを受けた
	    assert(this->mHostCommRecvQueue.length() > 0);
	    HostCommClass *pRecvHostCom = this->mHostCommRecvQueue.deq();
	    HostCommClass recvHCom = (*pRecvHostCom);
	    delete pRecvHostCom; // 受信したものは new されている
	    
	    if(recvHCom.getCommand() == HOSTCOM_Send_Patch_Descriptions_e)
	    {
		PEoutDebugMes(this->getMyRank(), recvHCom.toString());
		this->sendOutRadioResultToHost();
		return;		// 送信終了したのでこのコマンドから戻る
	    }
	    else
	    {
		cout << "Error! : received illegal host command. " <<
	    	"PEClass::sendOutRadioResultToHostAccordHostComm"  << endl;
		cout << "this rank = " << this->getMyRank() << endl;
	    }
	}
    }
}


//------------------------------
// radiosity の計算結果を host に送信する
//------------------------------
void PEClass::
sendOutRadioResultToHost(void)
{
    int totalnum = 0;
    Pix pidx;
    for(pidx = this->mObjList.first(); pidx != NULL; this->mObjList.next(pidx))
    {
	commMpi2_sendObject(SysStat::getInstance()->getHostRank(), 
			    this->mObjList(pidx));
	totalnum++;
    }
    objBaseClass *pNullObject = new nullObjectClass;
    commMpi2_sendObject(SysStat::getInstance()->getHostRank(), pNullObject);
    delete pNullObject;

    // output debug message
    char buf[256];
    sprintf(buf, "send objects to host, total objes %d", totalnum);
    PEoutVerboseMes(this->getMyRank(), buf);
}


//------------------------------
// Radiosity の中間結果を出力する
//------------------------------
void PEClass::
outRadiosityMpi2Data(const char *pOutBaseFname, YorN isShotRad)
{
    cout << "NIN: 並列版の場合には同期してある地点の結果を出力する必要"
    "があるが，それを実装していない． " << endl;
    // ここで同期して上記の sendOutRadioResultToHost を呼ぶ計画
}




