//------------------------------------------------------------
// $Id: volumeReader.cc,v 1.4 2000/05/21 15:42:18 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 volume reader 
//	read volume 
//	1998/10/1
//	Copyright (C) 1998 YAMAUCHI Hitoshi 山内 斉
// 
// 一つの sub volume (slice) を読み，その情報に従って，sub volume 
// を生成して返す．ここでは一つのファイルごとに読んで返すので，volume 
// の厚みは常に 1 のスライスと同じである．しかし，既に 3 次元中の位置
// などは固定されているので厚さ 1 の volume である．
//
// PNM ファイルを一つの volume として読み込む
// 
//   YorN readOneSubSliceVolume(const myString& subSliceVolumeFileName, 
// 			        SpaceParam&	spcParam,
// 			        YorN  		isDividedVolume, 
// 			        VolumeClass*	pSliceVolume);
//------------------------------------------------------------
#include <stdio.h>
#include <iostream.h>
#include <assert.h>
 
#include "Option.h"
#include "FileInfo.h"
#include "volume.h"
#include "myString.h"
#include "pnmReader.h"
#include "lineParser.h"
#include "volumeInfile.h"
#include "volumeFuncs.h"
#include "array3d.h"
#include "objectInfoInASpace.h"
#include "SpaceParam.h"

#ifdef GENVOL			// generate a volume and subdivide the volume
void deliverOneVolume(VolumeClass *pVol)
{
    // void func : genvol では volume の配送はない．
    pVol = NULL;
}
#else
// #  include "volumeFuncs.h"
#endif				// #ifdef GENVOL

//------------------------------
// volume slice ファイル中のコメントのエントリ識別子
//------------------------------
enum VolumeSliceEntry {
    GridIdx_vse,
    GridPos_vse,
    CellIdx_vse,
    Zdir_vse,
    Partvol_vse,
    Partnum_vse,
    //     Creator_vse, これは lineParse 形式ではないのでやめる
    SizeOfVolumeSliceEntry
};

