// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ************************************************************************* //
//                         avtExtrudedVolFileFormat.C                        //
// ************************************************************************* //

#include <avtExtrudedVolFileFormat.h>

#include <string>
#include <visitstream.h>

#include <vtkCell.h>
#include <vtkCellTypes.h>
#include <vtkDataSetReader.h>
#include <vtkFloatArray.h>
#include <vtkRectilinearGrid.h>
#include <vtkUnstructuredGrid.h>

#include <avtDatabaseMetaData.h>

#include <Expression.h>

#include <InvalidVariableException.h>
#include <InvalidFilesException.h>


using     std::string;


// ****************************************************************************
//  Method: avtExtrudedVol constructor
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

avtExtrudedVolFileFormat::avtExtrudedVolFileFormat(const char *filename, const DBOptionsAttributes *readOpts)
    : avtSTMDFileFormat(&filename, 1)
{
    ifstream ifile(filename);
    if (ifile.fail())
    {
        EXCEPTION1(InvalidFilesException, filename);
    }
 
    std::string tmp;
    ifile >> tmp; // "STEM: ";
    ifile >> tmp;
    stem = tmp;

    ifile >> tmp; // "NUMCHUNKS: ";
    ifile >> tmp;
    numChunks = atoi(tmp.c_str());
    if (numChunks <= 0)
    {
        EXCEPTION1(VisItException, "This does not appear to be a valid "
                                   "ExtrudedVol file.");
    }

    ifile >> tmp; // "NTIMES: ";
    ifile >> tmp;
    nTimesteps = atoi(tmp.c_str());
    if (nTimesteps <= 0)
    {
        EXCEPTION1(VisItException, "This does not appear to be a valid "
                                   "ExtrudedVol file.");
    }

    ifile >> tmp; // "VARIABLES: ";
    ifile >> tmp;
    int nVars = atoi(tmp.c_str());
    if (nVars <= 0)
    {
        EXCEPTION1(VisItException, "This does not appear to be a valid "
                                   "ExtrudedVol file.");
    }
    for (int i = 0 ; i < nVars ; i++)
    {
        ifile >> tmp;
        variables.push_back(tmp);
    }
}


// ****************************************************************************
//  Method: avtExtrudedVolFileFormat::FreeUpResources
//
//  Purpose:
//      When VisIt is done focusing on a particular timestep, it asks that
//      timestep to free up any resources (memory, file descriptors) that
//      it has associated with it.  This method is the mechanism for doing
//      that.
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

void
avtExtrudedVolFileFormat::FreeUpResources(void)
{
}


// ****************************************************************************
//  Method: avtExtrudedVolFileFormat::PopulateDatabaseMetaData
//
//  Purpose:
//      This database meta-data object is like a table of contents for the
//      file.  By populating it, you are telling the rest of VisIt what
//      information it can request from you.
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

void
avtExtrudedVolFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md)
{
    string meshname = "wedge_mesh";
    avtMeshType mt = AVT_UNSTRUCTURED_MESH;
    int nblocks = numChunks;
    int block_origin = 0;
    int spatial_dimension = 3;
    int topological_dimension = 3;
    double *extents = NULL;
    AddMeshToMetaData(md, meshname, mt, extents, nblocks, block_origin,
                      spatial_dimension, topological_dimension);

    string mesh_for_this_var = meshname; 
    for (size_t i = 0 ; i < variables.size() ; i++)
        AddScalarVarToMetaData(md, variables[i], mesh_for_this_var, 
                               AVT_NODECENT);
}


// ****************************************************************************
//  Method: avtExtrudedVolFileFormat::GetMesh
//
//  Purpose:
//      Gets the mesh associated with this file.  The mesh is returned as a
//      derived type of vtkDataSet (ie vtkRectilinearGrid, vtkStructuredGrid,
//      vtkUnstructuredGrid, etc).
//
//  Arguments:
//      domain      The index of the domain.  If there are NDomains, this
//                  value is guaranteed to be between 0 and NDomains-1,
//                  regardless of block origin.
//      meshname    The name of the mesh of interest.  This can be ignored if
//                  there is only one mesh.
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

