/*****************************************************************************
*
* Copyright (c) 2000 - 2017, 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.
*
*****************************************************************************/

// ************************************************************************* //
//                            avtHDFSFileFormat.C                           //
// ************************************************************************* //

#include <avtHDFSFileFormat.h>

#include <map>
#include <string>

#include <vtkCellData.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkType.h>
#include <vtkUnsignedCharArray.h>
#include <vtkUnstructuredGrid.h>

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

#include <FileFunctions.h>
#include <InvalidVariableException.h>
#include <snprintf.h>

using std::map;
using std::string;

// ****************************************************************************
//  Method: avtHDFSFileFormat constructor
//
//  Programmer: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

avtHDFSFileFormat::avtHDFSFileFormat(const char *filename)
    : avtSTSDFileFormat(filename)
{
    coords_filename = string(filename);
    if (FileFunctions::Basename(coords_filename) == "coords.txt.bz2")
    {
        topo_filename = FileFunctions::Dirname(coords_filename) + "/" +
                        "topology.txt.bz2";
    }
    else
    {
        topo_filename = FileFunctions::Dirname(coords_filename) + "/" +
                        FileFunctions::Basename(coords_filename, "_coords.txt.bz2") +
                        "_topology.txt.bz2";
    }
}


// ****************************************************************************
//  Method: avtHDFSFileFormat::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: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

void
avtHDFSFileFormat::FreeUpResources(void)
{
}


// ****************************************************************************
//  Method: avtHDFSFileFormat::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: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

void
avtHDFSFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md)
{
#ifdef PARALLEL
    if (PAR_Rank() != 0)
        goto PopulateDatabaseMetaData_done;
    if (!avtDatabase::OnlyServeUpMetaData())
        goto PopulateDatabaseMetaData_done;
#endif

    // "filename" should be a dir (a block, a mesh, a timestate, a database)

    // If at timestate level, open states.txt.bz2 to get their number
    //     cd state 0, for each mesh, compute num blocks
    //         divide work on blocks across ranks to get vars in each block
    //         read first line of vars file to get centering (from %8)
    //         need to convert first key to actual number, can probably just wory about last 6 digits 
    // If at mesh level, same work from mesh down but only for this mesh
    // If at block level, same work from block down but only for one rank

    // descend to where file blocks.txt.bz2 exists
    // get number of blocks (read dir or bzcat blocks.txt.bz2)
    // If open just a block, cd .. to get meshname
    // If at timestate level
    
#if 0
    int mode = -1;
    FileFunctions::VisItStat_t stat_buf;
    FileFunctions::VisItStat(this->filename, &stat_buf);
    if (stat_buf.st_mode & S_IFDIR)
        mode = 0;
    else if (stat_buf.st_mode & S_IFREG)
        mode = 1;
#endif

    AddMeshToMetaData(md, "mesh", AVT_UNSTRUCTURED_MESH, NULL, 1, 0, 3, 3);

#ifdef PARALLEL
PopulateDatabaseMetaData_done:
    ;

    // broadcast metadata
#endif
}

// ****************************************************************************
//  Method: avtHDFSFileFormat::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: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

vtkDataSet *
avtHDFSFileFormat::GetMesh(const char *meshname)
{
#if defined(_WIN32)
    // Figure out bzcat via popen doesn't appear portable.
    return NULL;
#else
    // open the coords.txt.bz2 file and read it
    char key[32];
    double c[3];
    int ghost;
    bool hasGhostNodes = false;
    map<string, int> nodeKeyMap;
    vtkPoints *points = vtkPoints::New();
    vtkUnsignedCharArray *ghostNodes = vtkUnsignedCharArray::New();
    string bzcmd = "bzcat " + coords_filename;
    FILE *coords_file = popen(bzcmd.c_str(), "r");
    int i = 0;
    while (fscanf(coords_file, "%18s,%d,%lg,%lg,%lg\n", key, &ghost, &c[0], &c[1], &c[2])==5)
    {
        points->InsertNextPoint(c[0],c[1],c[2]);
        nodeKeyMap[string(key)] = i++;
        ghostNodes->InsertNextTuple1((unsigned char) ghost);
        if (ghost) hasGhostNodes = true;
    }
    pclose(coords_file);

    vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::New();
    ugrid->SetPoints(points);
    points->Delete();

    if (hasGhostNodes)
    {
        ghostNodes->SetName("avtGhostNodes");
        ugrid->GetPointData()->AddArray(ghostNodes);
    }
    ghostNodes->Delete();

    bool hasGhostZones = false;
    vtkUnsignedCharArray *ghostZones = vtkUnsignedCharArray::New();
    bzcmd = "bzcat " + topo_filename;
    FILE *topo_file = popen(bzcmd.c_str(), "r");
    int cnt, type;
    while (fscanf(topo_file, "%18s,%d,%d,%d", key, &ghost, &type, &cnt)==4)
    {
        vtkIdType ids[10];
        for (i = 0; i < cnt; i++)
        {
            if (i == cnt - 1)
                fscanf(topo_file, ",%18s", key);
            else
                fscanf(topo_file, ",%18s", key);
            ids[i] = (vtkIdType) nodeKeyMap[string(key)];
        }
        ugrid->InsertNextCell(type, cnt, ids);
        ghostZones->InsertNextTuple1((unsigned char) ghost);
        if (ghost) hasGhostZones = true;
    }
    pclose(topo_file);

    if (hasGhostZones)
    {
        ghostZones->SetName("avtGhostZones");
        ugrid->GetCellData()->AddArray(ghostZones);
    }
    ghostZones->Delete();

    return ugrid;
#endif
}

// ****************************************************************************
//  Method: avtHDFSFileFormat::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: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

vtkDataArray *
avtHDFSFileFormat::GetVar(const char *varname)
{
    return 0;
}


// ****************************************************************************
//  Method: avtHDFSFileFormat::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: miller86 -- generated by xml2avt
//  Creation:   Tue Sep 15 18:47:11 PST 2015
//
// ****************************************************************************

vtkDataArray *
avtHDFSFileFormat::GetVectorVar(const char *varname)
{
    return 0;
}