//------------------------------------------------------------
// local functions
//------------------------------------------------------------
// コメント部分の解析と volume への値のセット
//   char **pBuf			: IN  : volume 情報のある comment 行
//   int commentlines			: IN  : volume 情報のある comment 行数
//   SubGridInfoClass *pSubVolInfo	: OUT : 取り出した subvolume 情報
//   int *pZdir				: OUT : bitmap の 法線方向の向き
//   Vector3 *pPartvolMinPos		: OUT : このスライスの partvol の最小値
//   Vector3 *pPartvolMaxPos		: OUT : このスライスの partvol の最大値
//   int     *pPartnum			: OUT : partnum 
//------------------------------
static void analyzeAndSetVolumeInfo(char **pBuf,  int commentlines,
				    SubGridInfoClass *pSubVolInfo,
				    int *pZdir,
				    Vector3 *pPartvolMinPos, 
				    Vector3 *pPartvolMaxPos,
				    int     *pPartNum
				    )
{
    // line parser :: 作成
    LineParser lp(SizeOfVolumeSliceEntry);
    LineParserNumberElem lpNumElem[SizeOfVolumeSliceEntry];

    // line parser :: 各要素の作成
    lpNumElem[GridIdx_vse].set("gridIdx", 6);
    lpNumElem[GridPos_vse].set("gridPos", 6);
    lpNumElem[CellIdx_vse].set("cellIdx", 3);
    lpNumElem[Zdir_vse].set("zdir", 1);
    lpNumElem[Partvol_vse].set("partvol", 6);
    lpNumElem[Partnum_vse].set("partnum", 1);


    // line parser :: set entries 
    int i;
    for(i = 0; i < SizeOfVolumeSliceEntry; i++)
    {
	lp.addEntry(&(lpNumElem[i]));
    }

    // cout << "DEBUG:: analyzeAndSetVolumeInfo "; lp.print();
    
    // line parser :: eval the buffer
    for(i = 0; i < commentlines; i++)
    {
	if(strncmp(pBuf[i], "creator", 6) == 0)
	{
	    continue;		// creator の行は飛ばす
	}
	LineParserElemIF *pLpIF = NULL;
	if(lp.evalOneLine(pBuf[i], &pLpIF) == YES) 
	{			// YES ならその行は登録したものに一致
	    assert(pLpIF->getType() ==  LP_NUMBER_e);
	    LineParserNumberElem *pLpNum = (LineParserNumberElem *)pLpIF;
	    if(pLpNum->getIdentifier() == "gridIdx") // この == は operator==
	    {
		assert(pLpNum->getVectorLen() == 6);
		// int iv[pLpNum->getVectorLen()];
		int j, iv[6];	// 固定でなくてはならぬコンパイラがある
		for(j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    iv[j] = (int)(pLpNum->getVecValue(j)); 
		}
		pSubVolInfo->setMinIdx(IntVec3(iv[0], iv[1], iv[2]));
		pSubVolInfo->setMaxIdx(IntVec3(iv[3], iv[4], iv[5]));
	    }
	    else if(pLpNum->getIdentifier() == "gridPos")
	    {
		assert(pLpNum->getVectorLen() == 6);
		int j;
		double dval[6];
		for(j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    dval[j] = pLpNum->getVecValue(j); 
		}
		pSubVolInfo->setMinPos(Vector3(dval[0], dval[1], dval[2]));
		pSubVolInfo->setMaxPos(Vector3(dval[3], dval[4], dval[5]));
	    }
	    else if(pLpNum->getIdentifier() == "cellIdx")
	    {
		assert(pLpNum->getVectorLen() == 3);
		int j, iv[3];
		for(j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    iv[j] = (int)(pLpNum->getVecValue(j)); 
		}
		pSubVolInfo->setSpcPos(IntVec3(iv[0], iv[1], iv[2]));
	    }
	    else if(pLpNum->getIdentifier() == "zdir")
	    {
		assert(pLpNum->getVectorLen() == 1);
		(*pZdir) = (int)(pLpNum->getVecValue(0)); 
	    }
	    else if(pLpNum->getIdentifier() == "partvol")
	    {
		assert(pLpNum->getVectorLen() == 6);
		int j;
		double dval[6];
		for(j = 0; j < pLpNum->getVectorLen(); j++)
		{
		    dval[j] = pLpNum->getVecValue(j); 
		}
		pPartvolMinPos->set(dval[0], dval[1], dval[2]);
		pPartvolMaxPos->set(dval[3], dval[4], dval[5]);
	    }
	    else if(pLpNum->getIdentifier() == "partnum")
	    {
		assert(pLpNum->getVectorLen() == 1);
		(*pPartNum) = (int)(pLpNum->getVecValue(0)); 
	    }
	    else
	    {
		cout << "Internal Error!:analyzeAndSetVolumeInfo"  << endl;  
		commMpi2_exit(1);
	    }
	}else
	{
	    cerr << "Illegal line at " << pBuf[i] << endl;
	}
    }

    if(lp.getNumberofUnparsedEntries() > 0)
    {
	cout << "Warning! :: There is unparsed entry." << endl;
	lp.printUnparsedEntries();
	commMpi2_exit(1);
    }
}    

