/*
 * $Id: Mpi2CommunicatorOnePE.java,v 1.13.4.1 2000/06/15 20:41:23 yamauchi Exp $
 *     (M\pi)^2 : Interface of Mpi2 Communicator : 1PE version implementation
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	@author YAMAUCHI Hitoshi 山内 斉
 *
 * original source mpi2communStandAlone.h mpi2communStandAlone.cc
 *
 * 1PE 版の実装
 *
 * 1999年8月 9日(月) 
 */

package jp.ac.tohoku.is.archi.mpi2.net;

import  java.util.*;
import  mpi.*;

import  jp.ac.tohoku.is.archi.mpi2.common.*;
import  jp.ac.tohoku.is.archi.mpi2.obj.*;
import  jp.ac.tohoku.is.archi.mpi2.sysparam.*;
import  jp.ac.tohoku.is.archi.mpi2.util.*;
import  jp.ac.tohoku.is.archi.mpi2.host.*;

/**
 * (M\pi)^2 が用いる通信関数群の interface
 */
public final class Mpi2CommunicatorOnePE 
implements Mpi2Communicator, Mpi2Enum
{
    // 通信時に一時的に物体を保持しておくキュー
    // PROF private Queue mQueue = new VectorQueue();
    private Queue mQueue = new RingBufferQueue();

    // 通信時の srcRank と destRank の記録
    private int   mSrcRank  = -1;
    // private int   mDestRank = -1;

    /**
     * get name : どんな種類の通信方式か
     *	one PE version
     */
    public String getName()
    {
	return("OnePE");	
    }

    /**
     * initialize commun (M\pi)^2
     */
    public synchronized String [] init(String [] args)
    {
	(SysStat.getInstance()).setCommSize(2);
	(SysStat.getInstance()).setMyRank(0);	// PE's rank = 0
	String s = "// Mpi2CommunicatorOnePE : can only handle 1 SendBuffer" + 
	    " and 1 Recv Buffer.\n"	+ 
	    "// CommSize is fixed to 2 and PE's rank defined to 0.";
	System.out.println(s);	
	return(args);
    }
    public synchronized void finalizecommun() // finalize method はよくあるので
    {
	
    }
    public synchronized void barrier()
    {
	
    }
    public synchronized void exit(int err_num)
    {
	System.exit(err_num);
    }

    /**
     * get type
     */
    public int getCommunicatorType()
    {
	return(Mpi2Enum.MPI2COMM_OnePE);
    }

    /**
     * get identification
     */
    public String getDescription()
    {
	return("Mpi2Communicator : One PE version");
    }

    /**
     * sysinfo (Broadcast)
     *  PE 用では object, material, sysinfo の receive はいらない。
     *  send と同時に receive する
     */
    public synchronized void 
    broadSysinfo(SysInfo [] sys, ViewData [] view, SpaceParam [] spcparam)
    {
	PE.getInstance().
	    receiveSysinfoNinitSpaceInfoStdAlone(new SysInfo(sys[0]),
						 new ViewData(view[0]),
						 new SpaceParam(spcparam[0]));
    }

    /**
     * 各空間に物体が存在するかの表
     */
    public synchronized void broadObjectInSpaceMap(Array3D [] objectInSpaceMap)
    {
	PE.getInstance().initDDASpcMap(objectInSpaceMap[0]);
    }

    /**
     * 物体からの距離の表
     */
    // public void broadPRCSkipMap(int bytes, IMPLEMENT_TYPE pDatArray)

    /**
     * send, recv objects
     */
    /**
     * send objects
     * 	@param destRank 	物体プリミティブ送付先の rank
     * 	@param objprim 		送付する物体プリミティブ
     */
    public synchronized void sendObject(int destRank, ObjectPrimitive objprim)
    {
	PE.getInstance().setObjectToThisPE(objprim);
    }
    
    /**
     * recv objects
     * 	@param destRank 	物体プリミティブ送付元の rank の入る長さ 1 配列
     * 	@param objprim 		受信した物体プリミティブの配列
     */
    public synchronized void 
    recvObject(int [] srcRank,  ObjectPrimitive [] objprim)
    {
	Mpi2Option.getInstance().
	    debugOut("DEBUG : Never Implemented recvObject");
    }

    /**
     * Isend objects
     *	non blocking send
     *	
     *	@param destRank	送信先
     *	@param buff	送信する物体の配列
     *	@param sendnum  配列は固定にとられることが多い．そのため，その
     *			配列のいくつまでが送信すべきものかを示しておく．
     */
    private int stage = 0;	// 一回目は radiosity stage end  
    public synchronized Request 
    IsendObj(int destRank, EncodedData lockedSendBuf, int sendObjTag)
    {
	// Host 行き
	if(destRank == SysStat.getInstance().getHostRank())
	{
	    if(sendObjTag == TAG_PE_STATUS)
	    {
		// PE Status
		Decoder dec = lockedSendBuf.getDecoder();
		int sendnum = lockedSendBuf.length() / 
		    PEStat.getObjectDecoder().sizeInDouble();
		
		for(int i = 0; i < sendnum; i++)
		{
		    PEStat pestat = 
			(PEStat)dec.decode(PEStat.getObjectDecoder());
		    this.proceedPEStat(pestat);
		}
	    }
	    else if(sendObjTag == TAG_INTENSITY)
	    {
		// 輝度
		Decoder dec = lockedSendBuf.getDecoder();		
		int sendnum = lockedSendBuf.length() / 
		    Intensity.getObjectDecoder().sizeInDouble();
		for(int i = 0; i < sendnum; i++)
		{
		    Intensity in = 
			(Intensity)dec.decode(Intensity.getObjectDecoder());
		    Host.getInstance().addIntensity(in);
		}
	    }
	    else
	    {
		throw new RuntimeException("OnePE sends no such object. Tag = "
					   + sendObjTag);
	    }
	}else
	{
	    Mpi2Option.getInstance().
		debugOut("DEBUG : NIN OnePE will never use IsendObj " +
			 "but called");
/*	    for(int i = 0; i < sendnum; i++)
	    {
		Assert.out(buff[i] != null, "Error! : can not send null.");
		this.mQueue.enq(buff[i]);
	    }
	    */
	    // this.mDestRank = destRank;
	}
	return(null);
    }

    private void proceedPEStat(PEStat pestat)
    {
	if(pestat.getStat() == PEStat.PESt_Idle)
	{
	    /*
	     * 1PE の場合には Idle が来れば stage は終了する
	     */
	    Queue comQ = 
		((PE.getInstance()).peekHostCommRecvQueue());
	    
	    Mpi2Option.getInstance().
		debugOut("DEBUG : Mpi2CommunicatorOnePE : stage "+ 
			 stage + ", " +
			 HostConstants.End_PrepareShading + ", "+
			 (PE.getInstance().peekSysInfo().
			  getShadingScheme()) +
			 ", " + Mpi2Enum.FlatShading);
	      
	    if((stage == HostConstants.End_PrepareShading) && 
	       (PE.getInstance().peekSysInfo().getShadingScheme() 
		== Mpi2Enum.FlatShading))
	    {
		/*
		 * shading stage だが，flat の場合には skip す
		 * る
		 */
		Mpi2Option.getInstance().
		    debugOut("DEBUG : Mpi2CommunicatorOnePE:hostcom "
			     + "skip shading stage");
		stage++;
	    }
	    HostCommand hcom = new HostCommand(stage);
	    comQ.enq(hcom); 
	    Mpi2Option.getInstance().
		debugOut("DEBUG : Mpi2CommunicatorOnePE : hostcom " +
			 "send to PE " + hcom);
	    stage++;	// 次は shading，そして raytrace 
	}
	else if(pestat.getStat() == PEStat.PESt_BUSY)
	{
	    Mpi2Option.getInstance().
		debugOut("DEBUG : Mpi2CommunicatorOnePE : Busy");
	}
	else if(pestat.getRequest() == PEStat.PEReq_StopGenRays)
	{
	    Mpi2Option.getInstance().
		debugOut("DEBUG : Mpi2CommunicatorOnePE:StopGenRay");
	}
	else if(pestat.getRequest() == PEStat.PEReq_ResumeGenRays)
	{
	    Mpi2Option.getInstance().
		debugOut("DEBUG : Mpi2CommunicatorOnePE:ResumeGRay");
	}else
	{
	    String s = "Mpi2CommunicatorOnePE : illegal pestat";
	    throw new RuntimeException(s + pestat);
	}
    }
	
	
    /**
     * Irecv objects
     *	non blocking recv
     *	
     *	@param srcRank	  送信元
     *	@param buff	  送信する物体の配列
     *	@param recvObjnum 受信する数
     */
    public synchronized Request 
    IrecvObj(int srcRank, EncodedData encodedBuf, int recvTags)
    {
	Mpi2Option.getInstance().
	    debugOut("DEBUG : OnePE will never use IrecvObj but called");
	/*
	if(this.mQueue.isEmpty())
	{
	    System.out.println("Warning! : IrecvObj is called " + 
			       "but queue is empty");	
	}else
	{
	    Mpi2Option.getInstance().
	    debugOut("DEBUG : RecvBuffSize = " + buff.length + 
			       ", recv num = " + recvObjnum);
	    for(int i = 0; i < recvObjnum; i++)
	    {
		buff[i] = this.mQueue.deq();
	    }
	}
	*/
	this.mSrcRank = srcRank;
	return(null);
    }
    
    /*
     * send complete? 
     * (waiting completion of non blocking send)
     */
    public synchronized boolean isSendComplete(Request req_handle)
    {
	// queue に残っている場合には送信は終了していない．
	return(this.mQueue.hasElements() ? false : true);
    }

    /*
     * recv complete? 
     * (waiting completion of non blocking recv)
     */
    public synchronized boolean isRecvComplete(Request req_handle)
    {
	return(true);		// OnePE では常に真
    }

    /**
     * send, recv volume (やがて object として統一すべきか?)
     *	しかし、固定長のものに serialize はしたくないので固定長のもの
     *	はそのまま、serialize すべきものは serialize して統一的に送信
     *	しよう  
     *------------------------------------------------------------
     * send subvolume
     */
    // public void commMpi2_sendVolume(int dstRank, VolumeClass *pVol);

    /**
     * recv subvolume
     */
    // public void commMpi2_recvVolume(int srcRank, int dstRank, 
    // 				       VolumeClass **ppVol);

    /**
     * material
     */
    public synchronized 
    void broadMaterial(Material [] aMaterial)
    {
	if(!(aMaterial[0].isNullMaterial()))
	{
	    PE.getInstance().
		receiveMaterialStdAlone(new Material(aMaterial[0]));
	}else
	{
	    PE.getInstance().initMaterialSet();
	}
    }

    /**
     * probe 
     */
   /*------------------------------------------------------------
     * probe 
     *-----------------------------------------------------------*/
    /**
     * can recv 
     * 	@param srcRank_and_recvObjNum[] : 返り値
     *		srcRank_and_recvObjNum[0] : 送信元
     *		srcRank_and_recvObjNum[1] : 受信する物体数
     *	@param recvStaffTAG 		: 受信したいものの TAG
     *	@return recv 発行可能なら true 
     */
    public synchronized boolean canRecv(int [] srcRank_and_recvObjNum, 
					int  recvStaffTAG,
					Datatype dat_t)
    {
	if(this.mQueue.hasElements())
	{
	    srcRank_and_recvObjNum[0] = this.mSrcRank;
	    srcRank_and_recvObjNum[1] = this.mQueue.length();
	    return(true);
	}else
	{
	    return(false);
	}
    }

    /**
     * ray
     */
    // public reqHandle_st commMpi2_sendRays(int destRank, Ray* pRay, int numOfRays);

    // public reqHandle_st commMpi2_recvRays(int srcRank, Ray *pRay, int numOfRays)


    /**
     * send intensity to Frame Buffer
     */
    // public void commMpi2_sendIntensity2FB(IntensityClass *pIntensity, int numOfInt);

    // public void commMpi2_recvIntensity2FB(IntensityClass *pIntensity, int numOfIntensity);


    /**
     * send, recv PEStatus
     */
    // public void commMpi2_sendPEstat2Host(PEStatClass *pPEstat);
    // public void commMpi2_recvPEstat(PEStatClass *pPEstat);

    /**
     * send, recv Intensity value and vertex position
     */
    // public reqHandle_st commMpi2_sendIntVer(int destRank, intVerClass *pIntver);
    // public void commMpi2_recvIntVer(int srcRank,  intVerClass *pIntver);

    /**
     * send, recv object
     *	1 PE の場合,実際には通信しないのでこの関数で直接宛先(通常は 
     *	host)に書いてしまう．  
     */
    // public void sendIntensityStandAlone(IntensityClass *pObj, int numOfObj);
}



