/*
 * $Id: Mpi2MPI.java,v 1.11.4.1 2000/06/18 18:54:36 yamauchi Exp $
 *     (M\pi)^2 : Mpi2 for Parallel with MPI
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	@author YAMAUCHI Hitoshi 山内 斉
 *	
 * original source main.cc
 *
 * 1999年9月13日(月)
 */

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

import java.io.*;

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

/**
 * for Parallel version with MPI 
 */
public final class Mpi2MPI implements Mpi2Constants, Mpi2Enum {
    /**
     * main
     * 	host computer 
     */
    private static void do_host(int hostrank)
    {
	Host host = Host.getInstance();

	// start up
	host.init(hostrank);
	
	ElapsedTimer.outHostRawTime("start read and deliver data.");
	ElapsedTimer etimer = new ElapsedTimer();
	etimer.start();
	host.readAndDeliverAllData();
	etimer.stop();
	ElapsedTimer.outHostEtime("done read and deliver", etimer);
	ElapsedTimer.outHostRawTime("done read and deliver data.");
	host.barrierSync();

	// radiosity stage
	host.doRadiosity();	// radiosity を始めるというコマンド送信
	host.barrierSync();

	// output radiosity result
	if(FileInfo.getInstance().isRadioStageResultOut() == true)
	{
	    host.getAndOutRadioResult();
	    host.barrierSync();
	}

	// prepare shading 
	host.doPrepareShading();	// shading 
	host.barrierSync();

	// ray-tracing shading 
	host.doRayTracing();	// ray tracing を始めるというコマンド送信
	host.barrierSync();

	// all over	
    }    

    /**
     * main
     *  PE : Processing Element
     */
    private static void do_PE()
    {
	PE pe = PE.getInstance();

	pe.receiveSysInfoNinitSpaceInfo();

	Mpi2CommFactory.getInstance().barrier();	

	pe.receiveMaterials();
	pe.receiveObjects();
	pe.receiveVolume();
	pe.receiveObjInSpcMap();    
	
	if(Mpi2Option.getInstance().getDebugMode() == true)
	{
	    pe.printSysInfo(NORMALHEAD);
	}
	if(Mpi2Option.getInstance().getShowDataMode() == true)
	{
	    pe.printMaterials(NORMALHEAD);
	    pe.printObjects(NORMALHEAD);
	}
	if(Mpi2Option.getInstance().getShowNumobjInSpace() == true)
	{
	    pe.printObjInSpcMap(NORMALHEAD);
	}
	pe.barrierSync();

	/*
	 * radiosity stage 
	 */
	if(Mpi2Option.getInstance().getVerboseMode())
	{
	    ElapsedTimer.outPERawTime("start radiosity stage.");
	}
	ElapsedTimer etimer = new ElapsedTimer();
	etimer.start();
	pe.doRadiosity();
	etimer.stop();		
	ElapsedTimer.outPEEtime("done radiosity stage.", etimer);
	if(Mpi2Option.getInstance().getVerboseMode())
	{
	    ElapsedTimer.outPERawTime("done radiosity stage.");
	}
	if(pe.peekSysInfo().isRadiosityCalc())
	{
	    pe.printStatInfo("Radiosity"); // 統計情報の出力
	}
	pe.barrierSync();

	/*
	 * prepare shading stage 
	 */
	if(Mpi2Option.getInstance().getVerboseMode())
	{
	    ElapsedTimer.outPERawTime("start prepare shading.");
	}
	etimer.reset();
	etimer.start();
	pe.doPrepareShading();
	etimer.stop();		
	ElapsedTimer.outPEEtime("done prepare shading.", etimer);
	if(Mpi2Option.getInstance().getVerboseMode())
	{
	    ElapsedTimer.outPERawTime("done prepare shading.");
	}
	pe.barrierSync();	

	/*
	 * ray-tracing stage 
	 */
	if(Mpi2Option.getInstance().getVerboseMode())	
	{
	    ElapsedTimer.outPERawTime("start ray-tracing stage.");
	}
	etimer.reset();
	etimer.start();
	pe.doRayTracing();
	etimer.stop();		
	ElapsedTimer.outPEEtime("done ray-tracing stage.", etimer);
	if(Mpi2Option.getInstance().getVerboseMode())
	{
	    ElapsedTimer.outPERawTime("done ray-tracing stage.");
	}
	if(pe.peekSysInfo().isRayTracingCalc())
	{
	    pe.printStatInfo("Ray-Tracing"); // 統計情報の出力
	}
	pe.barrierSync();
	//System.out.println(NORMALHEAD + " PE skip/traverse spaces of rays " +
	//	   pe.getSkipSpcOfRays() + "/"+ pe.getTravSpcOfRays());
    }

