/*****************************************************************************
*
* Copyright (c) 2000 - 2018, Lawrence Livermore National Security, LLC
* Produced at the Lawrence Livermore National Laboratory
* LLNL-CODE-442911
* 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.
*
*****************************************************************************/

// ************************************************************************* //
//                            avtparaDIS_tecplotFileFormat.C                           //
// ************************************************************************* //
#define NO_BOOST 1

#include <avtparaDIS_tecplotFileFormat.h>

#include <string>
#include "RC_cpp_lib/stringutil.h"

#include <vtkFloatArray.h>
#include <vtkPolyData.h>
#include <vtkCellArray.h>
#include <vtkRectilinearGrid.h>
#include <vtkStructuredGrid.h>
#include <vtkUnstructuredGrid.h>

#include <avtDatabaseMetaData.h>

#include <DBOptionsAttributes.h>
#include <Expression.h>
#include <DebugStream.h>

#include <InvalidVariableException.h>

#ifdef PARALLEL
#include <avtParallel.h>
#endif

using     namespace std;


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat constructor
//
//  Programmer: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

avtparaDIS_tecplotFileFormat::avtparaDIS_tecplotFileFormat(const char *filename)
  : avtSTSDFileFormat(filename), mFilename(filename), mNumElems(0), mNumPoints(0), mNumVars(0), 
    mRotateTecplotPoints(false), mOldOrientation(0,0,1), mNewOrientation(0,0,1)
{
    // INITIALIZE DATA MEMBERS
  mVerbosity = DebugStream::GetLevel(); 

#ifdef PARALLEL
  /*!  I keep this here to remind myself how to use MPI.  LOL
    MPI_Comm_rank(MPI_COMM_WORLD, &mProcNum); 
    MPI_Comm_size(MPI_COMM_WORLD, &mNumProcs);  
  */
  // This is the Visit Way: 
  mProcNum = PAR_Rank(); 
  mNumProcs = PAR_Size(); 
#else
  mProcNum = 0; 
  mNumProcs = 1; 
#endif
}


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::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: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

void
avtparaDIS_tecplotFileFormat::FreeUpResources(void)
{
  // This is probably a no-op, but note it just in case:
  debug1 << "avtparaDIS_tecplotFileFormat::FreeUpResources(void)" << endl; 
}


