//------------------------------------------------------------
// $Id: main.cc,v 1.2 1999/11/28 00:51:04 yamauchi Exp $
//------------------------------------------------------------
//	mpi2 main
//	1996/7/5
//	(C) Copyright Hitoshi Yamauchi
//------------------------------------------------------------
#include <stdio.h>
#include <iostream.h>
#include <iomanip.h>
extern "C" {
#include <sys/types.h>
#include <sys/time.h>
};
#include <new.h>

// #include <VT_trc.h>		// vt trace

#define THIS_IS_GLOBAL_DEFINE_FILE
#include "Option.h"
#include "FileInfo.h"
#include "ProcObj.h"
#include "adjdir.h"
#include "mpi2communication.h"
#include "host.h"
#include "stopwatch.h"
#include "ElapsedTimer.h"
#include "version.h"
#include "mpi2_funcs.h"
#include "ProfileMon.h"

//------------------------------------------------------------
// main
//------------------------------------------------------------
// work of host computer 
static void do_host(int hostrank)
{
    // initialize 
    GpHost->init(hostrank);

    outPERawTime("Host: start read and deliver data.");
    ElapsedTimerClass etimer; 	
    etimer.start();

    GpHost->readAndDeliverAllData();

    etimer.stop();		
    outPERawTime("Host: done read and deliver data.");
    outPEEtime("Host: elapsed time of read and deliver data.", etimer);

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

    // output radiosity result
    if(FileInfo::getInstance()->isRadioStageResultOut() == YES)
    {
        GpHost->getAndOutRadioResult();
	GpHost->barrierSync();
    }

    // prepare shading 
    GpHost->doPrepareShading();	// shading 
    GpHost->barrierSync();

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

    // all over
}    

//------------------------------
// work of Processing Element (host にシンクロして動作する)
//------------------------------
static void do_PE(void)
{
    // VT_trc_stop_c();		// vt trace stop

    //----- receive all data
    GpPE->receiveSysInfoNinitSpaceInfo();
    GpPE->receiveMaterials();
    GpPE->receiveObjects();
    GpPE->receiveVolume();
    GpPE->receiveObjInSpcMap();    
    if(Option::getInstance()->getShowDataMode() == YES)
    {
	GpPE->printSysInfo(  	"// PE");
 	GpPE->printMaterials(	"// PE");
 	GpPE->printObjects(  	"// PE");
    }
    if(Option::getInstance()->getShowNumobjInSpace() == YES)
    {
 	GpPE->printObjInSpcMap(	"// PE");	
    }

    GpPE->barrierSync();

    //------------------------------------------------------------
    // radisoity calculation
    //------------------------------------------------------------
    outPERawTime("start radiosity stage.");
    StopWatchClass watch;    	watch.start();    
    ElapsedTimerClass etimer; 	etimer.start();
    // VT_trc_start_c(9);		// vt trace start
    GpPE->doRadiosity();
    etimer.stop();		outPEEtime("done radiosity stage.", etimer);
    watch.stop(); 		outPEwatch("watch radiosity", watch);
    outPERawTime("done radiosity stage.");

    GpPE->barrierSync();

    // radiosity stage の結果の出力
    if(FileInfo::getInstance()->isRadioStageResultOut() == YES)
    {
        GpPE->sendOutRadioResultToHostAccordHostComm();
	cout << "## PE :: End output radiosity result." << endl;
	GpPE->barrierSync();
    }
    
    GpPE->printStatInfo("Radiosity"); // 統計情報の出力
    
    //------------------------------------------------------------
    // prepare shading 
    //------------------------------------------------------------
    outPERawTime("start prepare shading.");
    watch.start();
    etimer.start();
    GpPE->doPrepareShading();
    etimer.stop();		outPEEtime("done prepare shading.", etimer);
    watch.stop(); 		outPEwatch("watch prepare shading.", watch);
    outPERawTime("done prepare shading.");
    
    GpPE->barrierSync();
    
    //------------------------------------------------------------
    // ray-tracing calculation
    //------------------------------------------------------------
    outPERawTime("start ray-tracing stage.");
    watch.start();
    etimer.start();
    GpPE->doRayTracing();
    etimer.stop();		outPEEtime("done ray-tracing stage.", etimer);
    watch.stop();  		outPEwatch("watch ray-tracing.", watch);
    outPERawTime("done ray-tracing stage.");

    GpPE->barrierSync();

    GpPE->printStatInfo("RayTracing"); // 統計情報の出力
}

