//------------------------------------------------------------
// $Id: main.cc,v 1.7.2.1 2000/06/14 15:00:11 yamauchi Exp $
//------------------------------------------------------------
//	main for data read test
//
//	1998年12月15日(月)
//	Copyright (C) 1998 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
#ifndef READTEST
# error "This main is for read file test."
#endif

#define THIS_IS_GLOBAL_DEFINE_FILE
#include "Option.h"
#include "FileInfo.h"
#include "constants.h"
#include "SpaceParam.h"
#include "SLList.h"
#include "mpi2_funcs.h"
#include "material.h"
#include "mpi2ReaderClass.h"
#include "version.h"
#include "ElapsedTimer.h"

#define  OUTPUT_SHARP_PAR_PRIMITIVES 10000

// external functions
extern void getOption(int argc, char *argv[], FileInfo *pCommandLineFinfo);

// exit 
void commMpi2_exit(int errnum)
{
    if(errnum != 2)		// このファイルで致命的でない errcode 
    {				// は 2 にしてある 
	exit(errnum);
    }
}


//------------------------------------------------------------
// usage
//------------------------------------------------------------
void usage(const char * const com_name)
{
    cerr <<"Usage: " << com_name << " [-dhvsS]" << endl;
    cerr <<"\t[--spc] spcfile [--mat] materialfile [--geo] geometryfile\n";
    cerr <<"\t[--vinl] volume infile list file\n";
    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|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  \tmat  ... material information file\n";
    cerr << "\t  \tgeo  ... geometry information file.'(stdin)' is also OK.\n";
    cerr << "\t  \tvinl ... volume data infile list file\n";
    cerr << "\t  contents of conf file is override with other options.\n";
    cerr << com_name << " can recognize other mpi2 options.\n";
    cerr << "but it may be no mean except belows."	<< endl;
    cerr << "	By YAMAUCHI Hitoshi and (Mpi)2 term of Namkamura lab."<< endl;
    cerr << "	   TOU Yuichiro, MAEDA Takayuki, TOKUNAGA Mayumi" << endl;
    cerr << MPI2_VERSION 					  << endl;
    exit(1);
}


inline int getSubSpcIndex(int x, int y, int z, int onedimsize)
{
    // x + onedimsize * y + onedimsize * onedimsize * z
    return(x + onedimsize * (y + onedimsize * z));
}

/*
 * output object table 
 */
void outputObjectTable(int *pObjNumTable, const int spcDevNum)
{
    int max = 0;
    int minButNotZero = INT_MAX;

    for(int z = 0; z < spcDevNum; z++)
    {
	for(int y = 0; y < spcDevNum; y++)
	{
	    cout << "[x][" << y << "][" << z << "] ";
	    for(int x = 0; x < spcDevNum; x++)
	    {
		int idx = getSubSpcIndex(x, y, z, spcDevNum);
		if(pObjNumTable[idx] > max)
		{
		    max = pObjNumTable[idx];
		}
		if((pObjNumTable[idx] > 0) &&
		   (minButNotZero > pObjNumTable[idx]))
		{
		    minButNotZero = pObjNumTable[idx];
		}

		cout << pObjNumTable[idx];
		if((x + 1) % 20 != 0)
		{
		    cout << " ";
		}else
		{
		    cout << endl;
		}
	    }
	    cout << endl;
	}
    }
    cout << "Max polygons in a subspace = " << max 
	 << ", Min polygons but not zero = " << minButNotZero << endl;
}

/*
 * main
 */