/*!
// ****************************************************************************
//  Method: avtparaDISFileFormat::ParseTecplotHeader
//
//  Purpose:
//      Attempt to arse the header of a tecplot file. Return false on failure.
//      If successful, store some internal information and return true. 
//      
//  Arguments: 
//      tecplotfile is the file to be parsed
//      setnumvars reads the first point to set the number of vars, 
//          which means you cannot read the first point in subsequent operations
//  Programmer: rcook -- 
//  
//
// ****************************************************************************
*/
bool avtparaDIS_tecplotFileFormat::ParseTecplotHeader(ifstream &tecplotfile, bool setnumvars) {  
  if (!tecplotfile) {
    EXCEPTION1(VisItException, "File does not exist or is not readable."); 
  }
  mRotateTecplotPoints = false; 
  debug3 << "Attempting to parse tecplot file " << mFilename << endl;
  try { 
    string token; 
    
    while (token != "N" && tecplotfile.good()) {
      if (token == "VARIABLES") {
        debug3 << "found VARIABLES keyword" << endl; 
        mVariableNames.clear();
        char line[2048]=""; 
        tecplotfile.get(line, 2048); // read the first node
        string lines = line; 
        vector<string> tokens = Split(lines, ','); 
        // now need to store the variable names... 
        if (tokens.size() > 3) {
          size_t varnum = 3; 
          while (varnum < tokens.size()) {
            mVariableNames.push_back(Strip(tokens[varnum]));
            ++varnum;
          }       
        }
        // 
        tecplotfile >> token; 
      }
      if (token == "ORIENTATION") {
        debug2 << "Found ORIENTATION keyword." << endl;
        tecplotfile >> /* mOldOrientation[0] >> mOldOrientation[1] >> mOldOrientation[2] >> */ mNewOrientation[0] >> mNewOrientation[1] >> mNewOrientation[2]; 
        debug3 << "Setting old orientation to (" << mOldOrientation[0] << ", " << mOldOrientation[1] << ", " << mOldOrientation[2] << ") and new orientation to (" << mNewOrientation[0] << ", " << mNewOrientation[1] << ", " << mNewOrientation[2] << ")" << endl; 
        mRotateTecplotPoints = true; 
      }
      tecplotfile >> token; 
    }
    if (!tecplotfile.good()) {
      throw string("Cannot find \"N\" tag in tecplotfile"); 
    }
    tecplotfile >> token >> mNumPoints; // "=" followed by num points
    if (!tecplotfile.good()) {
      throw string("Cannot determine number of points in file."); 
    }
    tecplotfile >> token >> token; // ",", "E"
    if (token != "E") {
      throw string ("Cannot find \"E\" tag in tecplotfile"); 
    }
    tecplotfile >> token >> mNumElems; 
    if (!tecplotfile.good()) {
      throw string ("Cannot determine number of elements in tecplotfile"); 
    }
    tecplotfile >> token >> token >> token >> token; // ",", "F", "=", "FEPOINT,"
    tecplotfile >> token >> token >> mFileType; // "ET", "=", QUADRILATERAL or BRICK
    if (setnumvars) {
      if (mVariableNames.size() > 0) {
        mNumVars = mVariableNames.size(); 
      } else {
        debug2 << "Getting number of variables by counting" << endl; 
        mVariableNames.clear(); 
        char line[2048]=""; 
        // read the first line of data to see how many variables there are:
        tecplotfile.getline(line, 2048); // consume the rest of the current line
        tecplotfile.get(line, 2048); // read the first node
        debug3 << "Looking at line: \"" << line << "\""<< endl;
        string lines = line; 
        vector<string> tokens = Split(lines); 
        if (tokens.size() < 3) {
          throw string("Invalid line for variable: ")+lines; 
        }
        mNumVars = tokens.size()-3;
        debug2 << "Setting mNumVars to " << mNumVars << endl; 
        int i=0; 
        while (i<(int)mNumVars) {
          string varname = string("V")+doubleToString(i); 
          mVariableNames.push_back(varname); 
          ++i; 
        }
      }
    }
    
  } catch (string err) {
    debug2 << "Couldn't parse file " << mFilename << " as tecplot file: " << err << endl; 
    return false; 
  }
  debug2 << "Number of nodes: " << mNumPoints << endl; 
  debug2 << "Number of " << mFileType << "s: " << mNumElems << endl; 
  debug2 << "Number of variables: " << mNumVars << endl; 
  return true; 
}


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::GetTecplotMetaData
//
//  Purpose:
//      Check to see if the file is Tecplot format, if so, set up the metadata
//      accordingly.  
//
//  Programmer: rcook
//  Creation:   Tue Jan 30 14:56:34 PST 2007
//
// ****************************************************************************
bool avtparaDIS_tecplotFileFormat::PopulateTecplotMetaData(avtDatabaseMetaData *md){ 
  
  debug2 << "GetTecplotMetaData called" << endl; 
  // begin parsing to see if this is a recognizable file type
  ifstream tecplotfile(mFilename.c_str()); 
  
  if (!ParseTecplotHeader(tecplotfile, true)) {
    debug1 << "The file is not a recognizable Tecplot-style file." << endl;
    return false; 
  }
  

  debug1 << "The file is a Tecplot-style file." << endl;
  /*!
    =======================================================
    Mesh
    We need a grid mesh for plotting the grid,
    and a point mesh for volume plots. 
    =======================================================
  */ 
    debug3 << "Adding Tecplot-style mesh to metadata." << endl; 
    string meshname = "paraDIS_Tecplot_poly_mesh"; 
    avtMeshType meshtype = AVT_UNSTRUCTURED_MESH; 
    int nblocks = 1; /* This is for multi-domain, we are single-domain self-decomposing */ 
    int block_origin = 0; 
    int spatial_dimension = 3; /* 3D space */ 
    int topological_dimension = 2; /* quads or lines */ 
    //double extents[6] = {0};  /* xx yy zz */
    double *extents = NULL;
    AddMeshToMetaData(md, meshname, meshtype, extents, nblocks, block_origin,
                      spatial_dimension, topological_dimension);

    meshname = "paraDIS_Tecplot_point_mesh"; 
    meshtype = AVT_POINT_MESH;
    AddMeshToMetaData(md, meshname, meshtype, extents, nblocks, block_origin,
                      spatial_dimension, topological_dimension);

    // AddScalarVarToMetaData(md, "cylindrical_bounds", "cylindrical_bounds_mesh", AVT_ZONECENT);
  /*!
    =======================================================
    Variables
    I currently do not see the need to serve up variables for the grid, but it's easy to support in GetTecplotVar() if desired later.
    =======================================================
  */     
    { 
      int varnum=0;
      string varname; 
      while (varnum < (int)mNumVars) {
        varname = string("paraDIS_Tecplot_line_var_") +  mVariableNames[varnum]; 
        debug3 << "Adding tecplot variable " << varname << " to  grid mesh metadata." << endl;
        AddScalarVarToMetaData(md, varname.c_str(), "paraDIS_Tecplot_poly_mesh", AVT_NODECENT);
        
        varname = string("paraDIS_Tecplot_point_var_") +  mVariableNames[varnum]; 
        debug3 << "Adding tecplot variable " << varname << " to  point mesh metadata." << endl;
        AddScalarVarToMetaData(md, varname.c_str(), "paraDIS_Tecplot_point_mesh", AVT_NODECENT);
        ++varnum; 
      }
      // add a constant variable to the mesh to allow translucent bounds
      AddScalarVarToMetaData(md, "constantvalue", "paraDIS_Tecplot_poly_mesh", AVT_NODECENT);
      
    } // end field data variables

    
  md->SetFormatCanDoDomainDecomposition(true);  
  
  return true; 
}

// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::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: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

void
avtparaDIS_tecplotFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md)
{
  debug1 << "starting populateDatabaseMetaData" << endl; 
  debug1 << "avtparaDIS_tecplotFileFormat version " << PARADIS_TECPLOT_VERSION_NUMBER << ", " << PARADIS_TECPLOT_VERSION_DATE << endl;

  /* first segments */ 

  if (!PopulateTecplotMetaData(md)) {
    EXCEPTION1(VisItException, "Cannot get Tecplot metadata from the file."); 
  }

  debug1 << "finishing populateDatabaseMetaData" << endl; 
  return;
    //
    // CODE TO ADD A MESH
    //
    // string meshname = ...
    //
    // AVT_RECTILINEAR_MESH, AVT_CURVILINEAR_MESH, AVT_UNSTRUCTURED_MESH,
    // AVT_POINT_MESH, AVT_SURFACE_MESH, AVT_UNKNOWN_MESH
    // avtMeshType mt = AVT_RECTILINEAR_MESH;
    //
    // int nblocks = 1;  <-- this must be 1 for STSD
    // int block_origin = 0;
    // int spatial_dimension = 2;
    // int topological_dimension = 2;
    // double *extents = NULL;
    //
    // Here's the call that tells the meta-data object that we have a mesh:
    //
    // AddMeshToMetaData(md, meshname, mt, extents, nblocks, block_origin,
    //                   spatial_dimension, topological_dimension);
    //

    //
    // CODE TO ADD A SCALAR VARIABLE
    //
    // string mesh_for_this_var = meshname; // ??? -- could be multiple meshes
    // string varname = ...
    //
    // AVT_NODECENT, AVT_ZONECENT, AVT_UNKNOWN_CENT
    // avtCentering cent = AVT_NODECENT;
    //
    //
    // Here's the call that tells the meta-data object that we have a var:
    //
    // AddScalarVarToMetaData(md, varname, mesh_for_this_var, cent);
    //

    //
    // CODE TO ADD A VECTOR VARIABLE
    //
    // string mesh_for_this_var = meshname; // ??? -- could be multiple meshes
    // string varname = ...
    // int vector_dim = 2;
    //
    // AVT_NODECENT, AVT_ZONECENT, AVT_UNKNOWN_CENT
    // avtCentering cent = AVT_NODECENT;
    //
    //
    // Here's the call that tells the meta-data object that we have a var:
    //
    // AddVectorVarToMetaData(md, varname, mesh_for_this_var, cent,vector_dim);
    //

    //
    // CODE TO ADD A TENSOR VARIABLE
    //
    // string mesh_for_this_var = meshname; // ??? -- could be multiple meshes
    // string varname = ...
    // int tensor_dim = 9;
    //
    // AVT_NODECENT, AVT_ZONECENT, AVT_UNKNOWN_CENT
    // avtCentering cent = AVT_NODECENT;
    //
    //
    // Here's the call that tells the meta-data object that we have a var:
    //
    // AddTensorVarToMetaData(md, varname, mesh_for_this_var, cent,tensor_dim);
    //

    //
    // CODE TO ADD A MATERIAL
    //
    // string mesh_for_mat = meshname; // ??? -- could be multiple meshes
    // string matname = ...
    // int nmats = ...;
    // vector<string> mnames;
    // for (int i = 0 ; i < nmats ; i++)
    // {
    //     char str[32];
    //     sprintf(str, "mat%d", i);
    //     -- or -- 
    //     strcpy(str, "Aluminum");
    //     mnames.push_back(str);
    // }
    // 
    // Here's the call that tells the meta-data object that we have a mat:
    //
    // AddMaterialToMetaData(md, matname, mesh_for_mat, nmats, mnames);
    //
    //
    // Here's the way to add expressions:
    //Expression momentum_expr;
    //momentum_expr.SetName("momentum");
    //momentum_expr.SetDefinition("{u, v}");
    //momentum_expr.SetType(Expression::VectorMeshVar);
    //md->AddExpression(&momentum_expr);
    //Expression KineticEnergy_expr;
    //KineticEnergy_expr.SetName("KineticEnergy");
    //KineticEnergy_expr.SetDefinition("0.5*(momentum*momentum)/(rho*rho)");
    //KineticEnergy_expr.SetType(Expression::ScalarMeshVar);
    //md->AddExpression(&KineticEnergy_expr);
}