//------------------------------
// initialize sub volume for volume creation
//	global grid info は初期化されているとする
//------------------------------
void initSubVolume(PNMReader *pnmBuf, 
		   const SubGridInfoClass& subGridInfo, int zdir,
		   VolumeClass *pVol)
{
    // global grid は初期化されているはず
    assert((pVol->getGlobalGrid()).isInited() == YES);

    // 今は zdir は一定とする
    if(zdir != 2)
    {
	cout << "Warning! : now implementation assumes zdir == 2" << endl;
    }

    if(pnmBuf->getDepth() != (double)(pVol->getGridRGBDepth()))
    {
	cout << "Error! : detected inconsistency between volin file and "
	     "slice file. (volin depth, slice depth) = ("
	     << pVol->getGridRGBDepth() << " != " << pnmBuf->getDepth() 
	     << ")." << endl;
	commMpi2_exit(1);
    }

    // sub info の初期化
    pVol->initSubGridInfo(subGridInfo);

    // grid を fill する
    pVol->addPNM(pnmBuf);
    
    // subGridInfo を初期化し，effective index を初期化する．
    // effective index は 再計算し，subgrid に含めることにしよう
    // その後，serialize, deserialize をテストし，送受信する．
}


//------------------------------------------------------------
// PNM ファイルからコメントの情報を抜き出して分析にかけ，
// SubGridInfoClass を得る 
// 	@param  pnmBuf 	 [IN]  PNMImage
//	@param  spcParam [IN]  読み込んだ volume はこの spcparam に一致するか
// 	@param  pSgiinfo [OUT] comment 中から抽出された SubGridInfo
// 	@param  pZdir    [OUT] comment 中から抽出された zdir
//	@return YES ならば成功
//------------------------------------------------------------
static YorN getSubGridInfoFromComments(const PNMReader &pnmBuf, 
				       const SpaceParam &spcParam,
				       SubGridInfoClass *pSginfo, 
				       int  *pZdir)
{
    const char *pErrmes = "Error! : getSubGridInfoFromComments ";

    // コメントの行数が少なすぎる場合には分割された volume ファイルか疑わしい．
    if(pnmBuf.getSizeOfComments() < AT_LEAST_COMMENTS_WITHSUBDIVIDED_VOL)
    {
	cout << pErrmes << "This file has too few comments. Is this a "
	    "Subdivided volume file?" << endl;
	return(NO);
    }

    // PNMREADER_MAX_COMMENTS_LINES is defined in pnmReader.h.
    int i;
    char **pBuf = new char*[pnmBuf.getSizeOfComments()];
    for(i = 0; i < pnmBuf.getSizeOfComments(); i++) 
    {
	const char *line = pnmBuf.getCommentsRef(i);
	if(line[0] != '#')
	{
	    // コメントに埋め込んだ要素ではなかった．
	    cout << pErrmes << "illegal comment element : " << line << endl;  
	    return(NO);
	}

	// この行は最初に '# ' があると仮定している．それを除いてコピー
	// する
	// ex. "# setnum gridIdx = 0 0 0 35 35 0"
	//      ^^ ここを飛ばすので [2] から
	//  -> "setnum gridIdx = 0 0 0 35 35 0"
	pBuf[i] = strnew(&(line[2])); 
    }

    //------------------------------
    // line parser を用いて解析する
    //------------------------------
    // スライスに記されている partvol と partnum を受け，比較する
    Vector3 partVolMinofTheSlice, partVolMaxofTheSlice; 
    int     partNumofTheSlice;
    analyzeAndSetVolumeInfo(pBuf, pnmBuf.getSizeOfComments(), pSginfo,
			    pZdir,
			    &partVolMinofTheSlice, &partVolMaxofTheSlice, 
			    &partNumofTheSlice);
    // 後始末
    for(i = 0; i < pnmBuf.getSizeOfComments(); i++) 
    {
	strdel(pBuf[i]);
    }
    delete [] pBuf;

    // 正しい volume を読んでいるかの検査．つまりこの slice file は今
    // の space param に一致しているか?  
    if((spcParam.getPartVolumeMin() == partVolMinofTheSlice) &&
       (spcParam.getPartVolumeMax() == partVolMaxofTheSlice) && 
       (spcParam.getSubDivNum()	    == partNumofTheSlice))
    {
	return(YES);
    }else
    {
	cout << pErrmes << "volume data file is not match with space "
	"parameter." << endl;
	cout << "space parameter is below." << endl;
	spcParam.print("");
	cout << "partvol of the volume file (" << partVolMinofTheSlice << 
	")-(" << partVolMaxofTheSlice << "), partnum = " <<
	partNumofTheSlice << endl;

	return(NO);
    }
}

