//------------------------------------------------------------
// $Id: readSysinfo.cc,v 1.1.1.1 1999/11/25 06:26:09 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 read sysinfo file 
//	1996/7/11
//	Copyright (C) 1993--1998 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
// Test this routine 
// g++ -DTEST_READSYSINFO -g readsysinfo.cc lineParser.o IntVec3.o Vector3.o myString.o getvals.o -lm -o readsysinfo

#include <stdio.h>
#include <iostream.h>
#include "lineParser.h"
#include "sysinfo.h"


#define MAX_SYSINFO_ARGNUM 4	// sysinfo の entry の引数種類の最大値
const int MAX_LINE 	     = 1024;

//------------------------------
// line parser for sysinfo
//------------------------------
static LineParser *PLp = NULL;

//------------------------------
// initialize line parser
//------------------------------
static void initLPWithSysinfoEntry(void)
{
    const int NumOfNumElem  = 3; // vector
    const int NumOfTypeElem = 8; // type
    const int SYSINFO_ELEM_NUM = NumOfNumElem + NumOfTypeElem;
    PLp = new LineParser(SYSINFO_ELEM_NUM);
    
    // vector
    LineParserNumberElem lpNumElem[NumOfNumElem];     
    lpNumElem[0].set("NumberOfPEs", 3);
    lpNumElem[1].set("ProcRaysAtOnce", 4);
    lpNumElem[2].set("SuspendRayGenParam", 2);    

    int i;
    for(i = 0; i < NumOfNumElem; i++)
    {
	PLp->addEntry(&(lpNumElem[i]));
    }

    // type
    int curlpnum = 0;
    LineParserTypeElem lpTypeElem[NumOfTypeElem];         
    const char *pAllocationScheme[] = {
	"Block", 	"Distributed", "SkewedDistributed", "Random", NULL,
    };
    lpTypeElem[curlpnum].set("AllocationScheme", 4, pAllocationScheme);
    curlpnum++;

    const char *pRadiosityDistributionMethod[] = { 
	"Continuous", "Distribute", 	NULL,				
    };
    lpTypeElem[curlpnum].set("RadiosityDistributionMethod",
			     2, pRadiosityDistributionMethod);
    curlpnum++;
    
    const char *pShadingScheme[] = { 
	"Flat", 	"Gouroud", 	NULL,
    };
    lpTypeElem[curlpnum].set("ShadingScheme", 2, pShadingScheme);    
    curlpnum++;

    const char *pRendering[] = { 
	"radiosity",	"ray-tracing",	"multi-pass", NULL,
    };
    lpTypeElem[curlpnum].set("Rendering", 3, pRendering);    
    curlpnum++;
    
    // add pRayPropSkipMethod and pSystemNetworkType 1998年9月 9日(水)
    const char *pRayPropSkipMethod[] = { 
	"NoSkip", 	"SobokuSkip", 	"ProximityClouds", 	NULL
    };
    lpTypeElem[curlpnum].set("RayPropSkipMethod", 3, pRayPropSkipMethod);    
    curlpnum++;

    // add PRC Map Generation 1999年2月16日(火)
    const char *pPRCGenMethod[] = { 
	"NoPRC", 	"ReadMap", 	"GenerateMap", 	NULL
    };
    lpTypeElem[curlpnum].set("PRCMapGenerationMethod", 3, pPRCGenMethod);    
    curlpnum++;

    const char *pSystemNetworkType[] = { 
	"Torus", 	"MultiStage", 	NULL
    };
    lpTypeElem[curlpnum].set("SystemNetworkType", 2, pSystemNetworkType);    
    curlpnum++;

    // add first ray generation method 1998年5月31日(日)
    const char *pFRGMethod[] = { 
	"AllScan", 	"ScanlineScan", 	"DistributeScan",	NULL
    };
    lpTypeElem[curlpnum].set("FirstRayGenMethod", 3, pFRGMethod);    
    curlpnum++;

    assert(curlpnum == NumOfTypeElem);
    
    // submit all
    for(i = 0; i < NumOfTypeElem; i++)
    {
	PLp->addEntry(&(lpTypeElem[i]));
    }

    // cout << "DEBUG : lineparser" << endl;
    // PLp->print();    // DEBUG LineParser 
};

//------------------------------
// read err message
//------------------------------
void sysInfoReadErr(int line, const char *pErrline, const char *pMes)
{
    cout << "Error! : at line " << line << ": fail to analyze sysinfo" << endl;
    cout << pErrline << pMes << endl;
    commMpi2_exit(1);
}