void avtparaDIS_tecplotFileFormat::AddCellToMesh(vtkUnstructuredGrid *linemesh, vector<int> &hex) {
  vtkIdType nodeIndices[4]; 
  vtkIdType *ip = nodeIndices; // for printing
  unsigned int segnum = 0; 
  if (mFileType == "QUADRILATERAL") {
    int index = 4;
    while (index--) {
      nodeIndices[index] = hex[index]-1; 
    }
    debug5 << "inserting quadrilateral: " << arrayToString(ip, 4) << endl; 
    linemesh->InsertNextCell(VTK_QUAD, 4, nodeIndices);
   } else if (mFileType == "BRICK") {
    int index, indexnum = 0; (void) index; (void) indexnum;
    // 3 segments connected to vertex 0
    nodeIndices[0] = hex[0]-1;
    nodeIndices[1] = hex[1]-1; 
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[3]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[4]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    
    
    // 3 segments connected to vertex 6
    nodeIndices[0] = hex[6]-1;
    nodeIndices[1] = hex[5]-1; 
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[2]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[7]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    
    
    // 2 segments connected to vertex 4
    nodeIndices[0] = hex[4]-1;
    nodeIndices[1] = hex[5]-1; 
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[7]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    
    // 2 segments connected to vertex 3
    nodeIndices[0] = hex[3]-1;
    nodeIndices[1] = hex[7]-1; 
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[2]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    
    // 2 segments connected to vertex 1
    nodeIndices[0] = hex[1]-1;
    nodeIndices[1] = hex[5]-1; 
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
    nodeIndices[1] = hex[2]-1;
    debug5 << "inserting segment: " << arrayToString(ip, 2) << endl; 
    linemesh->InsertNextCell(VTK_LINE, 2, nodeIndices);
    ++segnum; 
  }
  return;
}


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::GetTecplotMesh
//
//  Purpose:
//      Gets the tecplot mesh.  
//
//  Arguments:
//      none
//
//  Programmer: rcook -- generated by xml2avt
//  Creation:   Tue Jan 30 14:56:34 PST 2007
//
// ****************************************************************************
vtkDataSet    * avtparaDIS_tecplotFileFormat::GetTecplotMesh(const char *meshname) {
  debug2 << "GetTecplotMesh("<<meshname<<")"<<endl;
  int elem=0, point=0;    
  //rclib::Point<float> pointloc; 
  float pointloc[3]; 
  float junk; 
  int index, varnum;  (void) index;
  vector<rclib::Point<float> > tecplotPoints;
  vtkPoints *linepoints = NULL; (void) linepoints;
  vtkPoints *points =  vtkPoints::New();
  points->SetNumberOfPoints(mNumPoints); 
  
  debug2 << "Will read " << mNumPoints << " points "<< endl;
  ifstream tecplotfile(mFilename.c_str()); 
  if (!ParseTecplotHeader(tecplotfile) || !tecplotfile) {
    EXCEPTION1(VisItException, "File does not exist or is not readable."); 
  }
  // accept scientific notation
  tecplotfile.setf(ios::scientific, ios::floatfield); 
  
  while ((size_t)point < mNumPoints) {
    tecplotfile >> pointloc[0] >> pointloc[1] >> pointloc[2]; 
    debug5 << "Read point: (" << pointloc[0] << ", " << pointloc[1] 
           << ", " << pointloc[2] << ")" << endl;
    varnum = mNumVars; 
    while (varnum --) {
      tecplotfile >> junk; 
    }
    if (!tecplotfile.good()) {
      throw string("Error reading point ")+doubleToString(point); 
    }
    if (mRotateTecplotPoints) {
      tecplotPoints.push_back(pointloc); 
    } else {
      points->SetPoint(point, pointloc); 
    }
    ++point; 
  }
  debug2 << "Done reading points" << endl;
  if (mRotateTecplotPoints) {
    debug2 << "Rotating points" << endl;
    rclib::RotatePoints(mOldOrientation, mNewOrientation, tecplotPoints); 
    size_t nodenum = 0; 
    float location[3];       
    while (nodenum < mNumPoints) {
      tecplotPoints[nodenum].Get(location); 
      debug5 << "Setting point " << nodenum << " to (" << location[0] << ", " << location[1] << ", " << location[2] << ")" << endl; 
      points->SetPoint(nodenum, location); 
      ++nodenum; 
    }
  }
  debug3 << "Adding points to mesh" << endl; 
  vtkUnstructuredGrid *mesh = vtkUnstructuredGrid::New(); // reference-counted "new"
  mesh->SetPoints(points); 
  points->Delete();  // memory is not really freed here, I think due to ref counting. From now on, points are by index   

  if (!strcmp(meshname, "paraDIS_Tecplot_point_mesh")) {
    debug2 << "Filling in trivial connectivity for point mesh" << endl; 
    point = 0; 
    vtkIdType onevertex[1]; 
    while ((size_t)point < mNumPoints) {
      *onevertex = point; 
      mesh->InsertNextCell(VTK_VERTEX, 1, onevertex); 
      ++point; 
    }
  } 
  else if (!strcmp(meshname, "paraDIS_Tecplot_poly_mesh")) {
    debug2 << "Adding mesh elements to line mesh" << endl; 
    int vertsPerElem = -1; 
    if (mFileType == "BRICK") {
      vertsPerElem = 8;
    } else if (mFileType == "QUADRILATERAL") {
      vertsPerElem = 4;
    }  else {
      throw string("Unknown tecplot file format: ")+mFileType;      
    }
    vector<int> cell; 
    while ((size_t)elem < mNumElems) {
      cell.clear(); 
      int index, i=0; 
      debug5 << "Found element with vertices: ("; 
      while (i++<vertsPerElem) {
        tecplotfile >> index; 
        debug5 << index; 
        if (i<vertsPerElem) {
          debug5 << ", "; 
        }
        cell.push_back(index); 
      }
      debug5 << ")"<< endl; 
      
      
      if (!tecplotfile.good()) {
        throw string("Error reading point index ")+doubleToString(i)+string(" in cell ")+doubleToString(elem); 
    }
      AddCellToMesh(mesh, cell); 
      elem++;
    }
  } // end line mesh
  else {
    throw string("Bad tecplot mesh name: ") + meshname; 
  }
  debug2 << "Tecplot file " << mFilename << " parsed successfully" << endl;
  return mesh; 
}

// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::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:
//      meshname    The name of the mesh of interest.  This can be ignored if
//                  there is only one mesh.
//
//  Programmer: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

vtkDataSet *
avtparaDIS_tecplotFileFormat::GetMesh(const char *meshname)
{
  debug2 << "GetMesh("<<meshname<<")"<<endl;
  return GetTecplotMesh(meshname); 

}


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::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:
//      varname    The name of the variable requested.
//
//  Programmer: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

vtkDataArray *
avtparaDIS_tecplotFileFormat::GetVar(const char *varname)
{
  debug2 << "Beginning GetVar(" << varname << ")" << endl; 
  vtkFloatArray *scalars = vtkFloatArray::New(); 
  
  // first look for the "constantvar" variable, it is special
  if (string(varname) == "constantvalue") {
    size_t pointNum = 0;
    float f = 1.0; 
    debug4 << "Inserting "<<mNumPoints << " constant variable values: "<<endl;
    while (pointNum < mNumPoints) {
      scalars->InsertTuple(pointNum,&f);       

      ++pointNum; 
    }
    return scalars; 
  }
  
  
  if (!strstr(varname, "paraDIS_Tecplot_") || !strstr(varname, "_var_")) {
    string err = string("GetTecplotVar: rejected varname ") + varname +" because it does not begin with 'paraDIS_Tecplot_' or does not contain '_var_'";
    EXCEPTION1(VisItException, err.c_str()); 
  }
  /*  Get the variable number. 
      Note that it does not matter if this is the line mesh or the 
      point mesh; the code is identical, so no check for that is done. 
  */ 
  size_t varnum = 0; 
  while (varnum < mNumVars) {
    string::size_type pos = string(varname).rfind(mVariableNames[varnum]);
    if (pos != string::npos) {      
      if (pos != strlen(varname)-mVariableNames[varnum].size()) {
        debug4 << "Warning in GetVar: Found variable name " << mVariableNames[varnum] << " at unexpected position " << pos << " in string " << varname << ".  Expected to find it at end of string, at position " << strlen(varname)-mVariableNames[varnum].size() << ".  I will assume this is the right variable, but something funny might be happening."  << endl; 
      }
      break; 
    }
    ++varnum;
  }
  if (varnum == mNumVars) {
    debug4 << "Warning: possible malformed tecplot variable: Could not determine varnum from apparently valid tecplot variable name: " << varname <<endl;
    return NULL; 
  }
  debug4 << "Looking for varnum " << varnum << endl; 

  /*! 
    Read the appropriate variable from the file 
   */ 
  ifstream tecplotfile(mFilename.c_str()); 
  if (!ParseTecplotHeader(tecplotfile) || !tecplotfile) {
    EXCEPTION1(VisItException, "GetTecplotVar: file does not exist or is not readable."); 
  }
  // accept scientific notation
  tecplotfile.setf(ios::scientific, ios::floatfield); 
  double junk; 
  float f; 
  size_t pointNum = 0; 
  debug4 << "Inserting "<<mNumPoints << " variable values: "<<endl; 
  try {
    while (pointNum < mNumPoints) {
      long varindex = 0; 
      tecplotfile >> junk >> junk >> junk; // location
      while (varindex++ < (long)varnum-1) {
        tecplotfile >> junk; 
      } 
      tecplotfile >> f; 
      while (varindex++ < mNumVars) {
        tecplotfile >> junk; 
      }
      //f= pointNum; 
      scalars->InsertTuple(pointNum,&f); 
      debug5 << f << "\t" ; 
      
      ++pointNum; 
      if (!(pointNum % 10)) { debug5 << endl; }
      if (!tecplotfile) {
        throw string("File integrity failure (failbit is set)"); 
      }     
    }
  } catch(...) {
    string err = string("GetTecplotVar: Error reading variable value for point ") + doubleToString(pointNum); 
    EXCEPTION1(VisItException, err.c_str()); 
  }
  return scalars; 

    //
    // If you have a file format where variables don't apply (for example a
    // strictly polygonal format like the STL (Stereo Lithography) format,
    // then uncomment the code below.
    //
    // EXCEPTION1(InvalidVariableException, varname);
    //

    //
    // If you do have a scalar variable, here is some code that may be helpful.
    //
    // int ntuples = XXX; // this is the number of entries in the variable.
    // vtkFloatArray *rv = vtkFloatArray::New();
    // rv->SetNumberOfTuples(ntuples);
    // for (int i = 0 ; i < ntuples ; i++)
    // {
    //      rv->SetTuple1(i, VAL);  // you must determine value for ith entry.
    // }
    //
    // return rv;
    //
}