//------------------------------------------------------------
// 1 つの volume slice file (pgm format)を読みこんで volume image にし
// て返す．これを繰返して一つの volume を読む．(したがってこの関数の名
// 前はこうなる．)
// 
//   @param subSliceVolumeFileName [IN]	 volume slice filename
//   @param spcParam		   [IN]	 volume の正当性の検査の空間情報
//   @param isDividedVolume	   [IN]	 YES の時分割済みの volume を読んでいる
//   @param pSliceVolume	   [OUT] 生成される volume image 
//   @return YES if succeed the read else NO
// 
// isDividedVolume == YES の場合には完全な subvolume を返す
// isDividedVolume == NO  の場合には仮の sub grid info で初期化した 
// 		      volume を返す．これは分割前の slice を読むため．
//		      (これは slice reader から呼ばれる場合)
//------------------------------------------------------------
YorN readOneSubSliceVolume(const myString& subSliceVolumeFileName, 
			   const SpaceParam &spcParam,
			   YorN  isDividedVolume, 
			   VolumeClass *pSliceVolume)
{
    static const char *pErrmes = "Error! : readOneSubSliceVolume : ";
    
    PNMReader pnmBuf;
    if(readOnePNMFile((const char*)subSliceVolumeFileName, &pnmBuf) == 0)
    {
	// pnm ファイルの読み込みに失敗した
	cout << pErrmes << "fail to read the volume slice file [" << 
	    subSliceVolumeFileName << "]" << endl;
	return(NO);
    }
    
    // 既にここでは global grid info は初期化済み
    assert((pSliceVolume->getGlobalGrid()).isInited() == YES);

    // subgrid を初期化する
    SubGridInfoClass sginfo;
    int zdir;
    if(isDividedVolume == YES)
    {
	// volume が分割済み
	if(getSubGridInfoFromComments(pnmBuf, spcParam, &sginfo, &zdir) == NO)
	{
	    cout << pErrmes << "This may an unsubdivided volume or "
	    "wrong volume. [" << subSliceVolumeFileName << "]" << endl;
	    return(NO);
	}

	// volume (pSliceVolume) の生成(初期化)
	initSubVolume(&pnmBuf, sginfo, zdir, pSliceVolume);
    }
    else
    {
	// volume をこれから分割する．まだ分割していない．
	if(pnmBuf.getSizeOfComments() >= AT_LEAST_COMMENTS_WITHSUBDIVIDED_VOL)
	{
	    cout << pErrmes << "This file may already subdivided." << endl;
	    return(NO);
	}

	// z 方向は default : 2 に固定
	zdir = 2; 

	// 分割していない slice の形は正方形であるはず
	if(pnmBuf.getResolSizeX() != pnmBuf.getResolSizeY())
	{
	    cout << "Error! : non divided slice must be squrt "
	        "(width["      << pnmBuf.getResolSizeX() << 
		"] != height[" << pnmBuf.getResolSizeY() << "])" << endl;
	    cout << "illegal file size : [ " << subSliceVolumeFileName
	        << "]" << endl;
	    commMpi2_exit(1);
	}

	// 仮の sginfo を Global Grid Info と pnmBuf から作成する
	int resolmin[3], resolmax[3];
	resolmin[0] = resolmin[1] = resolmin[2] = 0;
	resolmax[0] = pnmBuf.getResolSizeX() - 1; // Max index は 
	resolmax[1] = pnmBuf.getResolSizeY() - 1; // ResolSize - 1 となる
	resolmax[2] = 0;

	sginfo.initAll((pSliceVolume->getGlobalGrid()).getMinPos(),
		       (pSliceVolume->getGlobalGrid()).getMaxPos(),
		       IntVec3(0, 0, 0), IntVec3(resolmin), IntVec3(resolmax));
	initSubVolume(&pnmBuf, sginfo, zdir, pSliceVolume);
    }
    return(YES);
}