//------------------------------------------------------------
// exit new (gcc では default があるが、xlC, mpCC には無いようだ)
// if((somethingPtr = new something) == NULL) の時 call される
//------------------------------------------------------------
void newExit(void)
{
    fputs("Virtual memory exceeded in mpi2 new. exit.\n", stderr);
    commMpi2_exit(1);
}

//------------------------------------------------------------
// usage 
//------------------------------------------------------------
void usage(const char * const com_name)
{
    // 誰かが usage を出力して終了 (ここでは rank == 0 が usage & exit を行う)
    if(SysStat::getInstance()->getMyRank() == 0)
    {
	cerr <<"Usage: " << com_name << " [-dhvsS]" << endl;
	cerr <<"\t[--conf] configfile\n";
	cerr <<"\t[--spc] spcfile [--sys] sysinfofile [--view] viewfile\n";
	cerr <<"\t[--mat] materialfile [--geo] geometryfile\n";
	cerr <<"\t[--vinl] volume infile list file\n";
	cerr <<"\t[[--rado] radiosityresout] [--save[ppm|gfb]] imagesavefile\n"
	    << endl;
	cerr << "  Options:\n";
	cerr << "\t-d\tDebug mode\n";
	cerr << "\t-h\tPrint this message\n";
	cerr << "\t-v\tVerbose mode\n";
	cerr << "\t-s\tShow read data\n";
	cerr << "\t-S\tShow number of objects in subspaces\n";
	cerr << "\t--[conf|sys|view|spc|mat|geo|vinl] identify read file\n";
	cerr << "\t  \tconf ... configuration (all config) file\n";
	cerr << "\t  \tspc  ... space (definespace etc.) file\n";
	cerr << "\t  \tsys  ... system configuration file\n";
	cerr << "\t  \tview ... view file (viewpoint etc.)\n";
	cerr << "\t  \tmat  ... material information file\n";
	cerr << "\t  \tgeo  ... geometry information file\n";
	cerr << "\t  \tvinl ... volume data infile list file\n";
	cerr << "\t  contents of conf file is override with other options.\n";
	cerr << "\t--[rado|save[ppm|gfb]] identify output filename"<< endl;
	cerr << "\t  \trado    ... radiosity result as mpi2 patch(basename)\n";
	cerr << "\t  \tsaveppm ... rendering result as ppm format\n";
	cerr << "\t  \tsavegfb ... rendering result as global frame "
	    "buffer(gfb) format\n";
	cerr << "\t  \t            refer to mpi2.GFBraw.doc\n";
	cerr << "\t--rado is only available in stand alone mode"<<endl;
	cerr << "\t\t(C) YAMAUCHI Hitoshi yamauchi@archi.is.tohoku.ac.jp\n";
	cerr << "(Mpi)2 for MPI version (parallel processing with MPI)";
	cerr << endl;
	cerr << MPI2_VERSION 					<< endl;
    }
    commMpi2_exit(1);	
}


//------------------------------------------------------------
// main
//------------------------------------------------------------
int main(int argc, char *argv[])
{
    set_new_handler(newExit); 
    commMpi2_Init(&argc, &argv);

    int size, rank;
    commMpi2_SizeAndRank(&size, &rank);
    SysStat::getInstance()->setCommSize(size);
    SysStat::getInstance()->setMyRank(rank);
    int hostrank = size - 1; // host のランクは一番最後のやつ 
    SysStat::getInstance()->setHostRank(hostrank);

    // get option 
    FileInfo commandLineFinfo;    
    getOption(argc, argv, &commandLineFinfo);
    setFileInfo(commandLineFinfo);

    // PrifileMonitor init
    ProfileMon::getInstance()->init(SysStat::getInstance()->getMyRank(), 
				    FileInfo::getInstance()->
				    getTraceFileBaseName());

    if(SysStat::getInstance()->getMyRank() == hostrank)
    {
	GpHost = new hostComputerClass;
  	do_host(hostrank);
	GpHost->outResult();
	retrySleep();retrySleep();retrySleep();
	// lack of host's destructor 
	cout << "## host : End Parallel Rendering." << endl;
    }else
    {
	GpPE   = new PEClass;
  	do_PE();
	delete GpPE;
    }
    commMpi2_Finalize();
    return 0;
}
