//------------------------------------------------------------
// $Id: mpi2communStandAlone.cc,v 1.2 2000/05/19 20:35:51 yamauchi Exp $
//------------------------------------------------------------
//	mpi2 communication implementation
//	1996/7/31
//	Copyright (C)  YAMAUCHI Hitoshi 山内 斉
// 	通信関係 実装は MPI (commMpi2 関数群 でカプセル化)
// Stand Alone 用 通信ルーチンを呼ぶと終了する。PE 1 つで実行のこと
// ray-tracing, radiosity code debug 用 
//------------------------------------------------------------
#ifndef FOR_STANDALONE
# error "This communication routines are for stand alone processing"
#endif

#include <assert.h>

#include "StandAloneModeObjects.h"
#include "mpi2communication.h"
#include "sphereObject.h"
#include "triangleObject.h"
#include "volume.h"
#include "Option.h"

//------------------------------------------------------------
// initialize commun (M\pi)^2
//------------------------------------------------------------
void commMpi2_Init(int *pArgc, char ***pArgv)
{
    SysStat::getInstance()->setCommSize(2);
    SysStat::getInstance()->setMyRank(0);	// PE's rank = 0
    return;
    // for Wall
    pArgc = pArgc;
    pArgv = pArgv;
    // for Wall
}

void commMpi2_Finalize(void)
{
    cout << DEBUGHEAD << " commMpi2_Finalize nothing done" << endl;
}

void commMpi2_Barrier(void)
{
    // nothing for barrier synchronization
}

void commMpi2_exit(int err_num)
{
    exit(err_num);
}

//------------------------------------------------------------
// sysinfo
//------------------------------------------------------------
// send (Broadcast)
//  PE 用では object, material, sysinfo の receive はいらない。
//  send と同時に receive する
//------------------------------
// 受け渡し用の object
void commMpi2_BroadSysinfo(SysInfoClass 	*pSys,
			   ViewDataClass	*pVw,
			   SpaceParam		*pSp)
{
    GpPE->receiveSysinfoNinitSpaceInfo(*pSys, *pVw, *pSp);
}

// 各空間に物体が存在するかの表
void commMpi2_BroadObjInSpc(int bytes, OBJINSPC_IMPLEMENT_TYPE * pDatArray)
{
    GpPE->receiveObjInSpcMap(bytes, pDatArray);
}

// 物体からの距離の表
//tokunaga
void commMpi2_BroadPRCSkipMap(int bytes, OBJINSPC_IMPLEMENT_TYPE * pDatArray)
{
    GpPE->receivePRCSkipMap(bytes, pDatArray);
}


//------------------------------
// receive command
//------------------------------
// int commMpi2_recvBroadCommand(enum mpi2commun_command_e *pCommand)
// {
//     (*pCommand) = BroadCommand;
//     return(YES);
// }

//------------------------------------------------------------
// send, recv objects
//------------------------------------------------------------
// static IntVec3 		CommunSrcPEID;
// static IntVec3 		CommunDestPEID;
// static objBaseClass    *PCommunObj	= NULL;
void commMpi2_sendObject(int destRank, objBaseClass *pObj)
{
    if(destRank != 0)
    {
	cerr << "Error! : This is stand alone mode. There is only one PE."
	    << " You send to " << destRank << endl;
	exit(1);
    }
    
    // 他の PE からの情報を受信するため、受信側で new する必要がある。
    // 実際は stand alone では一つのメモリ空間で動いているのでこちらで
    // 新たに確保しないように実装も可能であるが、このコードは並列版と
    // シリアル版に同じ interface を提供するのでこのようにあたかも他の 
    // PE から送信されたように実装する必要がある。 
    // 
    // ダウンキャストしてしまったが、他の方法を考えるべきか
    objBaseClass *pRecvObj = NULL;
    switch(pObj->who())
    {
    case TRIANGLE_OBJ_E:	// Wooo! downcasting ... It is not good.
	pRecvObj = new triangleObjectClass(*((triangleObjectClass*)pObj));
	break;
    case SPHERE_OBJ_E:		// Wooo! downcasting ... It is bad.
	pRecvObj = new sphereObjectClass(*((sphereObjectClass*)pObj));
	break;
    case NULL_OBJ_E:
	pRecvObj = new nullObjectClass;
	break;
    default:
	cerr << "Error! : send illegal obj "
	    "at mpi2communStandAlone.cc:commMpi2_sendObject" << endl;
	commMpi2_exit(1);
    }
    
    GpPE->receiveObjects(pRecvObj);
}

void commMpi2_recvObject(int srcRank, int dstRank, objBaseClass **ppObj)
{
    // nothing to do here
    ppObj = NULL; // for wall
    srcRank = dstRank;
}

//------------------------------------------------------------
// send, recv volume (やがて object として統一すべきか?)
//	しかし、固定長のものに serialize はしたくないので固定長のもの
//	はそのまま、serialize すべきものは serialize して統一的に送信
//	しよう  
//------------------------------------------------------------
// send subvolume
void commMpi2_sendVolume(int dstRank, VolumeClass *pVol)
{
    double *pBuf = pVol->newSerializedArray();
    VolumeClass recvVol;
    recvVol.deserialize(pBuf);
    delete [] pBuf;

    GpPE->receiveVolume(&recvVol);    
    dstRank = dstRank;		// for Wall
}