vtkDataSet *
avtExtrudedVolFileFormat::GetMesh(int domain, const char *meshname)
{
    int   i, j;

    char filename[1024];
    snprintf(filename, 1024, "%s.%d.exvol_conn", stem.c_str(), domain);
    vtkDataSetReader *rdr = vtkDataSetReader::New();
    rdr->SetFileName(filename);
    rdr->Update();
    vtkDataSet *ds = rdr->GetOutput();
    if (ds == NULL || ds->GetDataObjectType() != VTK_POLY_DATA)
    {
        EXCEPTION1(InvalidVariableException, meshname);
    }

    vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::New();
    vtkPoints *pts = vtkPoints::New();
    int npts     = ds->GetNumberOfPoints()*nTimesteps;
    int nOrigPts = ds->GetNumberOfPoints();
    pts->SetNumberOfPoints(npts);

    for (i = 0 ; i < nTimesteps ; i++)
    {
        snprintf(filename, 1024, "%s.%d.%d.exvol_var", stem.c_str(), i,domain);
        ifstream ifile(filename);
        if (ifile.fail())
        {
            EXCEPTION1(InvalidVariableException, meshname);
        }
        int npts;
        ifile >> npts;
        for (j = 0 ; j < nOrigPts ; j++)
        {
            double pt[3];
            ifile >> pt[0];
            ifile >> pt[1];
            ifile >> pt[2];
            pts->SetPoint(i*nOrigPts+j, pt);
        }
    }

    int ncells = ds->GetNumberOfCells()*(nTimesteps-1);
    int ntris  = ds->GetNumberOfCells();
    ugrid->Allocate(ncells*(6+1));
    for (i = 0 ; i < ntris ; i++)
    {
        vtkCell *cell = ds->GetCell(i);
        if (cell->GetCellType() != VTK_TRIANGLE)
        {
            EXCEPTION1(InvalidVariableException, meshname);
        }
        vtkIdType wedge[6];
        wedge[0] = cell->GetPointId(0);
        wedge[1] = cell->GetPointId(1);
        wedge[2] = cell->GetPointId(2);
        for (j = 0 ; j < nTimesteps-1 ; j++)
        {
            wedge[3] = wedge[0] + nOrigPts;
            wedge[4] = wedge[1] + nOrigPts;
            wedge[5] = wedge[2] + nOrigPts;
            ugrid->InsertNextCell(VTK_WEDGE, 6, wedge);
            wedge[0] = wedge[3];
            wedge[1] = wedge[4];
            wedge[2] = wedge[5];
        }
    }
    ugrid->SetPoints(pts);
    pts->Delete();

    return ugrid;
}


// ****************************************************************************
//  Method: avtExtrudedVolFileFormat::GetVar
//
//  Purpose:
//      Gets a scalar variable associated with this file.  Although VTK has
//      support for many different types, the best bet is vtkFloatArray, since
//      that is supported everywhere through VisIt.
//
//  Arguments:
//      domain     The index of the domain.  If there are NDomains, this
//                 value is guaranteed to be between 0 and NDomains-1,
//                 regardless of block origin.
//      varname    The name of the variable requested.
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

vtkDataArray *
avtExtrudedVolFileFormat::GetVar(int domain, const char *varname)
{
    // We could probably do this more efficiently ... but, for now, read in
    // all the data one entry at a time.

    int  i, j, k;
    int  varId = -1;
    for (i = 0 ; i < (int)variables.size() ; i++)
    {
        if (variables[i] == varname)
            varId = i;
    }
    if (varId < 0)
        EXCEPTION1(InvalidVariableException, varname);

    vtkFloatArray *rv = vtkFloatArray::New();

    char filename[1024];
    for (i = 0 ; i < nTimesteps ; i++)
    {
        snprintf(filename, 1024, "%s.%d.%d.exvol_var", stem.c_str(), i,domain);
        ifstream ifile(filename);
        if (ifile.fail())
        {
            EXCEPTION1(InvalidVariableException, varname);
        }
        int npts;
        ifile >> npts;
        if (i == 0)
            rv->SetNumberOfTuples(npts*nTimesteps);

        double val;
        for (k = 0 ; k < npts ; k++)
        {
            ifile >> val; // X
            ifile >> val; // Y
            ifile >> val; // Z
        }
        for (j = 0 ; j < varId ; j++)
            for (k = 0 ; k < npts ; k++)
                ifile >> val;
        for (k = 0 ; k < npts ; k++)
        {
            ifile >> val;
            rv->SetTuple1(i*npts+k, val);
        }
    }

    return rv;
}


// ****************************************************************************
//  Method: avtExtrudedVolFileFormat::GetVectorVar
//
//  Purpose:
//      Gets a vector variable associated with this file.  Although VTK has
//      support for many different types, the best bet is vtkFloatArray, since
//      that is supported everywhere through VisIt.
//
//  Arguments:
//      domain     The index of the domain.  If there are NDomains, this
//                 value is guaranteed to be between 0 and NDomains-1,
//                 regardless of block origin.
//      varname    The name of the variable requested.
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Fri May 18 17:52:04 PST 2007
//
// ****************************************************************************

vtkDataArray *
avtExtrudedVolFileFormat::GetVectorVar(int domain, const char *varname)
{
    EXCEPTION1(InvalidVariableException, varname);
}


