#include <ccmio.h>
#include <ccmiocore.h>
#include <ccmioprivate.h>
#include <iostream>

using namespace std;

static const int kNChars = 70;
static const int kNNumbers = 4;

bool PrintNode( CCMIOError *err, CCMIONode origNode, string path );

int main( int argc, char *argv[] )
{
    CCMIOError error;
    CCMIONode rootNode;

    if (argc != 2)
    {
	cout << "Usage:  " << argv[0] << " adffile" << endl;
	return(1);
    }

    error = CCMIOOpen(argv[1], kCCMIORead, &rootNode);
    PrintNode(&error, rootNode, "");
    CCMIOClose(rootNode);
    
    return(0);
}

bool PrintNode( CCMIOError *err, CCMIONode node, string path )
{
    char *bytes = NULL;
    char name[kCCMIOMaxStringLength + 1], label[kCCMIOMaxStringLength + 1];
    int n = 0, nDims, *dims;
    unsigned int size;
    CCMIONode child;
    CCMIODataType type;
    CHECK_ERROR(err);

    CCMIOGetName(err, node, name);
    CCMIOGetLabel(err, node, label);
    CCMIOGetDimensions(err, node, &nDims, &dims);
    CCMIOGetDataType(err, node, &type);
    CCMIOGetDataSize(err, node, &size);

    path += "/";
    if (!IsRootNode(node))
	path += name;

    static const char typeNames[][16] = { "Float32", "Float64", "Int32",
					  "String", "Unknown", "BadType" };
    
    cout << "Node: '" << path << "'"
	 << ((IsRootNode(node)) ? " (a.k.a. 'ADF MotherNode')" : "")
	 << endl;
    cout << "    Label:\t'" << label << "'" << endl;
    cout << "    Type:\t" << typeNames[(int)type] << endl;
    cout << "    Dimensions:\t";
    if (nDims == 0)
	cout << "0  ";
    else
    {
	for (int i = 0;  i < nDims;  ++i)
	    cout << dims[i] << "  ";
    }
    cout << "(" << size << " bytes)";

    if (size)
    {
	bytes = (char *)malloc(size);
	if (!bytes)
	{
	    free(dims);
	    return(*err = kCCMIONoMemoryErr);
	}
	CCMIOReadData(err, node, bytes, type, nDims);
    }

    if (type != kCCMIOUnknownType && type != kCCMIOBadType)
    {
	unsigned int n = 0;
	unsigned int typeSize = CCMIOGetDataTypeSize(type);

	for (unsigned int i = 0;  i < size;  i += typeSize)
	{
	    if (type == kCCMIOString && (n % kNChars) == 0)
		cout << "'" << endl << "(" << n << ")\t'";
	    else if (type != kCCMIOString && (n % kNNumbers) == 0)
		cout << endl << "(" << n << ")\t";
	    else if (type != kCCMIOString)
		cout << "\t";

	    switch (type)
	    {
		case kCCMIOFloat32:
		    cout << *(float *)(bytes + i);
		    break;
		case kCCMIOFloat64:
		    cout << *(double *)(bytes + i);
		    break;
		case kCCMIOInt32:
		    cout << *(int *)(bytes + i);
		    break;
		case kCCMIOString:
		    cout << *(char *)(bytes + i);
		    break;
	    }
	    n++;
	}
    }

    if (type == kCCMIOString && bytes > 0)
	cout << "'";
    cout << endl << endl;

    free(bytes);
    free(dims);

    if (IsRootNode(node))
	path = "";

    while (CCMIOGetNextChild(err, node, &n, &child) == kCCMIONoErr)
	PrintNode(err, child, path);
    if ((*err) == kCCMIONoNodeErr)
	*err = kCCMIONoErr;

    return(*err);
}
