#ifndef IMAGEORIENTATIONHELPER_H
#define IMAGEORIENTATIONHELPER_H

#include <QObject>
#include <QStringList>


#include "CamiTKAPI.h"

#include <vtkSmartPointer.h>

class vtkMatrix4x4;

namespace camitk {

/**
 * Helper class
 *
 * By convention, vtkImageDatas stored in ImageComponents MUST BE in RAI format.
 *  Indeed, for the 2D Axial, Coronal and Sagittal viewers to display correct views
 *  in CamiTK, all images should be oriented the same way, that is to say:
 *  - in the first (deepest) direction (X): from the Right of the patient, to the Left of the patient
 *  - in the second direction (Y): from the Anterior (face) of the patient to the Posterior (back) of the patient
 *  - in the third direction (Z) : from Inferior (feet) to Superior (head) of the patient
 *
 * This class gives Transformation Matrices to orient Medical Images acquired in
 * standard Dicom Image Orientation from or toward RAI orientation.
 *
 * Note: this class only consideres Direct image orientations.
 *
 */
class CAMITK_API ImageOrientationHelper : QObject {

    Q_OBJECT

public:
    /**
     * For each axis (x, y or z), 6 possibilities:
     * - Right (of th patient) to left  (of the patient)    [R]
     * - Left  (of th patient) to right (of th patient)     [L]
     * - Anterior  (face) to Posterior (back)               [A]
     * - Posterior (back) to Anterior  (face)               [P]
     * - Inferior (feet) to Superior (head)                 [I]
     * - Superior (head) to Inferior (feet)                 [S]
     *
     * So 6 possibilities for x, 4 for y and 2 for z -> 48 possibilities
     * 24 direct and 24 indirect.
     *
     * Only Direct Orientations are considered here.
     *
     */
    enum PossibleImageOrientations {
        /// Direct Orientations
        /// X: Right to Left, Y: Anterior to Posterior, Z: Inferior to Superiror
        RAI =  0,
        /// X: Right to Left, Y: Posterior to Anterior, Z: Superior to Inferior
        RPS =  1,
        /// X: Right to Left, Y: Inferior to Superiror, Z: Posterior to Anterior
        RIP =  2,
        /// etc.
        RSA =  3,
        LAS =  4,
        LPI =  5,
        LIA =  6,
        ARS =  7,
        ALI =  8,
        AIR =  9,
        ASL = 10,
        PRI = 11,
        PLS = 12,
        PIL = 13,
        PSR = 14,
        IRA = 15,
        ILP = 16,
        IAL = 17,
        IPR = 18,
        SRP = 19,
        SLA = 20,
        SAR = 22,
        SPL = 23,
        UNKNOWN = 50,
    };

    Q_ENUM(PossibleImageOrientations)

    /**
     * Returns the enumeration type PossibleImageOrientations in the format of a QStringList.
     * This may be needed for GUI not using enums.
     *
     * Note: the index of each orientation String refers to the corresponding enum number
     *  for example the getPossibleImageOrientations().indexOf("LAS") returns 4
     *  which is the enum number of LAS in the PossibleImageOrientations enumeration
     */
    static const QStringList getPossibleImageOrientations();

    /**
     * Returns the Possible Medical Image orientation in PossibleImageOrientations enumeration format
     *  from a QString format.
     */
    static PossibleImageOrientations getOrientationAsEnum(QString orientation);

    /**
     * Returns the Possible Medical Image orientation in QString format from a
     *   PossibleImageOrientation enumeration format.
     */
    static QString getOrientationAsQString(PossibleImageOrientations orientation);


    /**
     * Given a possible Dicom Image Orientation, this method returns the transform matrix
     *  to express the image in the RAI (x: Right to Left, y: Anterior to Posterior,
     *  z: Inferior to Superior) orientation.
     *
     * @return a transform homogeneous matrix containing the rigid transformation (rotation + translation)
     *  from the orientation given in parameter to the RAI orientation
     *
     * @param orientation original orientation of the image (this orientation should have been
     *  encoded in the input image file) as PossibleImageOrientations ennumeration.
     *
     * @param dimX image dimension in X direction in millimeters (mm). It can be generally
     *  calculated the following way: dimX = (number of voxels in X direction) * (size of a voxel in X direction)
     *
     * @param dimY image dimension in Y direction in millimeters (mm). It can be generally
     *  calculated the following way: dimY = (number of voxels in Y direction) * (size of a voxel in Y direction)
     *
     * @param dimZ image dimension in Z direction in millimeters (mm). It can be generally
     *  calculated the following way: dimZ = (number of voxels in Z direction) * (size of a voxel in Z direction)
     *
     * Note: The original image dimensions are needed to re-translate the image to the origin after
     *  a possible rotation.
     *
     */
    static vtkSmartPointer<vtkMatrix4x4> getTransformToRAI(PossibleImageOrientations orientation, double dimX, double dimY, double dimZ);