// ****************************************************************************
//  Method: avtparaDIS_tecplotFileFormat::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:
//      varname    The name of the variable requested.
//
//  Programmer: rcook -- generated by xml2avt
//  Creation:   Fri Sep 26 12:04:51 PDT 2008
//
// ****************************************************************************

vtkDataArray *
avtparaDIS_tecplotFileFormat::GetVectorVar(const char *varname)
{
  return NULL;
    //
    // If you have a file format where variables don't apply (for example a
    // strictly polygonal format like the STL (Stereo Lithography) format,
    // then uncomment the code below.
    //
    // EXCEPTION1(InvalidVariableException, varname);
    //

    //
    // If you do have a vector variable, here is some code that may be helpful.
    //
    // int ncomps = YYY;  // This is the rank of the vector - typically 2 or 3.
    // int ntuples = XXX; // this is the number of entries in the variable.
    // vtkFloatArray *rv = vtkFloatArray::New();
    // int ucomps = (ncomps == 2 ? 3 : ncomps);
    // rv->SetNumberOfComponents(ucomps);
    // rv->SetNumberOfTuples(ntuples);
    // float *one_entry = new float[ucomps];
    // for (int i = 0 ; i < ntuples ; i++)
    // {
    //      int j;
    //      for (j = 0 ; j < ncomps ; j++)
    //           one_entry[j] = ...
    //      for (j = ncomps ; j < ucomps ; j++)
    //           one_entry[j] = 0.;
    //      rv->SetTuple(i, one_entry); 
    // }
    //
    // delete [] one_entry;
    // return rv;
    //
}
