#include <vtkDataSet.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkFieldData.h>
#include <vtkDataObject.h>
#include <vtkAlgorithmOutput.h>
#include <vtkAlgorithm.h>
#include <vtkObject.h>

void Commatize(long int number, unsigned char *string) {
    char snum[128]="";
    int sidx, didx; // source & dest index
    int commaCtr;

    memset(string, 0, strlen((char*)string));
    sprintf(snum, "%li", number);
    
    didx = sidx = 0;
    commaCtr = strlen(snum) % 3;

    if (number < 0) {
        // skip the leading - sign
        if (commaCtr == 1) 
            commaCtr = 4;
    }
    for(; sidx<strlen(snum); sidx++, didx++) {
        string[didx] = snum[sidx];
        if (--commaCtr == 0) {
            commaCtr = 3;
            string[++didx] = ',';
        }
    }
    string[strlen((char*)string)-1] = 0;
}

void PrintStatistics(vtkDataSet *ptr) {/*{{{*/
    int n,i;
    double range[2];
    double *bounds;
    double length;
    unsigned long memory;
    unsigned char numtext[128] = "";
    ptr->Update();
    printf("i ============= Data Statistics ==================\n");
    printf("i Data is a \"%s\" from a \"%s\"\n",
            ptr->GetClassName(),
            ptr->GetProducerPort()->GetProducer()->GetClassName());
    printf("i Dimensions:\n");
    bounds = ptr->GetBounds();
    printf("i\tX Range:\t%f\t%f\n", bounds[0], bounds[1]);
    printf("i\tY Range:\t%f\t%f\n", bounds[2], bounds[3]);
    printf("i\tZ Range:\t%f\t%f\n", bounds[4], bounds[5]);
    bounds = ptr->GetCenter();
    printf("i\tCenter:\t(%f, %f, %f)\n", bounds[0], bounds[1], bounds[2]);
    length = ptr->GetLength();
    printf("i\tDiagonal Length: %f\n", length);
    Commatize(ptr->GetNumberOfPoints(), numtext);
    printf("i\t# of Points: %s\n", numtext);
    Commatize(ptr->GetNumberOfCells(), numtext);
    printf("i\t# of Cells: %s\n", numtext);

    memory = ptr->GetActualMemorySize();
    if (memory < (2<<10) * 10) {
        printf("i\tReported Memory Usage: %li kB\n", memory);
    } else if (memory < (2<<20) * 10) {
        printf("i\tReported Memory Usage: %li MB\n", memory >> 10);
    } else {
        printf("i\tReported Memory Usage: %li GB\n", memory >> 20);
    }

    if (ptr->GetFieldData() != NULL) {/*{{{*/
        vtkFieldData *dataptr = ptr->GetFieldData();
        printf("f FIELD Data contains %i components in %i arrays.\n",
                    dataptr->GetNumberOfComponents(),
                    dataptr->GetNumberOfArrays());
        for(n=0; n < dataptr->GetNumberOfArrays(); n++) {
            printf("f\tArray [%d]: %s \"%s\", %li points, %li bytes per point\n", n, 
                dataptr->GetArray(n)->GetClassName(),
                dataptr->GetArrayName(n),
                dataptr->GetArray(n)->GetNumberOfTuples(),
                vtkDataArray::GetDataTypeSize(dataptr->GetArray(n)->GetDataType()));
            dataptr->GetArray(n)->GetRange(range,-1);
            printf("f\t\t\tMagnitude Range:\t%.4f\t%.4f\n",
                        range[0], range[1]);
            for(i=0; i<dataptr->GetArray(n)->GetNumberOfComponents();i++) {
                dataptr->GetArray(n)->GetRange(range,i);
                printf("f\t\t\tComponent %i Range:\t%.4f\t%.4f\n",
                            i, range[0], range[1]);
            }
        }
    } else {
        printf("f No Field Data\n");
    }
/*}}}*/
    if (ptr->GetPointData() != NULL) {
        vtkPointData *dataptr = ptr->GetPointData();
        printf("p POINT Data contains %i components in %i arrays.\n",
                    dataptr->GetNumberOfComponents(),
                    dataptr->GetNumberOfArrays());
        for(n=0; n < dataptr->GetNumberOfArrays(); n++) {
            Commatize(dataptr->GetArray(n)->GetNumberOfTuples(), numtext);
            printf("p\tArray [%d]: %s \"%s\", %s points, %li bytes per point\n", n, 
                dataptr->GetArray(n)->GetClassName(),
                dataptr->GetArrayName(n), numtext,
                vtkDataArray::GetDataTypeSize(dataptr->GetArray(n)->GetDataType()));
            dataptr->GetArray(n)->GetRange(range,-1);
            printf("p\t\t\tMagnitude Range:\t%.4f\t%.4f\n",
                        range[0], range[1]);
            for(i=0; i<dataptr->GetArray(n)->GetNumberOfComponents();i++) {
                dataptr->GetArray(n)->GetRange(range,i);
                printf("p\t\t\tComponent %i Range:\t%.4f\t%.4f\n",
                            i, range[0], range[1]);
            }
        }
        printf("p\tActive Arrays:\n");
        if(dataptr->GetScalars()!=NULL) {
            printf("p\t\tScalar Array: \"%s\"\n", dataptr->GetScalars()->GetName());
        }
        if(dataptr->GetVectors()!=NULL) {
            printf("p\t\tVector Array: \"%s\"\n", dataptr->GetVectors()->GetName());
        }
        if(dataptr->GetNormals()!=NULL) {
            printf("p\t\tNormal Array: \"%s\"\n", dataptr->GetNormals()->GetName());
        }
        if(dataptr->GetTCoords()!=NULL) {
            printf("p\t\tTCoord Array: \"%s\"\n", dataptr->GetTCoords()->GetName());
        }
        if(dataptr->GetTensors()!=NULL) {
            printf("p\t\tTensor Array: \"%s\"\n", dataptr->GetTensors()->GetName());
        }
    } else {
        printf("p No Point Data\n");
    }

    if (ptr->GetPointData() != NULL) {
        vtkCellData *dataptr = ptr->GetCellData();
        printf("c CELL Data contains %i components in %i arrays.\n",
                    dataptr->GetNumberOfComponents(),
                    dataptr->GetNumberOfArrays());
        for(n=0; n < dataptr->GetNumberOfArrays(); n++) {
            Commatize(dataptr->GetArray(n)->GetNumberOfTuples(), numtext);
            printf("c\tArray [%d]: %s \"%s\", %s points, %li bytes per point\n", n, 
                dataptr->GetArray(n)->GetClassName(),
                dataptr->GetArrayName(n), numtext,
                vtkDataArray::GetDataTypeSize(dataptr->GetArray(n)->GetDataType()));
            dataptr->GetArray(n)->GetRange(range,-1);
            printf("c\t\t\tMagnitude Range:\t%.4f\t%.4f\n",
                        range[0], range[1]);
            for(i=0; i<dataptr->GetArray(n)->GetNumberOfComponents();i++) {
                dataptr->GetArray(n)->GetRange(range,i);
                printf("c\t\t\tComponent %i Range:\t%.4f\t%.4f\n",
                            i, range[0], range[1]);
            }
        }
        printf("c\tActive Arrays:\n");
        if(dataptr->GetScalars()!=NULL) {
            printf("c\t\tScalar Array: \"%s\"\n", dataptr->GetScalars()->GetName());
        }
        if(dataptr->GetVectors()!=NULL) {
            printf("c\t\tVector Array: \"%s\"\n", dataptr->GetVectors()->GetName());
        }
        if(dataptr->GetNormals()!=NULL) {
            printf("c\t\tNormal Array: \"%s\"\n", dataptr->GetNormals()->GetName());
        }
        if(dataptr->GetTCoords()!=NULL) {
            printf("c\t\tTCoord Array: \"%s\"\n", dataptr->GetTCoords()->GetName());
        }
        if(dataptr->GetTensors()!=NULL) {
            printf("c\t\tTensor Array: \"%s\"\n", dataptr->GetTensors()->GetName());
        }
    } else {
        printf("c No Cell Data\n");
    }
    printf("i ========== End of Data Statistics ===============\n");
}/*}}}*/