    /**
     * stand alone (M\pi)^2 main
     */ 
    public static void main(String [] args) 
    {
	// Mpi2CommFactory.initCommunicator(Mpi2Enum.MPI2COMM_mpiJavaS1);
	Mpi2CommFactory.initCommunicator(Mpi2Enum.MPI2COMM_mpiJavaEncoder);
	Mpi2Communicator mpi2comm = Mpi2CommFactory.getInstance();
	String [] mpiretargs = mpi2comm.init(args);
	
	/*--
	 *-- FOR mpiJava
	 *-- mpiJava では args[0] にクラス名を入れることになっているらし
	 *-- い．これについても前田さんがパッチを作成してくれた．
	 *-- 最初にはコマンド名が入っているので除いておく
	 *-- END FOR mpiJava */
	String [] realargs = new String[mpiretargs.length - 1];
	for(int i = 1; i < mpiretargs.length; i++)
	{
	    realargs[i - 1] = mpiretargs[i];
	}
	/*
	  System.out.println("ArgLen = " + realargs.length);
	  for(int i = 0; i < realargs.length; i++)
	  {
	    System.out.println(realargs[i]);
	  }
	 */

	/*
	 * file info by command line option 
	 *  ここでは，全ての Process が command line と conf file が見
	 *  えるとしている 
	 */
	FileInfo optionFIF = null;
	try {
	    optionFIF = Mpi2Option.getopt_newfileinfo(realargs);
	}catch(IllegalArgumentException e)
	{
	    System.out.println(e);
	    Mpi2Option.usage();
	    mpi2comm.exit(1);
	}
	    
	// real file information
	FileInfo fif = FileInfo.getInstance();
	if(!((optionFIF.getConfigFileName()).
	     equals(FileInfo.INIT_FILENAME)))
	{
	    // Option で conf file が指定されていたなら読む
	    fif.setConfigFileName(optionFIF.getConfigFileName());
	    try {
		fif.readConfigFile();
	    }catch(IOException e)
	    {
		System.out.println(e);
	    }
	}

	// コマンドラインオプションをファイルで読み込んだものに上書きする．
	fif.overrideFileInfoWithOption(optionFIF);

	// PrifileMonitor init
	ProfileMon.
	    getInstance().init(SysStat.getInstance().getMyRank(), 
			       FileInfo.getInstance().getTraceFileBaseName());
	
	if(SysStat.getInstance().getMyRank() == 
	   SysStat.getInstance().getHostRank())
	{
	    /*
	     * Host
	     */
	    if(Mpi2Option.getInstance().getVerboseMode())
	    {
		String s = Mpi2Option.getInstance().
		    toStringWithHead(VERBOSEHEAD);
		System.out.println(s);
	    }
	
	    do_host(SysStat.getInstance().getHostRank());
	    Host.getInstance().outResult();
	    // lack of host's destructor 
	    System.out.println("## host : End Parallel Rendering.");
	}else
	{
	    do_PE();
	}
	mpi2comm.finalizecommun();
    }
}