//------------------------------------------------------------
// check volume range (define space の内部にあるか)
// 定義空間内にこの volume が収まっているのかを調べる
// 	@param volInfileInfo     [IN] 読み込んだ volume 情報
// 	@param spcParam          [IN] 読み込んだ空間情報
// 	@param pVolumeInfileName [IN] (ファイル名 : エラー時出力用)
//------------------------------
static void checkVolumeRange(const volumeInfileInfoClass& volInfileInfo, 
			      const SpaceParam& spcParam,
			      const char *pVolumeInfileName)
 {
     const char *mes = "Error! : checkVolumeRange ";
     GlobalGridInfoClass ggg = volInfileInfo.getGlobalGridInfo();
     YorN isOK = YES;
     for(int i = 0; i < 3; i++)	// 0..x, 1..y, 2..z
     {
	 if((ggg.getMinPos()).get(i) > (ggg.getMaxPos()).get(i))
	 {
	     cout << mes << "illegal volume position : must be min < max."
	     << endl;
	     isOK = NO;
	 }
	 if(((ggg.getMinPos()).get(i) < (spcParam.getPartVolumeMin()).get(i))||
	    ((spcParam.getPartVolumeMax()).get(i) < (ggg.getMinPos()).get(i)))
	 {
	     cout << mes << "volume minpos is out of define space." << endl;
	     isOK = NO;
	 }
	 if(((ggg.getMaxPos()).get(i) < (spcParam.getPartVolumeMin()).get(i))||
	    ((spcParam.getPartVolumeMax()).get(i) < (ggg.getMaxPos()).get(i)))
	 {
	     cout << mes << "volume maxpos is out of define space." << endl;
	     isOK = NO;
	 }
     }
     if(isOK == NO)
     {
	 cout << "Error! : ----- space param -----" << endl;
	 spcParam.print("");
	 cout << "Error! : ----- volume grobal grid -----" << endl;
	 ggg.print();
	 cout << "Error! : in file [" << pVolumeInfileName << "], "
	 "illegal volume range with space parameter." << endl;
	 commMpi2_exit(1);
     }
 }

 //------------------------------------------------------------
 // volume data の読み込みと配布 sub volume を読む．
 //	volumeInfileListFile ... volumeInfile のリストが書いてある
 //	ここでは volumeInfileListFile を読み，volumeInfile ごとに 
 //	volume を読む 
 //------------------------------
 // 一つの volumeInfile から volume data を読み込み，一つ読むごとにそれ
 // を指定されたメソッドで渡す
 // 
 // @param pVolumeInfilenName 	[IN] 一つの volume の範囲の最大，最小，
 // 				     解像度などを書いたファイル名  
 // @param spcParam 		[IN] 空間情報 : volume 読み込みの際の検査用
 // @param volumeID		[IN] 現在読み込んでいる volume の ID
 // @param pObjNum3dArray	[IN] 読み込んだ volume の存在する部分空間の表
 // @return 読み込みに成功したら YES 
 //------------------------------
 static YorN readOneVolume(const char *pVolumeInfileName, 
			   const SpaceParam& spcParam,
			   int volumeID,
			   array3dClass < objectNumInASpaceClass >
			   *pObjNum3dArray)
 {
     volumeInfileInfoClass volInfileInfo(volumeID);

     // readVolumeInfile ref. volumeInfile.h, readVolumeInfile.cc
     if(readVolumeInfile(pVolumeInfileName, &(volInfileInfo)) == NO)
     {
	 cout << "Error! : read fail [" << pVolumeInfileName << "]" << endl;
	 return(NO);
     }
     if(Option::getInstance()->getVerboseMode() == YES)
     {    
	 volInfileInfo.print(VERBOSEHEAD);
     }

     // 定義空間内にこの volume が収まっているのかを調べる
     checkVolumeRange(volInfileInfo, spcParam, pVolumeInfileName);


     if((Option::getInstance()->getDebugMode()   == NO) && 
	(Option::getInstance()->getVerboseMode() == YES))
     {
	 // ファイルの読み込み状況表示
	 cout << VERBOSEHEAD << "reading volume sequence: ";
     }

     for(int i = volInfileInfo.getSeqStart(); i <= volInfileInfo.getSeqEnd();
	 i    += volInfileInfo.getSeqInc())
     {
	 VolumeClass v;
	 const YorN  isDividedVolume = YES;
	 // global info の初期化
	 v.initGlobalGridInfo(volInfileInfo.getGlobalGridInfo());
	 // local info と grid の内容初期化
	 if(readOneSubSliceVolume(volInfileInfo.getFileName(i), 
				  spcParam, isDividedVolume, &v)
	    == YES)
	 {
	     // volume の読み込みに成功．分配する
	     deliverOneVolume(&v);
	     // 物体存在表を更新する．記録されるのは volume の数ではな
	     // くスライス数 
	     IntVec3 spos = (v.getSubGrid()).getSpcPos();
	     objectNumInASpaceClass onias = pObjNum3dArray->get(spos);
	     onias.mVolNum++;
	     pObjNum3dArray->set(spos, onias);
	 }else
	 {
	     cout << "Error!: fail to read volume [" << 
		 volInfileInfo.getFileName(i) << "]" << endl;
	     return(NO);
	 }

	 if(Option::getInstance()->getDebugMode() == YES)
	 {
	     cout << DEBUGHEAD << " [" << i << "] " << 
		 volInfileInfo.getFileName(i) << endl;
	 }
	 else if(Option::getInstance()->getVerboseMode() == YES)
	 {
	     cout << "[" << i << "]" << flush; // ファイルの読み込み状況表示
	 }
     }
     if((Option::getInstance()->getDebugMode()   == NO) && 
	(Option::getInstance()->getVerboseMode() == YES))
     {
	 cout << endl; // ファイルの読み込み状況表示
     }
     return(YES);
 }

 //------------------------------
 // @param  pVolInfileLists : volume infile (一つの volume についての記
 // 	   		     述) のリストが書いてあるファイル
 // @param  spcParam	   : space parameter 空間情報
 // @param  pObjNum3dArray  : 空間中に volume がどのように存在するかの表
 // @return 読み込んだ volume 数
 //------------------------------
 int readAllVolumeData(const char *const pVolInfileLists,
		      const SpaceParam& spcParam,
		      array3dClass < objectNumInASpaceClass > *pObjNum3dArray)
{
    int numOfVolume = 0;	// 読み込んだ volume 数 (volume ID)
    if(pVolInfileLists == NULL)
    {
	return(numOfVolume); // volume file の指定はない
    }

    FILE *pfp = fopen(pVolInfileLists, "r");
    if(pfp == NULL)
    {
	cout << "Error! : can not open infile list file [" << 
	    pVolInfileLists << "]" << endl;
	commMpi2_exit(1);
    }

    // 順に file を読んでいく
    const int MAX_LINE = 1024;
    char  buf[MAX_LINE];
    int   line = 0;
    while(fgets(buf, MAX_LINE, pfp) != NULL)
    {
	line++;
	if((buf[0] == '#') || (buf[0] == '\n'))	// comment, 空白は除く
	{
	    continue;
	}
	for(int i = 0; buf[i] != '\0'; i++) // chop
	{
	    if(buf[i] == '\n')
	    {
		buf[i] = '\0';
	    }
	}
	
	// volume を一つ読む
	if(readOneVolume(buf, spcParam, numOfVolume, pObjNum3dArray) == YES)
	{
	    numOfVolume++;
	}else
	{
	    cout << FileInfo::getInstance()->getVolumeInFileListName()
		<< ":" << line << ": illegal line." << endl;
	    cout << FileInfo::getInstance()->getVolumeInFileListName()
		<< ":" << line << " " << buf << endl;
	    commMpi2_exit(1);
	}
    }
    fclose(pfp);
    return(numOfVolume);
}

