/**
 * Copyright (c) Artenum SARL 2004-2005
 * @author Julien Forest / 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.plugin.cutter;

import com.artenum.cassandra.pipeline.Filter;
import com.artenum.cassandra.pipeline.FilterImpl;
import com.artenum.cassandra.pipeline.PipeLineManager;
import com.artenum.cassandra.pipeline.RemoveListener;
import com.artenum.cassandra.pipeline.CassandraObject;
import com.artenum.cassandra.plugin.CassandraPlugInProperty;
import com.artenum.cassandra.plugin.CassandraPlugin;
import com.artenum.cassandra.plugin.PlugInControlUI;
import com.artenum.cassandra.plugin.PluginManager;

import vtk.vtkActor;
import vtk.vtkBoxWidget;
import vtk.vtkCone;
import vtk.vtkCutter;
import vtk.vtkCylinder;
import vtk.vtkDataSet;
import vtk.vtkLookupTable;
import vtk.vtkPlane;
import vtk.vtkPolyDataMapper;
import vtk.vtkScalarBarActor;
import vtk.vtkSphere;
import vtk.vtkTransform;

import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

/**
 * <pre>
 * <b>Project ref           :</b> CASSANDRA project
 * <b>Copyright and license :</b> See relevant sections
 * <b>Status                :</b> under development
 * <b>Creation              :</b> 04/03/2005
 * <b>Modification          :</b>
 *
 * <b>Description  :</b>
 *             This class defines the VTK processing pipeline itself
 *             and the initialisation of the contextuel GUI of the plugin.
 *
 * </pre>
 * <table cellpadding="3" cellspacing="0" border="1" width="100%">
 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor"><td><b>Version number</b></td><td><b>Author (name, e-mail)</b></td><td><b>Corrections/Modifications</b></td></tr>
 * <tr><td>0.1</td><td>Sebastien Jourdain, jourdain@artenum.com</td><td>Creation</td></tr>
 * </table>
 *
 * @author        Sebastien Jourdain, ARTENUM SARL 
 * @author        Julien Forest, ARTENUM SARL
 * 
 * @version       1.2
 */
public class CutterPlugin implements CassandraPlugin, RemoveListener {
    // Cassandra elements
    private String name;
    private PipeLineManager pipelineManager;
    private PluginManager pluginManager;
    private JPopupMenu contextualMenu;
    private int nbUpdate = 0;

    // Contextual control GUI of the plugin
    private CutterControlUI controlUI;

    // Cutting functions
    private vtkPlane plane;
    private vtkBoxWidget box;
    private vtkCylinder cylinder;
    private vtkCone cone;
    private vtkSphere sphere;

    // Transform
    private vtkTransform cylinderTransform;

    // Vtk data
    private vtkDataSet lastDataSet;
    private vtkLookupTable lookupTable;
    private vtkScalarBarActor scalarBar;
    private vtkCutter cutter;
    private vtkPolyDataMapper cutMapper;
    private vtkActor cutActor;
    private Filter filterImpl;

    // Pipeline VtkObjects
    private CassandraObject actor;
    private CassandraObject mapper;
    private CassandraObject dataset;
    private CassandraObject filter;

