/*****************************************************************************
*
* 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.
*
*****************************************************************************/

// ************************************************************************* //
//  File: avtRemoveCellsFilter.C
// ************************************************************************* //

#include <avtRemoveCellsFilter.h>

#include <algorithm>

#include <vtkCellData.h>
#include <vtkCellLocator.h>
#include <vtkDataSet.h>
#include <vtkGenericCell.h>
#include <vtkPointData.h>
#include <vtkUnsignedIntArray.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVisItUtility.h>

using namespace std;

// ****************************************************************************
//  Method: avtRemoveCellsFilter constructor
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

avtRemoveCellsFilter::avtRemoveCellsFilter()
{
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter destructor
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
//  Modifications:
//
// ****************************************************************************

avtRemoveCellsFilter::~avtRemoveCellsFilter()
{
}


// ****************************************************************************
//  Method:  avtRemoveCellsFilter::Create
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

avtFilter *
avtRemoveCellsFilter::Create()
{
    return new avtRemoveCellsFilter();
}


// ****************************************************************************
//  Method:      avtRemoveCellsFilter::SetAtts
//
//  Purpose:
//      Sets the state of the filter based on the attribute object.
//
//  Arguments:
//      a        The attributes to use.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

void
avtRemoveCellsFilter::SetAtts(const AttributeGroup *a)
{
    atts = *(const RemoveCellsAttributes*)a;
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::Equivalent
//
//  Purpose:
//      Returns true if creating a new avtRemoveCellsFilter with the given
//      parameters would result in an equivalent avtRemoveCellsFilter.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

bool
avtRemoveCellsFilter::Equivalent(const AttributeGroup *a)
{
    return (atts == *(RemoveCellsAttributes*)a);
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::ExecuteData
//
//  Purpose:
//      Sends the specified input and output through the RemoveCells filter.
//
//  Arguments:
//      in_dr      The input data representation.
//
//  Returns:       The output data representation.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
//  Modifications:
//
//    Hank Childs, Thu Mar 10 09:55:08 PST 2005
//    Fix memory leak.
//
//    Eric Brugger, Thu Jul 31 19:27:52 PDT 2014
//    Modified the class to work with avtDataRepresentation.
//
// ****************************************************************************

avtDataRepresentation *
avtRemoveCellsFilter::ExecuteData(avtDataRepresentation *in_dr)
{
    //
    // Get the VTK data set and the domain number.
    //
    vtkDataSet *in_ds = in_dr->GetDataVTK();
    int domain = in_dr->GetDomain();

    vector<int> cells;
    ParseAtts(domain, cells);

    if(cells.size() == 0)
    {
        return in_dr;
    }

    sort(cells.begin(), cells.end());
  
    vtkCellData *inCD = in_ds->GetCellData();
    
    vtkUnstructuredGrid *ug = vtkUnstructuredGrid::New();
    vtkCellData *outCD = ug->GetCellData();
    vtkPoints *pts = vtkVisItUtility::GetPoints(in_ds);
    ug->SetPoints(pts);
    pts->Delete();
    ug->GetPointData()->PassData(in_ds->GetPointData());
    
    int nCells = in_ds->GetNumberOfCells();
    
    ug->Allocate(nCells);
    outCD->CopyAllocate(inCD);

    vtkUnsignedIntArray *origCellArr = 
                (vtkUnsignedIntArray *)inCD->GetArray("avtOriginalCellNumbers");
    unsigned int * origCellNums = NULL;
    if (origCellArr)
        origCellNums = origCellArr->GetPointer(0); 
   
    int i;
    int cIndex = 0;
    vtkGenericCell *cell = vtkGenericCell::New();
    for (i = 0; i < nCells; ++i)
    {
        //
        // If the cell is the next on our list to remove, increment, and skip
        //
        if (origCellNums)
        {
            if (cells[cIndex] == (int)origCellNums[1 + 2 * i])
            {
                ++cIndex;
                continue;
            }
        }
        else if (cells[cIndex] == i)
        {
            ++cIndex;
            continue;
        }
        
        in_ds->GetCell(i, cell);    
        int newId = ug->InsertNextCell(cell->GetCellType(), 
                                       cell->GetPointIds());
        outCD->CopyData(inCD, i, newId);
    }
    cell->Delete();

    outCD->Squeeze();
   
    avtDataRepresentation *out_dr = new avtDataRepresentation(ug,
        in_dr->GetDomain(), in_dr->GetLabel());

    ug->Delete();

    return out_dr;
}

// ****************************************************************************
//  Method: avtRemoveCellsFilter::ParseAtts
//
//  Purpose:
//      Parse the information in the attributes, and get out a list of
//      cells for a specified domain.
//
//  Arguments:
//      domain      The domain to look in.
//      cells       The vector to fill with cell ids.
//
//  Programmer: Akira Haddox
//  Creation:   June 2, 2003
//
// ****************************************************************************

void
avtRemoveCellsFilter::ParseAtts(int domain, vector<int> &cells)
{
    const vector<int> &cV = atts.GetCellList();
    const vector<int> &dV = atts.GetDomainList();
    
    for (size_t i = 0; i < cV.size(); ++i)
    {
        if (dV[i] == domain)
            cells.push_back(cV[i]);
    }
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::UpdateDataObjectInfo
//
//  Purpose:
//      Indicates the zones no longer correspond to the original problem.
//
//  Programmer: Akira Haddox
//  Creation:   June 2, 2003
//
//  Modifications:
//    Brad Whitlock, Mon Apr  7 15:55:02 PDT 2014
//    Add filter metadata used in export.
//    Work partially supported by DOE Grant SC0007548.
//
// ****************************************************************************

void
avtRemoveCellsFilter::UpdateDataObjectInfo(void)
{
    GetOutput()->GetInfo().GetValidity().InvalidateZones();
    GetOutput()->GetInfo().GetAttributes().AddFilterMetaData("RemoveCells");
}
