/*****************************************************************************
*
* Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC
* Produced at the Lawrence Livermore National Laboratory
* LLNL-CODE-400124
* All rights reserved.
*
* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The
* full copyright notice is contained in the file COPYRIGHT located at the root
* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
*
* Redistribution  and  use  in  source  and  binary  forms,  with  or  without
* modification, are permitted provided that the following conditions are met:
*
*  - Redistributions of  source code must  retain the above  copyright notice,
*    this list of conditions and the disclaimer below.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
*    documentation and/or other materials provided with the distribution.
*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may
*    be used to endorse or promote products derived from this software without
*    specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,
* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY
* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*****************************************************************************/

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

#include <avtExtrudedVolFileFormat.h>

#include <string>
#include <visitstream.h>
#include <snprintf.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, 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 (int 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 < 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);
}