    /**
     * Main contructor and VTK pipeline definition.
     * @param pipelineManager is the central pipeline manager of Cassandra.
     * @param pluginManager is the central list of plugin instance, where a contextual menu access is given.
     */
    public CutterPlugin(PipeLineManager pipelineManager, PluginManager pluginManager, Frame owner) {
        // Init default variable
        this.name = "Generic Cutter";
        this.pipelineManager = pipelineManager;
        this.pluginManager = pluginManager;
        this.filterImpl = new FilterImpl();
        filterImpl.addRemoveListener(this);

        // Init all the control UI
        controlUI = new CutterControlUI(pipelineManager, this, owner);

        // Init contextual menu 
        contextualMenu = new JPopupMenu("Generic Cutter");
        JMenuItem showControl = new JMenuItem("Show control");
        showControl.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    controlUI.setVisible(true);
                }
            });
        contextualMenu.add(showControl);
        contextualMenu.addSeparator();
        JMenuItem remove = new JMenuItem("Remove");
        remove.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    remove();
                }
            });
        contextualMenu.add(remove);

        // Define function       
        // Plane
        plane = new vtkPlane();
        plane.SetOrigin(0.0, 0.0, 0.0);
        plane.SetNormal(0, 0, 1.0);

        // Cone
        cone = new vtkCone();
        cone.SetAngle(15);

        // Box
        box = new vtkBoxWidget();

        // Sphere
        sphere = new vtkSphere();
        sphere.SetCenter(0, 0, 0);
        sphere.SetRadius(10);

        // Cylinder
        cylinder = new vtkCylinder();
        cylinder.SetCenter(0, 0, 0);
        cylinder.SetRadius(10);
        cylinderTransform = new vtkTransform();
        cylinder.SetTransform(cylinderTransform);

        // Define and init the VTK pipeline
        cutter = new vtkCutter();
        cutter.SetCutFunction(plane);

        cutMapper = new vtkPolyDataMapper();
        cutMapper.SetInput(cutter.GetOutput());

        cutActor = new vtkActor();
        cutActor.SetMapper(cutMapper);

        // Build lookupTable
        try {
            lookupTable = new vtkLookupTable();
            lookupTable.SetHueRange(0.66667, 0);
            lookupTable.Build();
            cutMapper.SetLookupTable(lookupTable);
        } catch (Exception e1) {
            // To suport mac error
        }

        // Scalar bar
        vtkScalarBarActor scalBar = null;
        try {
            scalBar = new vtkScalarBarActor();
            scalBar.SetLookupTable(lookupTable);
        } catch (Exception e1) {
            // To suport mac error
        }

        // Load the result data in the Cassandra pipeline
        try {
            actor = pipelineManager.addActor(cutActor, "Cutter");
        } catch (Exception e1) {
            // To suport mac error
        }

        try {
            mapper = pipelineManager.addMapper(cutMapper, "Cutter");
        } catch (Exception e1) {
            // To suport mac error
        }

        try {
            dataset = pipelineManager.addDataSet(cutter.GetOutput(), "Cutter");
        } catch (Exception e1) {
            // To suport mac error
        }

        try {
            filter = pipelineManager.addFilter(filterImpl, "Cutter");
        } catch (Exception e1) {
            // To suport mac error
        }

        try {
            pipelineManager.addLookupTable(lookupTable, "Cutter");
        } catch (Exception e1) {
            // To suport mac error
        }

        try {
            if (scalBar != null) {
                pipelineManager.setActorVisible(pipelineManager.addScalarBar(scalBar, "Cutter"), true);
            }
        } catch (Exception e1) {
            // To suport mac error
        }

        //
        filter.getMetaData().put(CassandraObject.POPUP_MENU, getContextualMenu());

        // end of the VTK pipeline
        actor.setValide(false);
    }

    /**
     * Update the data in the defined pipeline
     * @param cx
     * @param cy
     * @param cz
     * @param nx
     * @param ny
     * @param nz
     * @param vtkDataSet
     */
    public void updateCuttingPlane(double cx, double cy, double cz, double nx, double ny, double nz, vtkDataSet vtkDataSet) {
        if (vtkDataSet == null) {
            return;
        }

        actor.setValide(true);

        //
        plane.SetOrigin(cx, cy, cz);
        plane.SetNormal(nx, ny, nz);
        cutter.SetCutFunction(plane);
        cutter.SetInput(vtkDataSet);
        if (((lastDataSet == null) || !lastDataSet.equals(vtkDataSet)) && cutMapper.GetLookupTable().equals(lookupTable)) {
            cutMapper.SetScalarRange(vtkDataSet.GetScalarRange());
            lookupTable.SetTableRange(vtkDataSet.GetScalarRange());
            lastDataSet = vtkDataSet;
        }

        /*
           if (cutMapper.GetLookupTable() instanceof vtkLookupTable) {
           cutMapper.SetScalarRange(((vtkLookupTable) cutMapper.GetLookupTable()).GetTableRange());
           }
         */

        // Set the default actor visible by default
        if ((nbUpdate++ == 0) && pipelineManager.getActorList().getData().contains(actor)) {
            pipelineManager.setActorVisible(actor, true);
        }

        // Graph
        filterImpl.getInputDataSet().clear();
        filterImpl.getInputDataSet().add(vtkDataSet);
        filterImpl.getOutputDataSet().clear();
        filterImpl.getOutputDataSet().add(cutter.GetOutput());
        pipelineManager.notifyConnectivityChange(filter);
    }

    /**
     * update the status of the cutting sphere. 
     * 
     * @param cx
     * @param cy
     * @param cz
     * @param radius
     * @param vtkDataSet
     */
    public void updateCuttingSphere(double cx, double cy, double cz, double radius, vtkDataSet vtkDataSet) {
        if (vtkDataSet == null) {
            return;
        }

        actor.setValide(true);

        //
        sphere.SetCenter(cx, cy, cz);
        sphere.SetRadius(radius);
        cutter.SetCutFunction(sphere);
        cutter.SetInput(vtkDataSet);
        if (((lastDataSet == null) || !lastDataSet.equals(vtkDataSet)) && cutMapper.GetLookupTable().equals(lookupTable)) {
            cutMapper.SetScalarRange(vtkDataSet.GetScalarRange());
            lookupTable.SetTableRange(vtkDataSet.GetScalarRange());
            lastDataSet = vtkDataSet;
        }

        /*
           if (cutMapper.GetLookupTable() instanceof vtkLookupTable) {
           cutMapper.SetScalarRange(((vtkLookupTable) cutMapper.GetLookupTable()).GetTableRange());
           }
         */

        // Set the default actor visible by default
        if ((nbUpdate++ == 0) && pipelineManager.getActorList().getData().contains(actor)) {
            pipelineManager.setActorVisible(actor, true);
        }

        // Graph
        filterImpl.getInputDataSet().clear();
        filterImpl.getInputDataSet().add(vtkDataSet);
        filterImpl.getOutputDataSet().clear();
        filterImpl.getOutputDataSet().add(cutter.GetOutput());
        pipelineManager.notifyConnectivityChange(filter);
    }

    public void updateCuttingCylinder(double cx, double cy, double cz, double rx, double ry, double rz, double radius, vtkDataSet vtkDataSet) {
        if (vtkDataSet == null) {
            return;
        }

        actor.setValide(true);

        //
        cylinder.SetCenter(cx, cy, cz);
        cylinder.SetRadius(radius);
        cylinderTransform.RotateX(rx);
        cylinderTransform.RotateY(ry);
        cylinderTransform.RotateY(rz);
        cutter.SetCutFunction(cylinder);
        cutter.SetInput(vtkDataSet);
        if (((lastDataSet == null) || !lastDataSet.equals(vtkDataSet)) && cutMapper.GetLookupTable().equals(lookupTable)) {
            cutMapper.SetScalarRange(vtkDataSet.GetScalarRange());
            lookupTable.SetTableRange(vtkDataSet.GetScalarRange());
            lastDataSet = vtkDataSet;
        }

        /*
           if (cutMapper.GetLookupTable() instanceof vtkLookupTable) {
           cutMapper.SetScalarRange(((vtkLookupTable) cutMapper.GetLookupTable()).GetTableRange());
           }
         */

        // Set the default actor visible by default
        if ((nbUpdate++ == 0) && pipelineManager.getActorList().getData().contains(actor)) {
            pipelineManager.setActorVisible(actor, true);
        }

        // Graph
        filterImpl.getInputDataSet().clear();
        filterImpl.getInputDataSet().add(vtkDataSet);
        filterImpl.getOutputDataSet().clear();
        filterImpl.getOutputDataSet().add(cutter.GetOutput());
        pipelineManager.notifyConnectivityChange(filter);
    }

    /**
     * Default plugin interface
     */
    public String getName() {
        return name;
    }

    public JPopupMenu getContextualMenu() {
        return contextualMenu;
    }

    public void remove() {
        pluginManager.removePlugin(this);
        pipelineManager.removeVtkObject(actor);
        pipelineManager.removeVtkObject(mapper);
        pipelineManager.removeVtkObject(dataset);
        pipelineManager.removeVtkObject(filter);
    }

    /**
     * String printed in the plugin manager list
     */
    public String toString() {
        return getName();
    }
    
    public Filter getInternalFilter() {
        return filterImpl;
    }

    @Override
    public CassandraPlugInProperty getPlugInProperty() {
        // TODO Auto-generated method stub
        return null;
    }


    @Override
    public PlugInControlUI getControlUI() {
        return controlUI;
    }

    @Override
    public void initAndUpdate(CassandraPlugInProperty prop) {
        // TODO Auto-generated method stub
        
    }
}
