//------------------------------------------------------------
// $Id: PErecvStandAlone.cc,v 1.5.2.1 2000/06/14 15:00:10 yamauchi Exp $ 
//------------------------------------------------------------
//	PE.cc Processing Element 
//	1996/3/22, 1997/1/21
//	(C) 1997--1998 Copyright YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
#ifndef FOR_STANDALONE
# error "This file is for stand alone mode."
#endif

#include <stdio.h>
#include "PE.h"
#include "Option.h"
#include "FileInfo.h"
#include "volume.h"
#include "mpi2_funcs.h"

//------------------------------------------------------------
// for stand alone
//------------------------------------------------------------
void PEClass::
receiveSysinfoNinitSpaceInfo(const SysInfoClass&    sys,
			     const ViewDataClass&   vw,
			     const SpaceParam&	    sp)
{
    if(this->mObjList.empty() == Q_NOT_EMPTY) // なにかある
    {
	// まだ環境がわからないのに object が既にセットされている。
	cout << "Error! : there are objects in list PE(" << this->mID << 
	    ") at PEClass::receiveSysinfo" << endl;
	this->exitprog();
    }

    this->mSysInfo 	= sys;
    this->mViewData	= vw;
    this->mSpcParam	= sp;

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

    if(Option::getInstance()->getVerboseMode() == YES)
    {
	cout << genHd(VERBOSEHEAD, this->getID()) << "receive sysinfo data."
	<< endl;
    }
}

// receive materials 
void PEClass::
receiveMaterials(const materialClass &mat)
{
    this->mMatList.append(mat);
    // this->outRecvMaterialInfo();とりたてて有益な情報ではないので出力しない
}

//------------------------------
// volume 関連
//------------------------------
void PEClass::
receiveVolume(VolumeClass* pVolume)
{
    if(pVolume->isNullVolume() == NO)
    {
	VolumeClass* pRecvVolume = new VolumeClass(*pVolume);
	this->mVolList.append(pRecvVolume);
    }else
    {
	// all null volume is received
	this->initRecvVolumeSet();
	// ここまでは各 volume を保持していることがわかった
    }
}

//------------------------------
// objects (sizeof = 一定) の受信
//------------------------------
void PEClass::
receiveObjects(objBaseClass *pObj)
{
    if(pObj->who() != NULL_OBJ_E)
    {
	this->mObjList.append(pObj);
    }else
    {
	// get NULL Object ... 送信終了
	this->initObjectMaterialSet();
	this->outRecvObjectInfo();
    }
}

//------------------------------
// 空間中の物体存在表の受信
//------------------------------
void PEClass::
receiveObjInSpcMap(int bytesize,  OBJINSPC_IMPLEMENT_TYPE * pDatArray)
{
    int size[3];
    size[0] = size[1] = size[2] = this->mSpcParam.getSubDivNum();
    const int totalSize = size[0] * size[1] * size[2];
    if((totalSize <= 0) ||	// 既に SpcParam は受信済みのはず
       (totalSize != bytesize))
    {
	cout << "Internal Error! : PEClass::receiveObjInSpcMap" << endl;
	commMpi2_exit(1);
    }

    // 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);
    }
}

//------------------------------------------------------------
// write geometry file
// @param isShotRad : YES の場合には shot のみを出力する
//	  	      NO  の場合には unshot のみを出力する
// 最終結果を書く場合には PEClass::finalizeForRadiosity を呼ぶと統合する
//------------------------------------------------------------
void PEClass::
writeGeometryFile(FILE *pFp, YorN isShotRad)
{
    char buf[1024];
    int outputType = ((isShotRad == YES) ? 
		      WITH_SHOT_RADOUT_e : WITH_UNSHOT_RADOUT_e);
    int oldmatid = -1;
    Pix pidx;
    for(pidx = this->mObjList.first(); pidx != NULL; this->mObjList.next(pidx))
    {
	if(oldmatid != this->mObjList(pidx)->getMaterialID())
	{
	    oldmatid = this->mObjList(pidx)->getMaterialID();
	    fprintf(pFp, "m %s\n", 
		    (this->mMaterialSet.get(oldmatid))->getName());
	}
	this->mObjList(pidx)->getMpi2Form(outputType, buf);
	fprintf(pFp, "%s\n",  buf);
    }
}

//------------------------------------------------------------
// output radiosity intermediate result
// @param isShotRad == YES の時には shot radiosity を出力する
//		       NO  の時には unshot radiosity を出力する
//------------------------------------------------------------
void PEClass::
outRadiosityMpi2Data(const char *pOutBaseFname, YorN isShotRad)
{
    // filename buf
    const int FNAMEBUFSIZE = 128;
    char buf[FNAMEBUFSIZE];
    sprintf(buf, "%s.r%03d.mpi2.geo", pOutBaseFname, this->getMyRank());
    FILE *pFp = NULL;

    char realWriteFName[FNAMEBUFSIZE];
    if((pFp = getUniqueWriteFP(buf, realWriteFName, FNAMEBUFSIZE)) == NULL)
    {
	cout << "Error! : can not open [" << buf << "]" << endl;
	commMpi2_exit(1);
    }

    cout << NORMALHEAD << " radiosity intermediate result out. Writing ["
	 << buf << "] ..."; cout.flush();

    // write Hemi-cube num 
    fprintf(pFp, "# create HC num is %d\n", this->mGStat.getHCGenNum());
    this->writeGeometryFile(pFp, isShotRad);
    fclose(pFp);

    // gzip output file
    char combuf[FNAMEBUFSIZE];
    sprintf(combuf, "gzip %s", buf);
    system(combuf);

    cout << " save done." << endl;
}
