/**
 * Copyright (c) Artenum SARL 2004-2005
 * @author Sebastien Jourdain
 *
 * All rights reserved. This software can
 * not be used or copy or diffused without
 * an explicit license of Artenum SARL, Paris-France
 */
package com.artenum.cassandra.pipeline;

import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Observable;

import vtk.vtkActor;
import vtk.vtkActor2D;
import vtk.vtkAlgorithm;
import vtk.vtkDataSet;
import vtk.vtkDataSetMapper;
import vtk.vtkDataSetReader;
import vtk.vtkLookupTable;
import vtk.vtkMapper;
import vtk.vtkObject;
import vtk.vtkPolyDataMapper;
import vtk.vtkProp;
import vtk.vtkScalarBarActor;
import vtk.vtkTextActor;
import vtk.vtkXMLUnstructuredGridReader;

import com.artenum.cassandra.pipeline.graph.VtkObjectCellAdapter;
import com.artenum.cassandra.renderer.vtk.CassandraView;
import com.artenum.cassandra.ui.DefaultAxes;

/**
 * @author Sebastien Jourdain, Julien Forest, Jérémie Turbet, Benoit Thiébault
 * 
 * @version 2.0
 */
public class SimplePipeLineManager extends Observable implements PipeLineManager {
    private CassandraView view;
    private final ArrayList connectivityListener;
    private Hashtable<Integer, CassandraObject> vtkObjectHashtable;
    private final VtkObjectListModel actorList;
    private final VtkObjectListModel mapperList;
    private final VtkObjectListModel datasetList;
    private final VtkObjectListModel filterList;
    private final VtkObjectListModel lookupTableList;
    private final VtkObjectListModel scalarBarList;
    private final VtkObjectListModel txtActorList;

    private Integer vtkObjectIndex = new Integer(0);

    public Integer getVtkObjectIndex() {
        return this.vtkObjectIndex;
    }

    private final int pluginNumber = 1;
    private int actorNumber = 1;
    private int sourceNumber = 1;
    private int mapperNumber = 1;
    private int filterNumber = 1;
    private int lookupNumber = 1;
    private int scalarBarNumber = 1;
    private int txtActorNumber = 1;

    //
    private final DefaultAxes axes;

    /**
     * main constructor.
     */
    public SimplePipeLineManager() {

        // loading of the VTK based context.
        // try {
        // final VtkContextLoader contextLoader = new VtkContextLoader(4);
        // if (contextLoader.load() == false) {
        // System.exit(-1);
        // }
        // } catch (final Exception e) {
        // System.out.print("Error in the call to native context loader");
        // }

        // Instantiation of the VTK based renderer.
        try {
            this.view = new CassandraView();
        } catch (final Exception e) {
            System.out.println("Error: impossible to build the VTK based renderer and/or view");
            System.exit(-1);
        }

        this.vtkObjectHashtable = new Hashtable<Integer, CassandraObject>();
        this.actorList = new VtkObjectListModel(CassandraObject.ACTOR);
        this.mapperList = new VtkObjectListModel(CassandraObject.MAPPER);
        this.datasetList = new VtkObjectListModel(CassandraObject.DATASET);
        this.filterList = new VtkObjectListModel(CassandraObject.FILTER);
        this.lookupTableList = new VtkObjectListModel(CassandraObject.LOOKUP_TABLE);
        this.scalarBarList = new VtkObjectListModel(CassandraObject.SCALAR_BAR);
        this.txtActorList = new VtkObjectListModel(CassandraObject.TXT_ACTOR);
        this.axes = new DefaultAxes(this);
        this.connectivityListener = new ArrayList();
    }

    @Override
    public Hashtable<Integer, CassandraObject> getVtkObjectHashtable() {
        return this.vtkObjectHashtable;
    }

    public void setVtkObjectHashtable(final Hashtable vtkObjectHashtable) {
        this.vtkObjectHashtable = vtkObjectHashtable;
    }

