#ifndef POST_CCMIO_CPP
#define POST_CCMIO_CPP

#include "PostCCMIO.h"
#include <iostream>

using namespace std;

void ReadPostScalar( CCMIOError& error, CCMIOID field, vector<int>& mapData,
		     PostField *f, int readingVector = false,
		     int offset = 0, int readingOldVector =false );

PostCCMIO::PostCCMIO( const char *filename, const char *caseName )
{
    int i = 0;
    CCMIOID root, state, proc, solution;
    CCMIOError error = kCCMIONoErr, *err = &error;

    if (CCMIOOpenFile(err, filename, kCCMIORead, &root))
	throw(IOException("Can't open post data from CCMIO file."));
    
    CCMIOGetState(err, root, caseName, NULL, &state);
    CCMIONextEntity(err, state, kCCMIOProcessor, &i, &proc);
    CCMIOReadProcessor(err, proc, NULL, NULL, NULL, &solution);
    if (*err != kCCMIONoErr)
	throw(IOException("No processor data in CCMIO file."));

    ReadPostNode(solution);

    CCMIOCloseFile(err, root);
    if (*err != kCCMIONoErr)
	throw(IOException("Error reading CCMIO post data"));
}

void PostCCMIO::ReadPostNode( CCMIOID& solution )
{
    bool oldPost = false;
    char name[256] = "", fieldName[kCCMIOMaxStringLength + 1];
    int i = 0, phaseIdx;
    unsigned int n = 0;
    CCMIOID field, phase;
    CCMIODimensionality dims;
    CCMIOError error = kCCMIONoErr, *err = &error;
    PostField *f;

    if (CCMIONextEntity(NULL, solution, kCCMIOFieldPhase, &i, &phase)
								 == kCCMIONoErr)
	oldPost = true;
    
    while (CCMIONextEntity(NULL, solution, kCCMIOFieldPhase, &i, &phase) == kCCMIONoErr || oldPost)
    {
	while (CCMIONextEntity(NULL, phase, kCCMIOField, &i, &field)
								 == kCCMIONoErr)
	{
	    if (oldPost)
	    {
		phase = solution;
		oldPost = false;
	    }

	    CCMIOReadField(err, field, fieldName, NULL, &dims, NULL);
	    CCMIOGetEntityIndex(err, phase, &phaseIdx);
	    sprintf(name, "%s (phase %d)", name, phaseIdx);
	    if (dims == kCCMIOScalar)
		f = new PostScalarField((name));
	    else if (dims == kCCMIOVector)
		f = new PostVectorField(name);

	    vector<int> mapData;
	    switch (dims)
	    {
		case kCCMIOScalar:
		{
		    ReadPostScalar(error, field, mapData, f);
		    break;
		}
		case kCCMIOVector:
		{
		    CCMIOID scalar;
		    CCMIOReadMultiDimensionalFieldData(err, field,
						       kCCMIOVectorX, &scalar);
		    if (error == kCCMIOVersionErr)
		    {
			ReadPostScalar(error, scalar, mapData, f, true, 0,true);
		    }
		    else
		    {
			ReadPostScalar(error, scalar, mapData, f, true, 0);
			CCMIOReadMultiDimensionalFieldData(err, field,
							   kCCMIOVectorY,
							   &scalar);
			ReadPostScalar(error, scalar, mapData, f, true, 1);
			CCMIOReadMultiDimensionalFieldData(err, field,
							   kCCMIOVectorZ,
							   &scalar);
			ReadPostScalar(error, scalar, mapData, f, true, 2);
		    }
		}
		break;
	        case kCCMIOTensor:
		    cout << "Tensor data not supported. Ignoring field "
			 << name << "." << endl;
		    continue;
	    }
	    for (unsigned int k = 0;  k < n;  ++k)
		f->cellmap[mapData[k]] = true;
	    this->fields[name] = f;
	}
    }
}

void ReadPostScalar( CCMIOError& error, CCMIOID field, vector<int>& mapData,
		     PostField *f, int readingVector /*= false*/,
		     int offset /*= 0*/, int readingOldVector /*=false*/ )
{
    unsigned int n, max;
    int j = 0;
    CCMIOID fieldData, mapID;
    CCMIODataLocation type;

    // Read each piece of field data
    while (CCMIONextEntity(NULL, field, kCCMIOFieldData, &j, &fieldData)
								 == kCCMIONoErr)
    {
	CCMIOEntitySize(&error, fieldData, &n, &max);
	mapData.resize(n);
	CCMIOReadFieldDataf(&error, fieldData, &mapID, &type, NULL,
			    kCCMIOStart, kCCMIOEnd);
	CCMIOReadMap(&error, mapID, &mapData[0], kCCMIOStart, kCCMIOEnd);

	if (type == kCCMIOCell)
	{
	    if (readingVector)
		f->data.resize(3 * n + 1);
	    else
		f->data.resize(n + 1);
	    f->cellmap.resize(max + 1, false);
	    vector<float> data(n);
	    CCMIOReadFieldDataf(&error, fieldData, &mapID, NULL, &data[0],
				kCCMIOStart, kCCMIOEnd);
	    if (readingVector && !readingOldVector)
	    {
		for (unsigned int i = 0;  i < n;  ++i)
		    f->data[3 + 3 * i + offset] = data[i];
	    }
	    else
	    {
		for (unsigned int i = 0;  i < n;  ++i)
		    f->data[1 + i] = data[i];
	    }
	}
    }
}

#endif // POST_CCMIO_CPP