int main(int argc, char *argv[])
{
    FileInfo commandLineFinfo;
    getOption(argc, argv, &commandLineFinfo);
    setFileInfo(commandLineFinfo);
    
    FileInfo *pFI = FileInfo::getInstance();

    // space information file
    cout << NORMALHEAD << "--- Checking spcfile [" << 
    pFI->getSpcFileName() << "]---" << endl;
    SpaceParam 	spcParam;	
    if(readSpcparamFile(pFI->getSpcFileName(), &spcParam) == NO)
    {
	cerr << "Error! : fail reading spcfile " << 
		pFI->getSpcFileName() << endl;
	commMpi2_exit(1);
    }
    spcParam.print(NORMALHEAD);
    Vector3 spcPartMin  = spcParam.getPartVolumeMin();
    const int spcDevNum = spcParam.getSubDivNum();
    Vector3 subSpcSize = (spcParam.getPartVolumeMax() - spcPartMin)/ spcDevNum;

    // the number of object in each subspace 
    const int totalSpcNum = spcDevNum * spcDevNum * spcDevNum;
    int *pObjNumTable = new int[totalSpcNum];
    for(int i = 0; i < totalSpcNum; i++)
    {
	pObjNumTable[i] = 0;
    }

    ElapsedTimerClass etimer; 	
    etimer.start();
    if(pFI->isGeometryFile() == NO)
    {
	cout << "No (geometry && material) file is specified, skip." << endl;
    }
    else
    {
	// material information file
	cout << NORMALHEAD << "--- Check matfile [" << 
		pFI->getMatFileName() << "]--- ... "; 
	SLList < materialClass * > matPtrList;
	if(readMatInfo(pFI->getMatFileName(), &matPtrList) == NO)
	{
	    cerr << "Error! : fail reading matfile " << 
	    	pFI->getMatFileName() <<  endl;
	    commMpi2_exit(1);	
	}
	cout << "done" << endl;
	
	/*
	 * sort material information
	 */
	const int arySize = matPtrList.length();
	materialClass *pMatArray = new materialClass [arySize];
	int i, j;
	for(i = 0; i < arySize; i++)
	{
	    materialClass *pTmpMat = matPtrList.front();
	    pMatArray[i] = (*pTmpMat);
	    matPtrList.del_front();
	    delete pTmpMat;
	}
    
	int minMatIdx = 0;
	materialClass swapArea;
	// 単純選択法で sort する
	for(i = 0; i < (arySize - 1); i++)
	{
	    // i は処理の時に入れ換える所 (処理の進み具合)
	    minMatIdx = i;
	    for(j = (i + 1); j < arySize; j++)	
	    {
		// i+1 から後で最小のものを選ぶ
		if(strncmp(pMatArray[j].getName(), 
			   pMatArray[minMatIdx].getName(), 
			   MAX_MATERIAL_NAME_LEN) < 0)
		{
		    minMatIdx = j;
		}
	    }
	    // i + 1 から後で最小ものは minMatIdx が指している
	    swapArea     = pMatArray[i];
	    pMatArray[i] = pMatArray[minMatIdx];
	    pMatArray[minMatIdx] = swapArea;
	}
	if(Option::getInstance()->getShowDataMode() == YES)
	{
	    for(i = 0; i < arySize; i++)
	    {
		cout << "[" << i << "] " << pMatArray[i] << endl;
	    }
	}
    
	// geometry information file
	cout << "//--- Check geo file [" << pFI->getGeoFileName()
		<< "]---" << endl; 
	objBaseClass *pObj = NULL;		
	int objnum = 0;
	int tkn;
	geoReaderClass geoRead;
	char **ppMatName = new char *[arySize];
	for(i = 0; i < arySize; i++)
	{
	    ppMatName[i] = strnew(pMatArray[i].getName());
	}
	
	if(geoRead.open(pFI->getGeoFileName(), arySize, ppMatName, pMatArray)
	   == NO)
	{
	    cerr << "Error! : can't open geometry file [" << 
	    	pFI->getGeoFileName() << endl;
	    commMpi2_exit(1);
	}
	while((tkn = geoRead.getOneGeoData(&pObj)) != EOF_tkn)
	{
	    objnum++;
	    if(Option::getInstance()->getShowDataMode() == YES)
	    {
		pObj->print(OUTDATAHEAD);
	    }else
	    {
		if((Option::getInstance()->getVerboseMode() == YES) && 
		   (objnum % OUTPUT_SHARP_PAR_PRIMITIVES == 0))
		{
		    cerr << "#";
		}
	    }

	    // record the table
	    IntVec3 iv = pObj->getSpcPos();
	    (pObjNumTable[getSubSpcIndex(iv.get(IntVec3::X), 
					 iv.get(IntVec3::Y), 
					 iv.get(IntVec3::Z), spcDevNum)])++;
	    
	    // check space position 
	    if(pObj->checkSpcPos(spcPartMin, subSpcSize, spcDevNum) == NO)
	    {
		cout << "Error! : inconsistency occur between spcpos and "
		    "object at line " << geoRead.getReadLineNum() << endl;
	    }
	    
	    // check shape of triangle
	    switch(pObj->who())
	    {
	    case TRIANGLE_OBJ_E:
		if(pObj->getArea() <= 0.0)
		{
		    cout << "Error! : area size is too small."  
		    " at line " << geoRead.getReadLineNum() << endl;
		}
		break;
	    case SPHERE_OBJ_E:
	    case NULL_OBJ_E:
	    default:
		break;
	    }
	    delete pObj;		// (オブジェクトは new されていたぞ！)
	}	
	if((Option::getInstance()->getShowDataMode() != YES) &&
	   (Option::getInstance()->getVerboseMode() == YES))
	{
	    cerr << endl;
	}
	geoRead.close();
	cout << "read geometry file done" << endl;
    }

    if(pFI->isVolumeFile() == NO)
    {
	cout << "No volume file is specified, skip." << endl;
    }
    else
    {
	cout << "Volume Read is not implemented here" << endl;	// herehere
    }

    outputObjectTable(pObjNumTable, spcDevNum);
    
    etimer.stop();		
    cout << "Readtime = " << etimer.getTotalTime() << endl;

    delete [] pObjNumTable;
}