    // Pipeline management
    /**
     * Add a VtkDataSet from a file reading into the pipeline manager and build-up the corresponding visualisation
     * pipeline.
     */
    @Override
    synchronized public void addVtkFile(final File vtkFile) {

        vtkDataSet inputDataSet;

        if (!vtkFile.exists()) {
            System.err.println("File does not exist: " + vtkFile.getAbsolutePath());
            return;
        }

        if (vtkFile.getName().endsWith(".vtu")) {
            final vtkXMLUnstructuredGridReader dataSetXMLReader = new vtkXMLUnstructuredGridReader();
            dataSetXMLReader.SetFileName(vtkFile.getAbsolutePath());
            dataSetXMLReader.Update();
            inputDataSet = dataSetXMLReader.GetOutput();
        } else {
            System.out.print("Vtk file loading... ");
            final vtkDataSetReader dataSetReader = new vtkDataSetReader();
            dataSetReader.SetFileName(vtkFile.getAbsolutePath());
            dataSetReader.Update();
            inputDataSet = dataSetReader.GetOutput();
            System.out.println("DONE");
        }

        // Set pipeline
        final vtkDataSetMapper mapper = new vtkDataSetMapper();

        mapper.SetInput(inputDataSet);
        mapper.Update();
        final vtkActor actor = new vtkActor();
        actor.SetMapper(mapper);

        // vtkScalarBarWidget scalBarWidget = new vtkScalarBarWidget();
        // scalBarWidget.SetScalarBarActor(scalBar);
        // vtkRenderWindowInteractor iren = new vtkRenderWindowInteractor();
        // scalBarWidget.SetInteractor(getCassandraView().GetRenderWindow().GetInteractor());
        // scalBarWidget.SetInteractor(iren);
        // iren.SetRenderWindow(getCassandraView().GetRenderWindow());
        // scalBarWidget.SetInteractor(iren);
        // iren.Initialize();
        // iren.Start();
        //
        // Register vtkObject into the pipeline
        this.addDataSet(inputDataSet, vtkFile.getName());
        this.addMapper(mapper, vtkFile.getName());

        // Show actors
        setActorVisible(addActor(actor, vtkFile.getName()), true);

        // lookup table
        if (inputDataSet.GetScalarRange() != null) {
            final vtkLookupTable lookupTable = new vtkLookupTable();
            lookupTable.SetHueRange(0.66667, 0);
            lookupTable.SetTableRange(inputDataSet.GetScalarRange());
            lookupTable.Build();
            mapper.SetLookupTable(lookupTable);
            mapper.SetScalarRange(inputDataSet.GetScalarRange());

            // Scalar bar
            final vtkScalarBarActor scalBar = new vtkScalarBarActor();
            scalBar.SetLookupTable(lookupTable);

            // register
            addLookupTable(lookupTable, vtkFile.getName());
            setActorVisible(addScalarBar(scalBar, vtkFile.getName()), true);
        }

        // to resize automatically the view on the loaded data
        this.view.resetCamera();
    }

    /**
     * Set the actor of Id vtkObjectId, visible (if true) or not (if false) in both the 3D (CassandraView) and 2D
     * (pipeline Editor).
     * 
     * @param vtkObjectId
     * @param viewActor
     */
    @Override
    public synchronized void setActorVisible(final Integer vtkObjectId, final boolean viewActor) {
        setActorVisible(this.vtkObjectHashtable.get(vtkObjectId), viewActor);
    }