//------------------------------
// one line analyzer (LineParser で解析できるコマンドは 1 line)
//	この line の解析に成功したら YES を返す
//------------------------------
static void analyzeOneLine(SysInfoClass *pSysinfo, int line, const char *pBuf)
{
    LineParserElemIF *pLPIF = NULL;
    if(PLp->evalOneLine(pBuf, &pLPIF) == YES)
    {
	if(pLPIF->getType() == LP_NUMBER_e)
	{
	    LineParserNumberElem *pLpNum = (LineParserNumberElem *)pLPIF;
	    if(pLpNum->getIdentifier() == "NumberOfPEs")
	    {
		int iv[3];
		assert(pLpNum->getVectorLen() == 3);
		for(int j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    iv[j] = (int)(pLpNum->getVecValue(j));
		}
		pSysinfo->setPEDim(IntVec3(iv));
	    }
	    else if(pLpNum->getIdentifier() == "ProcRaysAtOnce")
	    {
		// case ProcRaysAtOnce_e:
		int iv[4];
		assert(pLpNum->getVectorLen() == 4);
		for(int j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    iv[j] = (int)(pLpNum->getVecValue(j));
		}
		pSysinfo->setProcRaysAtOnce(iv[0], iv[1], iv[2], iv[3]);
	    }
	    else if(pLpNum->getIdentifier() == "SuspendRayGenParam")
	    {
		// case SuspendRayGenParam_e:
		int iv[2];
		assert(pLpNum->getVectorLen() == 2);
		for(int j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    iv[j] = (int)(pLpNum->getVecValue(j));
		}
		pSysinfo->setSuspendRayNums(iv[0], iv[1]);
	    }
	    else
	    {
		sysInfoReadErr(line, pBuf, " no such setnum ");
	    }
	}
	else if(pLPIF->getType() == LP_TYPE_e)
	{
	    LineParserTypeElem *pLpType = (LineParserTypeElem *)pLPIF;
	    if(pLpType->getIdentifier() == "AllocationScheme")
	    {
		// case AllocationScheme_e:
		pSysinfo->setAllocationScheme(pLpType->getTypeNumber());
	    }
	    else if(pLpType->getIdentifier() == "RadiosityDistributionMethod")
	    {
		// case RadiosityDistributionMethod_e:
		switch(pLpType->getTypeNumber())
		{
		case 0:		// 0 ... Continuous
		    pSysinfo->setContinuousRadiation();
		    break;
		case 1:		// 1 ... Distributed
		    pSysinfo->setDistributeRadiation();
		    break;
		default:
		    sysInfoReadErr(line, pBuf, 
				   " no such radiosity distribution ");
		    break;
		}
	    }
	    else if(pLpType->getIdentifier() == "ShadingScheme")	    
	    {
		// case ShadingScheme_e:
		pSysinfo->setShadingScheme(pLpType->getTypeNumber());
	    }
	    else if(pLpType->getIdentifier() == "Rendering")	    
	    {
		// case Rendering_e:
		// "radiosity",	"ray-tracing", "multi-pass", 
		switch(pLpType->getTypeNumber())
		{
		case 0:
		    pSysinfo->setRadiosityCalc();
		    break;
		case 1:
		    pSysinfo->setRayTracingCalc();
		    break;
		case 2:
		    pSysinfo->setRadiosityCalc();
		    pSysinfo->setRayTracingCalc();
		    break;
		default:
		    sysInfoReadErr(line, pBuf, " no such rendering method");
		    break;
		}
	    }
	    else if(pLpType->getIdentifier() == "RayPropSkipMethod")
	    {
		pSysinfo->setRayPropSkipMethod(pLpType->getTypeNumber());
	    }
	    else if(pLpType->getIdentifier() == "PRCMapGenerationMethod")
	    {
		pSysinfo->setPRCMapGenerationMethod(pLpType->getTypeNumber());
	    }
	    else if(pLpType->getIdentifier() == "SystemNetworkType")	    
	    {
		pSysinfo->setSystemNetworkType(pLpType->getTypeNumber());
	    }
	    else if(pLpType->getIdentifier() == "FirstRayGenMethod")	
	    {
		pSysinfo->setFirstRayGenerationMethod(pLpType->
						      getTypeNumber());
	    }
	    else 
	    {
		// default:
		sysInfoReadErr(line, pBuf, " no such settype ");
	    }
	}
    }else
    {
	sysInfoReadErr(line, pBuf, " can not analyze ");	
    }
}

//------------------------------
// read sysinfo 
//------------------------------
YorN readSysinfoFile(const char *pSysinfoFile, SysInfoClass *pSysinfo)
{
    // initialize line parser with sysinfo entries
    initLPWithSysinfoEntry();
 
    FILE *pfp = fopen(pSysinfoFile, "r");
    if(pfp == NULL)
    {
 	cerr << "Error! : can't open sysinfo file [" << pSysinfoFile <<
 	    "]" << endl;
 	return(NO);
    }
    
    char buf[MAX_LINE];
    int line = 0;
    while(fgets(buf, MAX_LINE, pfp) != NULL)
    {
 	line++;
 	// skip comment and void line
 	if(((buf[0] == '/') && (buf[1] == '/'))	|| // //
 	   (buf[0] == '#') 			|| // #
 	   (buf[0] == ' ') 			|| // ' '
	   (buf[0] == '\n')			   // '\n'	   
 	   )
 	{
 	    continue;
 	}
 	analyzeOneLine(pSysinfo, line, buf);
    }
    if(PLp->getNumberofUnparsedEntries() > 0)
    {
	cout << "Warning ! : sysinfo file [" << pSysinfoFile << "] has " 
	    "lack of some entries." << endl;  
	PLp->printUnparsedEntries();
    }
    return(pSysinfo->isContentsOK());
}

//------------------------------------------------------------
// test for read sysinfo
//------------------------------------------------------------
#ifdef TEST_READSYSINFO
void commMpi2_exit(int i)
{
    exit(i);
}

const char* genHd(const char *pHead, const IntVec3& PEid)
{
    static char buf[256];    
    sprintf(buf, "%s PE:: %d %d %d : ", pHead, PEid.get(IntVec3::X), 
	    PEid.get(IntVec3::Y), PEid.get(IntVec3::Z))
    return(buf);
}

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
	cerr << "Usage : " << argv[0] << " sysinfofile" << endl;
	return(1);
    }
    SysInfoClass sysinfo;
    
    if(readSysinfoFile(argv[1], &sysinfo) == NO)
    {
	cerr << "Error! : read fail " << argv[1] << endl;
	commMpi2_exit(1);
    }
    cout << "// host ----- read sysinfo succeeded" << endl;
    sysinfo.print("// ", IntVec3(0, 0, 0));
}
// g++ -DTEST_READSYSINFO -g readsysinfo.cc lineParser.o IntVec3.o Vector3.o myString.o getvals.o -lm
#endif