//------------------------------------------------------------
// Test 1:  read subvolume 部分 volume の読み込みテスト
//------------------------------------------------------------
#ifdef TEST_READ_A_SUB_VOLUME
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
	cerr << "usage : svr slicevolumefile" << endl;
	commMpi2_exit(1);
    }
    
    int volumeID = 1;
    IntVec3 globalGridResSize(100, 100, 100);
    Vector3 globalGridMinPos(  0.0,   0.0,   0.0);
    Vector3 globalGridMaxPos(100.0, 100.0, 100.0);
    double  voxelEdgeLen = 2.0;
    GlobalGridInfoClass gginfo;
    gginfo.initAll(volumeID, globalGridResSize, 
		   globalGridMinPos, globalGridMaxPos, voxelEdgeLen);

    VolumeClass v;
    v.initGlobalGridInfo(gginfo);

    if(readOneSubVolume(myString(argv[1]), &v) != YES)
    {
	cout << "Error! : fail to read volume data [" << argv[1] <<
	    "]" << endl;
    }else
    {
	cout << "OK!" << endl;
    }
    cout << "DEBUG at main --------------------" << endl;
    v.print();

    cout << "DEBUG : serialize" << endl;
    int bufsize = v.getSerializedSize();
    double *pSendbuf = v.newSerializedArray();
    
    VolumeClass recvVol;
    recvVol.deserialize(pSendbuf);
    for(int i = 0; i < bufsize; i++)
    {
	pSendbuf[i] = -1.0;
    }
    delete [] pSendbuf;
    cout << "DEBUG : deserialize" << endl;
    recvVol.print();
}
#endif				// #ifdef TEST_READ_A_SUB_VOLUME
// g++ -Wall -g -DTEST_READ_A_SUB_VOLUME -I../mpi2dataReader pnmReader.cc LineParser.cc volumeReader.cc myString.cc volume.cc getvals.cc Vector3.cc IntVec3.cc -o svr 