    /**
     * set the actor visible or not in both 3D and 2D view.
     */
    @Override
    public synchronized void setActorVisible(final CassandraObject cassObject, final boolean viewActor) {
        if ((cassObject.getType() == CassandraObject.ACTOR) || (cassObject.getType() == CassandraObject.TXT_ACTOR)
                || (cassObject.getType() == CassandraObject.SCALAR_BAR)) {
            if (!cassObject.isValide()) {
                return;
            }

            cassObject.getMetaData().put(CassandraObject.ACTOR_VISIBLE, Boolean.toString(viewActor));
            if (cassObject.getVtkObject() instanceof vtkActor) {
                // 3D
                if (viewActor) {                	
                	int vtkActorIndex = this.view.GetRenderer().GetActors().IsItemPresent((vtkProp) cassObject.getVtkObject());
                    if( vtkActorIndex != 0){
                     	((vtkProp) cassObject.getVtkObject()).SetVisibility(1);
                     } else {
                     	this.view.GetRenderer().AddActor((vtkProp) cassObject.getVtkObject());
                     }
                } else {
                	int vtkActorIndex = this.view.GetRenderer().GetActors().IsItemPresent((vtkProp) cassObject.getVtkObject());
                    if( vtkActorIndex != 0){
                    	((vtkProp) cassObject.getVtkObject()).SetVisibility(0);
                    }
                }
            } else {
                // 2D
                if (viewActor) {
                	
                	//OLD FASHION
                    //this.view.GetRenderer().AddActor2D((vtkProp) cassObject.getVtkObject());
                    
                	//NEW FASHION
                    int vtkActorIndex = this.view.GetRenderer().GetActors2D().IsItemPresent((vtkProp) cassObject.getVtkObject());
                    if( vtkActorIndex != 0){
                    	((vtkProp) cassObject.getVtkObject()).SetVisibility(1);
                    } else {
                    	this.view.GetRenderer().AddActor2D((vtkProp) cassObject.getVtkObject());
                    }
                    
                } else {
                	//OLD FASHION
                    //this.view.GetRenderer().RemoveActor2D((vtkProp) cassObject.getVtkObject()); 
                	// NEW FASHION
                	int vtkActorIndex = this.view.GetRenderer().GetActors2D().IsItemPresent((vtkProp) cassObject.getVtkObject());
                    if( vtkActorIndex != 0){
                    	((vtkProp) cassObject.getVtkObject()).SetVisibility(0);
                    }
                }
            }
        }

        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
    }

    /**
     * return the Cassandra VtkObject of Id vtkObjectId.
     */
    @Override
    public CassandraObject getVtkObject(final Integer vtkObjectId) {
        return this.vtkObjectHashtable.get(vtkObjectId);
    }

    /**
     * return a new Id for a new VtkObject in the pipeline manager.
     * 
     * @return vtkObjectIndex
     */
    public Integer getNextVtkObjectId() {
        this.vtkObjectIndex = new Integer(this.vtkObjectIndex.intValue() + 1);
        return this.vtkObjectIndex;
    }

    /**
     * return the list of actors
     */
    @Override
    public VtkObjectListModel getActorList() {
        return this.actorList;
    }

    @Override
    public VtkObjectListModel getDataSetList() {
        return this.datasetList;
    }

    @Override
    public VtkObjectListModel getFilterList() {
        return this.filterList;
    }

    @Override
    public VtkObjectListModel getMapperList() {
        return this.mapperList;
    }

    @Override
    public VtkObjectListModel getLookupTableList() {
        return this.lookupTableList;
    }

    @Override
    public VtkObjectListModel getScalarBarList() {
        return this.scalarBarList;
    }

    @Override
    public VtkObjectListModel getTextActorList() {
        return this.txtActorList;
    }

    /**
     * Add a new actor into the pipeline manager.
     * 
     * @param actor
     * @param name
     * @return
     */
    @Override
    synchronized public CassandraObject addActor(final Object actor, final String name) {

        final int id = this.actorNumber++;
        final String actorId = name + " (" + id + ")";
        final VtkObjectAdapter vtkObject = new VtkObjectAdapter(actor, CassandraObject.ACTOR, actorId,
                getNextVtkObjectId());
        vtkObject.setLocalTypeId(id);
        this.vtkObjectHashtable.put(vtkObject.getId(), vtkObject);
        this.actorList.addVtkObject(vtkObject);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return vtkObject;
    }