// recv subvolume
void commMpi2_recvVolume(int srcRank, int dstRank, VolumeClass **ppVol)
{
    // nothing to do here;
    ppVol = NULL;
    srcRank = dstRank;
}

//------------------------------------------------------------
// material
//------------------------------------------------------------
void commMpi2_BroadMaterial(materialClass *pMat)
{
    GpPE->receiveMaterials(*pMat);
}


//------------------------------------------------------------
// probe 
//------------------------------------------------------------
YorN commMpi2_canRecv(int *pSrcRank, 
		      enum communication_tags_e recvStaff,
		      int *pNumOdObjs)
{
    return(NO);
    recvStaff  = recvStaff;	// for -Wall
    pSrcRank   = pSrcRank;
    pNumOdObjs = pNumOdObjs;
}

YorN commMpi2_isSendComplete(reqHandle_st req_handle)
{
    return(YES);		// stand alone では常に送信可能
    req_handle = req_handle;	// for -Wall
}

YorN commMpi2_isRecvComplete(reqHandle_st req_handle)
{
    return(YES);		// stand alone では常に受信可能
    req_handle = req_handle;	// for -Wall
}

//------------------------------------------------------------
// ray
//------------------------------------------------------------
reqHandle_st commMpi2_sendRays(int destRank, Ray* pRay, int numOfRays)
{
    cerr << "Error! : at stand alone version, commMpi2_sendRay." << 
	"this function will be never called." << endl; // 一台しかない
    exit(1);
    destRank = destRank;    pRay = pRay;    numOfRays = numOfRays;
    static reqHandle_st tmp;
    return(tmp);
}

reqHandle_st commMpi2_recvRays(int srcRank, Ray *pRay, int numOfRays)
{
    cerr << "Error! : at stand alone version, commMpi2_recvRay." << 
	"this function will never be called." << endl; // 一台しかない
    exit(1);
    srcRank = srcRank;		// for wall
    pRay = pRay;
    numOfRays = numOfRays;
    static reqHandle_st tmp;
    return(tmp);
}


//------------------------------------------------------------
// send intensity to Frame Buffer
//------------------------------------------------------------
void commMpi2_sendIntensity2FB(IntensityClass *pIntensity, int numOfInt)
{
    int	i;
    for(i = 0; i < numOfInt; i++)
    {
	GpHost->setIntensity(pIntensity[i]);
    }
}

void commMpi2_recvIntensity2FB(IntensityClass *pIntensity, int numOfIntensity)
{
    // void but OK
    pIntensity = pIntensity; // for -Wall
    numOfIntensity = numOfIntensity;
}

// YorN commMpi2_canRecvIntensity(int *pSrcRank)
// {
//     // void but OK
// }

//------------------------------------------------------------
// send, recv PEStatus
//------------------------------------------------------------
void commMpi2_sendPEstat2Host(PEStatClass *pPEstat)
{
    // void but OK
    pPEstat = pPEstat; // for wall
}

void commMpi2_recvPEstat(PEStatClass *pPEstat)
{
    // void but OK
    pPEstat = pPEstat;// for wall
}

// YorN commMpi2_canRecvPEStatus(int *pSrcRank)
// {
//     // void but OK
// }

//------------------------------------------------------------
// send, recv HostCommand : HostCommand は Host -> PE
//------------------------------------------------------------
// void commMpi2_sendHostCommand(int destRank, enum hostCommand_e host_command)
// {
//     // void but OK
//     destRank = destRank; // for wall
//     host_command = host_command;
// }
// 
// enum hostCommand_e commMpi2_recvHostCommand(void)
// {
//     // void but OK
//     return(HOSTCOM_ELSE_e);
// }

// if return NO, *pSrcRank has no mean
// YorN commMpi2_canRecvHostCommand(void)
// {
//     // void but OK
//     return(NO);
// }

//------------------------------------------------------------
// send, recv Intensity value and vertex position
//------------------------------------------------------------
reqHandle_st commMpi2_sendIntVer(int destRank, intVerClass *pIntver)
{
    cerr << "This function will never use in stand alone mode." << endl;
    cerr << "commMpi2_sendIntVer" << endl;
    commMpi2_exit(1);
    destRank = destRank;	pIntver = pIntver; // for Wall
    static reqHandle_st dummy;
    return dummy;
}

void commMpi2_recvIntVer(int srcRank,  intVerClass *pIntver)
{
    cerr << "This function will never use in stand alone mode." << endl;
    cerr << "commMpi2_recvIntVer" << endl;
    commMpi2_exit(1);    
    srcRank	= srcRank;
    pIntver	= pIntver;
}


//------------------------------------------------------------
// send, recv object
//	1 PE の場合,実際には通信しないのでこの関数で直接宛先(通常は 
//	host)に書いてしまう．  
//------------------------------------------------------------
void sendIntensityStandAlone(IntensityClass *pObj, int numOfObj)
{
    for(int i = 0; i < numOfObj; i++)
    {
	GpHost->setIntensity(pObj[i]);
    }
}