// imake -DUseInstalled -I/usr/X11R6/lib/X11/config -f Imakefile.volreadtest


//------------------------------------------------------------
// Test 2:  volume を一つ読む
//------------------------------------------------------------
// test read volume infile file and construct a volume
// 	1998年10月30日(金)
// 	このソースと一年近く格闘している．先が見えないなぁ．
//------------------------------------------------------------
#ifdef TEST_READ_VOLUME
#include "Option.h"
optionClass Option; 
void commMpi2_exit(int i)
{
    exit(i);
}

const char* genHd(const char *pHead, const int rank)
{
    static char buf[256];    
    sprintf(buf, "%s rank %d : ", pHead, rank);
    return(buf);    
}

int main(int argc, char *argv[])
{
    Option::getInstance()->setDebugMode();

    if(argc != 3)
    {
	cerr << "Usage : " << argv[0] << " volumeInfileFile " << 
	    "space_param_file" << endl;
	return(1);
    }

    // read space parameter
    SpaceParam spcParam;
    if(readSpcparamFile(argv[2], &spcParam) == NO)
    {
	cout << "Error! : Can't read space param file ["
	    << argv[2] << "]" << endl;
	commMpi2_exit(1);
    }
    cout << "// test ----- read space param succeeded" << endl;
    spcParam.print("//", IntVec3(0, 0, 0));

    // read one volume
    int volumeID = 68000;
    if(readOneVolume(argv[1], volumeID) == NO)
    {
	cerr << "Error! : fail to read a volume accrding to the infile [" 
	    << argv[1] << "]" << endl;
 	commMpi2_exit(1);
    }
}

#endif				// #ifdef TEST_READ_VOLUME