    /**
     * Add an actor at the x, y position in the pipeline editor.
     * 
     * @param actor
     * @param name
     * @param cellPosX
     * @param cellPosY
     * @return
     */
    synchronized public CassandraObject addActor(final Object actor, final String name, final int cellPosX,
            final int cellPosY) {
        final CassandraObject casActor = addActor(actor, name);
        ((VtkObjectCellAdapter) casActor.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (casActor);
    }

    /**
     * Add a new mapper into the pipeline manager and register it.
     * 
     * @param mapper
     * @param name
     * @return the built VtkObject
     */
    @Override
    synchronized public CassandraObject addMapper(final Object mapper, final String name) {

        final int id = this.mapperNumber++;
        final String mapperId = name + " (" + id + ")";

        // for a better color mapping FIXME: should be linked with the GUI
        ((vtkMapper) mapper).SetInterpolateScalarsBeforeMapping(1);

        final VtkObjectAdapter casObject = new VtkObjectAdapter(mapper, CassandraObject.MAPPER, mapperId,
                getNextVtkObjectId());
        casObject.setLocalTypeId(id);
        this.vtkObjectHashtable.put(casObject.getId(), casObject);
        this.mapperList.addVtkObject(casObject);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return casObject;
    }

    /**
     * Add a mapper at the x, y position in the pipeline editor.
     * 
     * @param mapper
     * @param name
     * @param cellPosX
     * @param cellPosY
     * @return
     */
    synchronized public CassandraObject addMapper(final Object mapper, final String name, final int cellPosX,
            final int cellPosY) {
        final CassandraObject casMapper = addMapper(mapper, name);
        ((VtkObjectCellAdapter) casMapper.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (casMapper);
    }

    @Override
    synchronized public CassandraObject addDataSet(final Object dataset, final String name) {
        final int id = this.sourceNumber++;
        final String datasetId = name + " (" + id + ")";
        final VtkObjectAdapter vtkObject = new VtkObjectAdapter(dataset, CassandraObject.DATASET, datasetId,
                getNextVtkObjectId());
        vtkObject.setLocalTypeId(id);
        this.vtkObjectHashtable.put(vtkObject.getId(), vtkObject);
        this.datasetList.addVtkObject(vtkObject);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return vtkObject;
    }

    synchronized public CassandraObject addDataSet(final Object dataset, final String name, final int cellPosX,
            final int cellPosY) {
        final CassandraObject casDataset = addDataSet(dataset, name);
        ((VtkObjectCellAdapter) casDataset.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (casDataset);
    }

    /**
     * Add a data set into the pipeline manager and automatically build-up the downstream pipeline. Useful to load a
     * data set already in memory like a file.
     * 
     * @param dataset
     * @param name
     */
    synchronized public void addDataSetAndBuildPipeline(final Object dataset, final String name) {

        final CassandraObject tmpDataSet = this.addDataSet(dataset, name);

        final vtkDataSetMapper mapper = new vtkDataSetMapper();
        final vtkActor actor = new vtkActor();
        mapper.SetInput((vtkDataSet) dataset);

        actor.SetMapper(mapper);
        final vtkLookupTable lookupTable = new vtkLookupTable();
        lookupTable.SetHueRange(0.66667, 0);
        mapper.SetLookupTable(lookupTable);
        mapper.SetScalarRange(((vtkDataSet) dataset).GetScalarRange());
        final vtkScalarBarActor scalarBar = new vtkScalarBarActor();
        scalarBar.SetLookupTable(lookupTable);

        //
        final CassandraObject tmpMapper = this.addMapper(mapper, name + " mapper");
        final CassandraObject tmpActor = this.addActor(actor, name + " actor");
        this.setActorVisible(tmpActor, true);
        final CassandraObject tmpLookUpTable = this.addLookupTable(lookupTable, name + " lookup table");
        this.setActorVisible(addScalarBar(scalarBar, name), true);
        
        
        //FIXME: apparently generate reentrant lock in keridwen context. concurrent access?
        //the solution can be to add an empty text editor in renderer in cassandra constructor because the renderer may not be initialized at the begining. 
        //this.validateViewAndGo();
    }
    

 synchronized public void addDataSetAndBuildPipeline(Object dataset, String name, String title) {
	 
	 final CassandraObject tmpDataSet = this.addDataSet(dataset, name);

     final vtkDataSetMapper mapper = new vtkDataSetMapper();
     final vtkActor actor = new vtkActor();
     mapper.SetInput((vtkDataSet) dataset);

     actor.SetMapper(mapper);
     final vtkLookupTable lookupTable = new vtkLookupTable();
     lookupTable.SetHueRange(0.66667, 0);
     mapper.SetLookupTable(lookupTable);
     mapper.SetScalarRange(((vtkDataSet) dataset).GetScalarRange());
     final vtkScalarBarActor scalarBar = new vtkScalarBarActor();
     scalarBar.SetLookupTable(lookupTable);  
     scalarBar.SetTitle(title);

     //
     final CassandraObject tmpMapper = this.addMapper(mapper, name + " mapper");
     final CassandraObject tmpActor = this.addActor(actor, name + " actor");
     this.setActorVisible(tmpActor, true);
     final CassandraObject tmpLookUpTable = this.addLookupTable(lookupTable, name + " lookup table");
     this.setActorVisible(addScalarBar(scalarBar, name), true);

     
     //FIXME: apparently generate reentrant lock in keridwen context. concurrent access?
     //the solution can be to add an empty text editor in renderer in cassandra constructor because the renderer may not be initialized at the begining. 
     //this.validateViewAndGo();
  }

    /**
     * add a simple vtkFilter into the pipeline manager.
     * 
     * @param filter
     * @param name
     * @return
     */
    @Override
    synchronized public CassandraObject addFilter(final Filter filter, final String name) {

        // System.out.println("DEBUG - ADDING FILTER" + filter.toString());
        // System.out.println("filterNumber = " + filterNumber);

        final int id = this.filterNumber++;
        final String filterId = name + " (" + id + ")";
        final VtkObjectAdapter cassAdapter = new VtkObjectAdapter(filter, CassandraObject.FILTER, filterId,
                getNextVtkObjectId());

        // System.out.println("DEBUG - " + cassAdapter.toString());

        // set the id of the filter (in the filters list), used to defined the cell rendering position
        cassAdapter.setLocalTypeId(id);

        this.vtkObjectHashtable.put(cassAdapter.getId(), cassAdapter);
        this.filterList.addVtkObject(cassAdapter);

        Point tmpPos = ((VtkObjectCellAdapter) cassAdapter.getMetaData().get(CassandraObject.CELL)).getPosition();
        // System.out.println("DEBUG - cell position after addVtkObject:" + tmpPos.x + ", " + tmpPos.y);

        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        tmpPos = ((VtkObjectCellAdapter) cassAdapter.getMetaData().get(CassandraObject.CELL)).getPosition();
        // System.out.println("DEBUG - cell position after notification:" + tmpPos.x + ", " + tmpPos.y);

        return cassAdapter;
    }

    synchronized public CassandraObject addFilter(final Filter filter, final String name, final int cellPosX,
            final int cellPosY) {
        final CassandraObject cassFilter = addFilter(filter, name);
        ((VtkObjectCellAdapter) cassFilter.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (cassFilter);
    }

    /**
     * add a lookup table into the pipeline manager.
     * 
     * @param lookupTable
     * @param name
     * @return the Cassandra's VtkObject
     */
    @Override
    synchronized public CassandraObject addLookupTable(final vtkLookupTable lookupTable, final String name) {
        final int id = this.lookupNumber++;
        final String lookupTableId = name + " (" + id + ")";
        final VtkObjectAdapter adapter = new VtkObjectAdapter(lookupTable, CassandraObject.LOOKUP_TABLE, lookupTableId,
                getNextVtkObjectId());
        adapter.setLocalTypeId(id);
        this.vtkObjectHashtable.put(adapter.getId(), adapter);
        this.lookupTableList.addVtkObject(adapter);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return adapter;
    }

    synchronized public CassandraObject addLookupTable(final vtkLookupTable lookupTable, final String name,
            final int cellPosX, final int cellPosY) {
        final CassandraObject cassLookupTable = addLookupTable(lookupTable, name);
        ((VtkObjectCellAdapter) cassLookupTable.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(
                cellPosX, cellPosY));
        return (cassLookupTable);
    }

    @Override
    synchronized public CassandraObject addScalarBar(final vtkScalarBarActor scalarBar, final String name) {
        final int id = this.scalarBarNumber++;
        final String scalarBarId = name + " (" + id + ")";
        final VtkObjectAdapter vtkObject = new VtkObjectAdapter(scalarBar, CassandraObject.SCALAR_BAR, scalarBarId,
                getNextVtkObjectId());
        vtkObject.setLocalTypeId(id);
        this.vtkObjectHashtable.put(vtkObject.getId(), vtkObject);
        this.scalarBarList.addVtkObject(vtkObject);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return vtkObject;
    }

    synchronized public CassandraObject addScalarBar(final vtkScalarBarActor scalarBar, final String name,
            final int cellPosX, final int cellPosY) {
        final CassandraObject cassScalarBar = addScalarBar(scalarBar, name);
        ((VtkObjectCellAdapter) cassScalarBar.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (cassScalarBar);
    }

    /**
     * add text (i.e 2D actor) into the pipeline manager.
     */
    @Override
    synchronized public CassandraObject addTxtActor(final vtkTextActor txtActor, final String name) {
        final int id = this.txtActorNumber++;
        final String txtActorId = name + " (" + id + ")";
        final VtkObjectAdapter vtkObject = new VtkObjectAdapter(txtActor, CassandraObject.TXT_ACTOR, txtActorId,
                getNextVtkObjectId());
        vtkObject.setLocalTypeId(id);
        this.vtkObjectHashtable.put(vtkObject.getId(), vtkObject);
        this.txtActorList.addVtkObject(vtkObject);
        this.setChanged();
        this.notifyObservers(this.vtkObjectHashtable);
        return vtkObject;
    }

    synchronized public CassandraObject addTxtActor(final vtkTextActor txtActor, final String name, final int cellPosX,
            final int cellPosY) {
        final CassandraObject cassTextActor = addTxtActor(txtActor, name);
        ((VtkObjectCellAdapter) cassTextActor.getMetaData().get(CassandraObject.CELL)).setPosition(new Point(cellPosX,
                cellPosY));
        return (cassTextActor);
    }

    /**
     * remove the VtkObject defined by vtkObjectId from the pipeline manager.
     */
    @Override
    synchronized public void removeVtkObject(final Integer vtkObjectId) {
        final CassandraObject vtkObject = this.vtkObjectHashtable.remove(vtkObjectId);
        if (vtkObject != null) {
            switch (vtkObject.getType()) {
            case CassandraObject.ACTOR:
                setActorVisible(vtkObject, false);
                this.actorList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.MAPPER:
                this.mapperList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.DATASET:
                this.datasetList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.FILTER:
                this.filterList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.LOOKUP_TABLE:
                this.lookupTableList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.SCALAR_BAR:
                setActorVisible(vtkObject, false);
                this.scalarBarList.removeVtkObject(vtkObject);
                break;
            case CassandraObject.TXT_ACTOR:
                setActorVisible(vtkObject, false);
                this.txtActorList.removeVtkObject(vtkObject);
                break;
            }

            this.setChanged();
            this.notifyObservers(this.vtkObjectHashtable);
        }
    }

    /**
     * hide automatically the actor corresponding to the input data set of a filter.
     */
    @Override
    synchronized public void hideInputActor(final CassandraObject actor, final vtkDataSet vtkDataSet) {
        // we search the actor corresponding to the input dataset, in order to
        // hide it
        int i = 0;
        CassandraObject inputPipelineActor = null;
        vtkDataSet inputDataSet = null;
        vtkObject inputActor = null;
        boolean isValid = true;

        while ((((inputDataSet == vtkDataSet) && (inputActor != actor)) != true) && isValid) {
            try {
                inputPipelineActor = (CassandraObject) this.getActorList().getElementAt(i);
            } catch (final Exception e) {
                System.out.println("Error, actor not found.");
                isValid = false;
            }
            inputActor = (vtkObject) inputPipelineActor.getVtkObject();
            final vtkMapper inputMapper = ((vtkActor) inputActor).GetMapper();
            // because the common abstract mapper class has no getInput
            // method...
            if (inputMapper instanceof vtkDataSetMapper) {
                inputDataSet = ((vtkDataSetMapper) inputMapper).GetInput();
            }
            if (inputMapper instanceof vtkPolyDataMapper) {
                inputDataSet = ((vtkPolyDataMapper) inputMapper).GetInput();
            }
            i++;
        }
        setActorVisible(inputPipelineActor, false);
    }

    /**
     * remove the VtkObject defined by the vtkObject for the pipeline manager
     */
    @Override
    synchronized public void removeVtkObject(final CassandraObject vtkObject) {
        removeVtkObject(vtkObject.getId());
    }

    /**
     * returns the Cassandra Viewer (i.e panel and renderer) linked to the current pipeline.
     */
    @Override
    public CassandraView getCassandraView() {
        return this.view;
    }

    /**
     * set the axis arrows visible or not.
     */
    @Override
    public void setAxisVisible(final boolean viewAxis) {
        this.axes.setVisible(viewAxis);
    }

    /**
     * Set the projection parallel (i.e no perspective) or not.
     * 
     * @param setParallel
     */
    @Override
    public void setParallelProjection(final boolean setParallel) {
        int flag = 0;
        if (setParallel) {
            flag = 1;
        } else {
            flag = 0;
        }
        getCassandraView().GetRenderer().GetActiveCamera().SetParallelProjection(flag);
    }

    /**
     * requests an update (refresh) of the renderer and continues without waiting this update.
     */
    @Override
    public void validateViewAndGo() {
        getCassandraView().validateViewAndGo();
    }

    @Override
    public void validateViewAndWait() {
        getCassandraView().validateViewAndWait();
    }

    @Override
    public void deepValidateView() {
        getCassandraView().deepValidateView();
    }

    @Override
    synchronized public void addConnectivityListener(final ConnectivityListener l) {
        this.connectivityListener.add(l);
    }

    @Override
    public void notifyConnectivityChange(final CassandraObject obj) {
        for (final Iterator i = this.connectivityListener.iterator(); i.hasNext();) {
            ((ConnectivityListener) i.next()).connectivityChange(obj);
        }
    }

    @Override
    synchronized public void removeConnectivityListener(final ConnectivityListener l) {
        this.connectivityListener.remove(l);
    }

    public int getNbVtkObjects() {
        return (this.vtkObjectHashtable.size());
    }

    /**
     * return the Cassandra's VtkObject Wrapping of the given real vtkObject.
     */
    @Override
    public CassandraObject getCassandraVtkObjectByTrueVtkObject(final vtkObject obj) {
        Iterator tmpIterator;

        // if the object is an actor
        if (obj instanceof vtkActor) {
            tmpIterator = this.actorList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is a mapper
        if (obj instanceof vtkMapper) {
            tmpIterator = this.mapperList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is a dataSet
        if (obj instanceof vtkDataSet) {
            tmpIterator = this.datasetList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is vtkAlgorithm
        if (obj instanceof vtkAlgorithm) {
            tmpIterator = this.filterList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is a lookUpTable
        if (obj instanceof vtkLookupTable) {
            tmpIterator = this.lookupTableList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is a scalarBarList
        if (obj instanceof vtkScalarBarActor) {
            tmpIterator = this.scalarBarList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        // if the object is a text
        if (obj instanceof vtkTextActor) {
            tmpIterator = this.txtActorList.getData().iterator();
            while (tmpIterator.hasNext()) {
                final CassandraObject pipelineObj = (CassandraObject) tmpIterator.next();
                if (pipelineObj.getVtkObject().equals(obj)) {
                    return (pipelineObj);
                }
            }
        }

        return null;
    }
}
