# create a filter, called 'Get Cell From Points'
#
# this filter will, given one or more point ids, extract any cell using any of
# those points

# How to load filter:
#   - open Paraview
#   - on the Menu Bar, click on Tools -> Manage Plugins
#   - there is a dialog box with two sides, left is Remote Plugins,
#     and right is Local Plugins
#   - if you are using the client-server connection, you need to 
#     load this filter both locally and remotely
#     - Local Instructions
#       - click on the 'Load New' button, near the middle bottom (local side)
#       - choose this file to load
#       - you will see a new plugin called 'getCellsFromPoints' at the bottom
#       - click on the arrow left of 'getCellsFromPoints'
#       - click the box next to 'Auto Load' to make it automatically
#         load in the future
#     - Remote Instructions
#       - click on the 'Load New' button, near the bottom left (remote side)
#       - choose this file to load (will need to copy this file to the
#         remote machine)
#       - you will see a new plugin called 'getCellsFromPoints' at the bottom
#       - click on the arrow left of 'getCellsFromPoints'
#       - click the box next to 'Auto Load' to make it automatically
#         load in the future
#     - click on the 'Close' button
#   - if you are only working locally (no client-server connection)
#     - load the file only on the local side, using the instructions above
#
#   - there is now an available filter called 'Get Cell From Points'.
#   - click on Filters -> Alphabetical -> Get Cell From Points

# How to use filter:
#   - create a 'Get Cell From Points' filter on your dataset
#   - in the Properties tab, there is a box called 'Point Ids'
#     - input however many point ids, seperated by commas
#   - hit the 'Apply' button
#   - all found cells will be shown as a separate grid

import vtk
from vtkmodules.vtkCommonDataModel import vtkDataSet
from vtkmodules.util.vtkAlgorithm import VTKPythonAlgorithmBase
from paraview.util.vtkAlgorithm import smproxy, smproperty

@smproxy.filter(label="Get Cell From Points")
@smproperty.input(name="Input")
class GetNeighborZones(VTKPythonAlgorithmBase):
    """Given a zone id, extract all neighbor cells of that zone"""

    def __init__ (self):
        VTKPythonAlgorithmBase.__init__(self, outputType='vtkUnstructuredGrid')
        self.points = set()

    def RequestData(self, request, inInfo, outInfo):
        in0 = vtkDataSet.GetData(inInfo[0])
        extractedGrids = []

        # iterate through all unstructured grids in the dataset,
        # and accumulate extracted grids which contain cells we want
        if in0.IsA('vtkUnstructuredGrid'):
            extractedGrids.append(self.processGrid(in0))
        elif in0.IsA('vtkMultiBlockDataSet'):
            block = in0.GetBlock(0)
            if block.IsA('vtkMultiPieceDataSet'):
                multipiece = block
                for i in range(multipiece.GetNumberOfPieces()):
                    ug = multipiece.GetPiece(i)
                    # the piece may not be local to this proc, so need to check
                    if ug is not None:
                        extractedGrids.append(self.processGrid(ug))
            else:
                # block is an unstructured grid
                ug = block
                extractedGrids.append(self.processGrid(ug))

        # append all extracted grids together into one dataset
        append = vtk.vtkAppendDataSets()
        for ug in extractedGrids:
            append.AddInputData(ug)
        append.Update()

        # set the output to the result of append
        output = vtk.vtkUnstructuredGrid.GetData(outInfo, 0)
        output.DeepCopy(append.GetOutput())

        return 1

    def processGrid(self, ug):
        """Given an unstructured grid, find cells which use any of the points
        in self.points, and return an unstructured grid with those cells.
        
        """

        allCellIdsList = vtk.vtkIdList()
        for pointId in self.points:
            cellIdsList = vtk.vtkIdList()
            ug.GetPointCells(pointId, cellIdsList)

            for i in range(cellIdsList.GetNumberOfIds()):
                allCellIdsList.InsertNextId(cellIdsList.GetId(i))

        # extract all cells into a separate grid
        extract = vtk.vtkExtractCells()
        extract.SetInputData(ug)
        extract.SetCellList(allCellIdsList)
        extract.Update()
        return extract.GetOutput()

    # text box indicating which point ids to use
    @smproperty.stringvector(name ="Point Ids (Comma Separated)",
                             default_values='0')
    def SetPointIds(self, x):
        if x is None:
            self.points = set()
        else:
            self.points = set([int(pointid) for pointid in x.split(',')])
        self.Modified()