    /**
     * Given a possible Dicom Image Orientation, this method returns the transform matrix
     *  to express the image in the RAI (x: Right to Left, y: Anterior to Posterior,
     *  z: Inferior to Superior) orientation.
     *
     * @return a transform homogeneous matrix containing the rigid transformation (rotation + translation)
     *  from the orientation given in parameter to the RAI orientation
     *
     * @param orientation original orientation of the image (this orientation should have been
     *  encoded in the input image file) in QString format.
     *
     * @param dimX image dimension in X direction in millimeters (mm). It can be generally
     *  calculated the following way: dimX = (number of voxels in X direction) * (size of a voxel in X direction)
     *
     * @param dimY image dimension in Y direction in millimeters (mm). It can be generally
     *  calculated the following way: dimY = (number of voxels in Y direction) * (size of a voxel in Y direction)
     *
     * @param dimZ image dimension in Z direction in millimeters (mm). It can be generally
     *  calculated the following way: dimZ = (number of voxels in Z direction) * (size of a voxel in Z direction)
     *
     * Note: The original image dimensions are needed to re-translate the image to the origin after
     *  a possible rotation.
     *
     */
    static vtkSmartPointer<vtkMatrix4x4> getTransformToRAI(QString orientation, double dimX, double dimY, double dimZ);

    /**
     * Given a possible Dicom Image Orientation, this method returns the transform matrix
     *  to express an RAI image in this orientation.
     *
     * @return a transform homogeneous matrix containing the rigid transformation (rotation + translation)
     *  from the RAI orientation to the orientation given in parameter
     *
     * @param orientation new orientation wiched for the image (originnally in RAI orientation).
     * @param dimX image dimension in X direction in millimeters (mm). It can be generally
     *  calculated the following way: dimX = (number of voxels in X direction) * (size of a voxel in X direction)
     * @param dimY image dimension in Y direction in millimeters (mm). It can be generally
     *  calculated the following way: dimY = (number of voxels in Y direction) * (size of a voxel in Y direction)
     * @param dimZ image dimension in Z direction in millimeters (mm). It can be generally
     *  calculated the following way: dimZ = (number of voxels in Z direction) * (size of a voxel in Z direction)
     *
     * \note
     * The original image dimensions are needed to re-translate the image to the origin after
     * a possible rotation.
     *
     */
    static vtkSmartPointer<vtkMatrix4x4> getTransformFromRAI(PossibleImageOrientations orientation, double dimX, double dimY, double dimZ);

    /**
     * Given a possible Dicom Image Orientation, this method returns the transform matrix
     *  to express an RAI image in this orientation.
     *
     * @return a transform homogeneous matrix containing the rigid transformation (rotation + translation)
     *  from the RAI orientation to the orientation given in parameter
     *
     * @param orientation new orientation for the image (originnally in RAI orientation).
     * @param dimX image dimension in X direction in millimeters (mm). It can be generally
     *  calculated the following way: dimX = (number of voxels in X direction) * (size of a voxel in X direction)
     * @param dimY image dimension in Y direction in millimeters (mm). It can be generally
     *  calculated the following way: dimY = (number of voxels in Y direction) * (size of a voxel in Y direction)
     * @param dimZ image dimension in Z direction in millimeters (mm). It can be generally
     *  calculated the following way: dimZ = (number of voxels in Z direction) * (size of a voxel in Z direction)
     *
     * \note
     * The original image dimensions are needed to re-translate the image to the origin after
     * a possible rotation.
     *
     */
    static vtkSmartPointer<vtkMatrix4x4> getTransformFromRAI(QString orientation, double dimX, double dimY, double dimZ);


};
}
#endif // AXESREPRESENTATIONHELPER_H

