
#ifndef _P1_IMAGE_SDK_STACKING_HPP_
#define _P1_IMAGE_SDK_STACKING_HPP_


#include <memory>

#include "P1ImageRawImage.hpp"
#include "P1ImageLensDistortion.hpp"

namespace P1
{
    namespace ImageSdk
    {
        /** @brief Struct used for two purposes. the three boolean variables. hasRgbBitmap, hasIrgBitmap, hasNdviBitmap is used to order what type of output to be produced by the stacker.
        The produced bitmaps are returned in the correcponding: RgbiBitmap, IrgBitmap and NdviBitmap. 
        It is only possible to produce either an RgbiBitmap or an IrgBitmap (and not both in same run). The NdviBitmap can be selected if wanted.
        */
        struct EXPORT_API StackingOutput
        {
            bool hasRgbiBitmap=false;   //!< If set to true. The stacker will produce an RGBI Bitmap (in member: RgbiBitmap)
            bool hasIrgBitmap=false;    //!< If set to true. The stacker will produce an IRG Bitmap (in member: IrgBitmap)
            bool hasNdviBitmap=false;   //!< If set to true. The stacker will produce an NDVI Bitmap (in member: NdviBitmap). 
                                        //!< Ndvi is a single channel bitmap calculated based on the equation:  (R-I)/(R+I)

            P1::ImageSdk::BitmapImage RgbiBitmap;   //!< This will contain a 4 channel bitmap after stacking if hasRgbiBitmap was set to true
            P1::ImageSdk::BitmapImage IrgBitmap;    //!< This will contain a 3 channel bitmap after stacking if hasIrgBitmap was set to true
            P1::ImageSdk::BitmapImage NdviBitmap;   //!< This will contain a 1 channel bitmap after stacking if hasNdviBitmap was set to true
        };


        class CStacking;
        enum StackerResult;

        class EXPORT_API Stacking
        {
        public:
            Stacking();
            ~Stacking();

            /** @brief A class to stack an rgb image and a nir images from PAS280i or the 4-band solution. The rgb image is regarded as the master image. The stacker will scale and merge the two images into up to 2 
                the 3 different formats that are supported by the stacker. What output bitmaps that are generated is controlled by the StackingOutput struct. The same struct will after stacking is performed, contain the generated output bitmaps.
            * @param masterImage . This is a reference to the master image for the rgb image, if the rgb bitmap has been stitched then the reference should point to the left image (the left image is regarded as the master)
            * @param rgbBitmap is a reference to the rgb image (this image will normally for a PAS system be a stitched image). This bitmap is expected to be an undistorted image.
            * @param rgbCalibration is a reference to a struct containing a simplifed Geometric calibration (since image is undistored already - you only need to setup focallength and pixelsize).
            * @param nirBitmap is a reference to the nir image. This bitmap is expected to be still an distorted image. The stacker will undistort the image using the geometric calibration for the nir camera.
            * @param nirCalibration is a reference to a struct containing a full Geometric calibration for the nir bitmap (the Stacker will undistort the nir image using this struct).
            * @param output is a struct that is used to setup the types of out puts the stacker should produce. It can produce either an Rgbi or a Irg bitmap. Aisde this it can in the same process also produce an ndvi bitmap if it is selected. The selected bitmaps are returned in this stract after a successful stacking
            * @param alloc is an allocator that is used to allocate memory for the output bitmap. Its an optional parameter and should not be used unless its important for the host program.
            * @throw throws a SdkException on error          
            */
            void DoStacking(P1::ImageSdk::RawImage& masterImage, P1::ImageSdk::BitmapImage& rgbBitmap, P1::ImageSdk::GeometricCorrection& rgbCalibration, P1::ImageSdk::RawImage& nirImage, P1::ImageSdk::BitmapImage& nirBitmap, P1::ImageSdk::GeometricCorrection& nirCalibration, P1::ImageSdk::StackingOutput& output, std::allocator<uint8_t> alloc = std::allocator<uint8_t>());


            /** @brief Setup a fine calibration. A finecalibration is a binary blob setup by the stacker itself that can speed up the stacking process.
            * @param fineCalibrationData is a pointer to the data where the fine calibration to setup is stored.
            * @param fineCalibrationLength is an integer that tells how much memory the finecalibration is using
            */
            void SetFineCalibration(uint8_t* fineCalibrationData, uint32_t fineCalibrationLength);
            /** @brief Get a pointer to the fine calibration data from the stacker*/
            uint8_t* GetFineCalibrationData();
            /** @brief Get an integer with the length of the fine calibration data in the stacker*/
            uint32_t GetFineCalibrationLength();

            /** Get the last result of the stacker. This can be used to get info about errors and warnings that had an impact on the stacker. Errors will cause the stacker to throw an excetion*/
            StackerResult GetLastResult();

        private:
            P1::ImageSdk::CStacking* mStacker = nullptr;
        };
    }
}

#endif  // _P1_IMAGE_SDK_STACKING_HPP_
