/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef CANONICAL_SLICE_H
#define CANONICAL_SLICE_H

// -- Core stuff
#include "CamiTKAPI.h"
#include "InterfaceBitMap.h"

// -- vtk stuff
#include <vtkSmartPointer.h>
#include <vtkWindowLevelLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkActor.h>
#include <vtkImageActor.h>
#include <vtkImageChangeInformation.h>
#include <vtkImageReslice.h>
#include <vtkMatrix4x4.h>
#include <vtkPolyDataMapper.h>
#include <vtkPlaneSource.h>
#include <vtkTransform.h>
#include <vtkPixel.h>
#include <vtkUnstructuredGrid.h>
#include <vtkDataSetMapper.h>
#include <vtkLine.h>
#include <vtkPolygon.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
#include <vtkAxesActor.h>
#include <vtkTransformPolyDataFilter.h>

namespace camitk {
/**
 * @ingroup group_sdk_libraries_core_component
 *
 * @brief
 * Display a slice (i.e. an image or BitMap) of an @ref camitk::ImageComponent "ImageComponent"
 *
 * Uses vtkImageActor::SetDisplayExtent for 3D and 2D Axial, Coronal and Sagittal representaiton.
 * Re-position the camera for the 2D views.
 *
 *
 *  \verbatim
 *       3D Volume                         2D Slice
 *       ________  /|\
 *      /|      /|  |                      _______
 *     /______ / | _|_slice     ===>      /       /        Displayed in
 *    |  |____|_/|  |  number            /______ /         the window
 *    | /     |//
 *    |/______|/
 *
 *                                          ________________
 *                                         | vtkLookUpTable |
 *                                      ---|                |
 *                                     |   |    lut         |
 *                                     |   |________________|
 *  setOriginalVolume(..)              |
 *   |                                 | setLookUpTable
 *   |                   setInput      |                                   __________________
 *   |   ________________       _______v____________                      |  vtkImageActor   |
 *   |  |  vtkImageData  |     | vtkImageMapToColor |                     |(setDisplayExtent)|
 *   |_\|                |----\|                    |-------------------\ |                  |
 *     /| originalVolume |----/|   imgToMapFilter   |-------------------/ |   image2DActor   |
 *      |________________|     |____________________|     | |             |__________________|
 *                                                        | |
 *                                                        | |              _________________________            __________________
 *                                                        | |             |  vtkTransformFilter     |          |  vtkImageActor   |
 *                                                        |  -----------\ |(setWorldTransformation) | --------\|(setDisplayExtent)|
 *                                                         -------------/ |                         | --------/|                  |
 *                                                                        |                         |          |   image3DActor   |
 *                                                                        |_________________________|          |__________________|
 *
 *
 *
 * \endverbatim
 *
 */

class CAMITK_API Slice : public InterfaceBitMap {
public:
    /* -------------------------------------------------------------------- */
    /**@{                                                                   */
    /**@name Constructors / Destructors                                     */
    /**@{                                                                   */
    /* -------------------------------------------------------------------- */

    /** Common slices orientation: axial, sagittal, coronal axial_neuro.
     * Axial, Sagittal and Coronal orientation are given in Radiologist point of view.
     * The neurologist point of view is displayed in axial_neuro.
     *
     * The ImageComponent is supposed to be given in RAI orientation !
     * (see Image Reorientation Action Documentation).
     * @image imageRAI.png
     *
     * AXIAL:     from feet  to head of the patient
     * @image axialView.png
     *
     * CORONAL:   from the front to back  of the patient
     * @image coronalView.png
     *
     * SAGITTAL:  from the right to left of the patient
     * @image sagittalView.png
     *
     * AXIAL_NEURO: from head to feet (other side of AXIAL)
     *
     * ARBITRARY: any arbitrary orientation.
     *
     */
    enum SliceOrientation {
        AXIAL,
        CORONAL,
        SAGITTAL,
        AXIAL_NEURO,
        ARBITRARY
    };

    /// Constructor
    Slice(vtkSmartPointer<vtkImageData> volume, SliceOrientation AXIAL_ORIENTATION, vtkSmartPointer<vtkWindowLevelLookupTable> lookupTable = nullptr);

    /// virtual destructor
    ~Slice() override;

    /* -------------------------------------------------------------------- */
    /**@}                                                                   */
    /**@name          InterfaceBitMap implementation                        */
    /**@{                                                                   */
    /* -------------------------------------------------------------------- */

    /// set the original volume image data (the source vtkImageData before any reslice) and refresh the vtk pipeline
    void setOriginalVolume(vtkSmartPointer<vtkImageData> img) override;

    /// set the transformation for 3D image representation
    void setImageWorldTransform(vtkSmartPointer<vtkTransform>) override;

    /** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 2D viewers. */
    vtkSmartPointer<vtkImageActor> get2DImageActor() const override;

    /** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 3D viewers. */
    vtkSmartPointer<vtkImageActor> get3DImageActor() const override;

    /** Return the vtkActor used to pick pixels in the slices. */
    vtkSmartPointer<vtkActor> getPickPlaneActor() const override;

    /** Return the vtkActor used to pick pixels in the slices. */
    vtkSmartPointer<vtkActor> getPixelActor() override;

    /** Return 2D Axes at the proper slice origin */
    virtual vtkSmartPointer<vtkAxesActor> get2DAxesActor();

    /** This method is called when the associated plane has been picked in the InteractiveViewer,
     *  the given coordinates is position where the plane was picked.
     */
    void pixelPicked(double, double, double) override;

    /** Compute the volume coordinates (xyz) from the resliced coordinates (ijk)
    * @param ijk: given resliced coordiantes (generally from a pixel picked in the pickPlane)
    * @param xyz: output (should be allocated before calling this function)
    *     volume coordinates (with image at the origin in RAI convention) computed from the input
    */
    /// Todo: put this method in abstract slice
    void reslicedToVolumeCoords(const double* ijk, double* xyz);

    /// Todo, idem...
    void volumeToReslicedCoords(const double* xyz, double* ijk);

    void updatePickPlane() override;

    /** Return the number of slices in the image data set. */
    int getNumberOfSlices() const override;

    /** Return the index of the current displayed slice. */
    int getSlice() const override;

    /** Set the current slice index.
     * If the slice index is less than the first slice index, the first slice is displayed.
     * If the slice index is more than the last slice index, the last slice is displayed.
     * @param s the index of the slice to display (base 0). */
    void setSlice(int s) override;

    /// Set the slice corresponding to the given real image (RAI) coordinates
    void setSlice(double x, double y, double z) override;

    /** Return the number of colors in the images.
    * If color is coded on 1 byte, the images are on 256 grey level.
    * If color is coded on 2 bytes, the images are on 4096 grey level (not 65536). */
    int getNumberOfColors() const override;

    /// move the pixel selection green indicator (pixelActor) to the given real position
    void setPixelRealPosition(double, double, double) override;

    /// get the current image data
    vtkSmartPointer<vtkImageData> getImageData() const override;

    // BEGIN TODO : put all of this into a dedicated interface
    /// The additional map for prop (include at least "label" and "glyph")
    QMap<QString, vtkSmartPointer<vtkProp> > extraProp;

    /// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
    vtkSmartPointer<vtkProp> getProp(const QString&) override;

    /// return the number of additional prop
    unsigned int getNumberOfProp() const override;

    /// return an additional prop by its index
    vtkSmartPointer<vtkProp> getProp(unsigned int) override;

    /** insert an additional prop, defining it by its name (default visibility = false)
     *  @return true if the additional prop was added (i.e. another additional prop of the same name does not exist)
     */
    bool addProp(const QString&,  vtkSmartPointer<vtkProp>) override;

    /** remove a given additional prop.
     * @return true if effictively done
     */
    bool removeProp(const QString&) override;
    // END TODO


protected:
    /* -------------------------------------------------------------------- */
    /**@}                                                                   */
    /**@name          Protected utility methods                             */
    /**@{                                                                   */
    /* -------------------------------------------------------------------- */

    /** Initialize Attributes */
    virtual void init();

    /** Initialize actors and everything they need.*/
    virtual void initActors();

    /* -------------------------------------------------------------------- */
    /**@}                                                                   */
    /**@name          Attributes / Members of the class                     */
    /**@{                                                                   */
    /* ---------------------------------------------------------------------*/

    /** Direction of the reslice */
    SliceOrientation sliceOrientation;

    /** Smart pointer to the original volume to reslice (input of the vtk pipeline) */
    vtkSmartPointer<vtkImageData> originalVolume;

    /// Table containing first and last indices of the image in each direction
    /// 0 & 1 -> x; 2 and 3 -> y; 4 & 5 -> z
    int extent[6];

    /** Keep track of the slice number                                      */
    int currentSliceIndex;

    /// Common lookup table
    vtkSmartPointer<vtkWindowLevelLookupTable>  lut;

    /** Original volume dimensions in number of voxels (x, y and z) */
    int originalDimensions[3];

    /** Voxel size of the original image volume. Used to compute point coordinates between real world and index world.*/
    double originalSpacing[3];

    /** Real size (originalDimension * originalSpacing in x, y and z) of the original image */
    double originalSize[3];

    /// To be able to extract a slice
    vtkSmartPointer<vtkImageMapToColors>		imgToMapFilter;

    /// 3D actor
    vtkSmartPointer<vtkImageActor>				image3DActor;

    /// 2D actor
    vtkSmartPointer<vtkImageActor>              image2DActor;
    /**@}                                                                   */


    /**@}                                                                   */
    /**@name          Uses for picking                                      */
    /**@{                                                                   */

    /** A plane used for picking. This plane has the same size and position as the displayed slice. However, it is a
    * real vtkActor that can be easily picked (using 'p' ot 'Ctrl+left click'). */
    vtkSmartPointer<vtkPlaneSource> pickPlane;

    /** Mapper of the the pickPlane. */
    vtkSmartPointer<vtkPolyDataMapper> pickPlaneMapper;

    /** Actor representing the pickPlane. */
    vtkSmartPointer<vtkActor> pickPlaneActor;


    /**
     * Init the pixel actor for pixel picking
     */
    void initPixelActor();

    /** Update the pixel actor position according to the specified pixel picked by the user
     * i.e. Compute and draw the bounding box around the selected pixel.
     * @param x:
     * The absciss value of the selected pixel
     * @param y:
     * The ordinate value of the selected pixel
     * @param z:
     * The depth value of the selected pixel. In the plane, it's always +/- 0.01 in order to the pixel actor to be
     * visible over the slice.
     **/
    void updatePixelActorPosition(double x, double y, double z);


    /** Actor representing a pixel, displayed over the image. */
    vtkSmartPointer<vtkActor> pixelActor;


    void update2DAxesActorPosition();
    void init2DAxesActor();
    vtkSmartPointer<vtkAxesActor> axes2DActor;


};

}

#endif // CANONICAL_SLICE_H
