/*****************************************************************************/
// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/** \file
 * Class definition for dng_host, initial point of contact and control between
 * host application and DNG SDK.
 */

/*****************************************************************************/

#ifndef __dng_host__
#define __dng_host__

/*****************************************************************************/

#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_errors.h"
#include "dng_flags.h"
#include "dng_types.h"
#include "dng_uncopyable.h"

/*****************************************************************************/

/// @brief The main class for communication between the application and the
/// DNG SDK. Used to customize memory allocation and other behaviors.
///
/// dng_host allows setting parameters for the DNG conversion, mediates callback
/// style interactions between the host application and the DNG SDK, and allows
/// controlling certain internal behavior of the SDK such as memory allocation.
/// Many applications will be able to use the default implementation of dng_host
/// by just setting the dng_memory_allocator and dng_abort_sniffer in the
/// constructor. More complex interactions will require deriving a class from
/// dng_host.
///
/// Multiple dng_host objects can be allocated in a single process. This may
/// be useful for DNG processing on separate threads. (Distinct dng_host objects
/// are completely threadsafe for read/write. The application is responsible for
/// establishing mutual exclusion for read/write access to a single dng_host
/// object if it is used in multiple threads.)

class dng_host: private dng_uncopyable
    {

    private:

        dng_memory_allocator *fAllocator;

        dng_abort_sniffer *fSniffer;

        // Does the host require all the image metadata (vs. just checking
        // to see if the file is readable)?

        bool fNeedsMeta;

        // Does the host require actual image data (vs. just getting metadata
        // or just checking to see if the file is readable)?

        bool fNeedsImage;

        // If we need the image data, can it be read at preview quality?

        bool fForPreview;

        // If non-zero, the minimum size (longer of the two pixel dimensions)
        // image to read.  If zero, or if the full size image is smaller than
        // this, read the full size image.

        uint32 fMinimumSize;

        // What is the preferred size for a preview image?  This can
        // be slightly larger than the minimum size.  Zero if we want
        // the full resolution image.

        uint32 fPreferredSize;

        // What is the maximum size for a preview image?  Zero if there
        // is no maximum size limit.

        uint32 fMaximumSize;

        // The fraction of the image kept after a crop.  This is used to
        // adjust the sizes to take into account the cropping that
        // will be peformed.

        real64 fCropFactor;

        // What DNG version should we keep enough data to save?

        uint32 fSaveDNGVersion;

        // Do we want to force saving to a linear DNG?

        bool fSaveLinearDNG;

        // Do we want to create JXL compressed in saved DNGs?

        bool fLossyMosaicJXL = false;
        bool fLosslessJXL    = false;

        // Keep the original raw file data block?

        bool fKeepOriginalFile;

        // Should we ignore the enhanced IFD when reading DNGs?

        bool fIgnoreEnhanced;

        // Is this host being used to perform a negative read for fast
        // conversion to DNG?

        bool fForFastSaveToDNG;

        uint32 fFastSaveToDNGSize;

        bool fPreserveStage2;

        std::shared_ptr<const dng_jxl_encode_settings> fJXLEncodeSettings;

        std::shared_ptr<const dng_jxl_color_space_info> fJXLColorSpaceInfo;

    public:

        /// Allocate a dng_host object, possiblly with custom allocator and sniffer.
        /// \param allocator Allows controlling all memory allocation done via this
        /// dng_host. Defaults to singleton global dng_memory_allocator, which calls
        /// new/delete dng_malloc_block for appropriate size.
        /// \param sniffer Used to periodically check if pending DNG conversions
        /// should be aborted and to communicate progress updates. Defaults to singleton
        /// global dng_abort_sniffer, which never aborts and ignores progress updated.

        dng_host (dng_memory_allocator *allocator = NULL,
                  dng_abort_sniffer *sniffer = NULL);

        /// Clean up direct memory for dng_host. Memory allocator and abort sniffer
        /// are not deleted. Objects such as dng_image and others returned from
        /// host can still be used after host is deleted.

        virtual ~dng_host ();

        /// Getter for host's memory allocator.

        dng_memory_allocator & Allocator ();

        /// Alocate a new dng_memory_block using the host's memory allocator.
        /// Uses the Allocator() property of host to allocate a new block of memory.
        /// Will call ThrowMemoryFull if block cannot be allocated.
        /// \param logicalSize Number of usable bytes returned dng_memory_block
        /// must contain.

        virtual dng_memory_block * Allocate (uint32 logicalSize);

        /// Setter for host's abort sniffer.

        void SetSniffer (dng_abort_sniffer *sniffer)
            {
            fSniffer = sniffer;
            }

        /// Getter for host's abort sniffer.

        dng_abort_sniffer * Sniffer ()
            {
            return fSniffer;
            }

        /// Check for pending abort. Should call ThrowUserCanceled if an abort
        /// is pending.

        virtual void SniffForAbort ();

        /// Setter for flag determining whether all XMP metadata should be parsed.
        /// Defaults to true. One might not want metadata when doing a quick check
        /// to see if a file is readable.
        /// \param needs If true, metadata is needed.

        void SetNeedsMeta (bool needs)
            {
            fNeedsMeta = needs;
            }

        /// Getter for flag determining whether all XMP metadata should be parsed.

        bool NeedsMeta () const
            {
            return fNeedsMeta;
            }

        /// Setter for flag determining whether DNG image data is needed. Defaults
        /// to true. Image data might not be needed for applications which only
        /// manipulate metadata.
        /// \param needs If true, image data is needed.

        void SetNeedsImage (bool needs)
            {
            fNeedsImage = needs;
            }

        /// Setter for flag determining whether DNG image data is needed.

        bool NeedsImage () const
            {
            return fNeedsImage;
            }

        /// Setter for flag determining whether image should be preview quality,
        /// or full quality.
        /// \param preview If true, rendered images are for preview.

        void SetForPreview (bool preview)
            {
            fForPreview = preview;
            }

        /// Getter for flag determining whether image should be preview quality.
        /// Preview quality images may be rendered more quickly. Current DNG SDK
        /// does not change rendering behavior based on this flag, but derived
        /// versions may use this getter to choose between a slower more accurate path
        /// and a faster "good enough for preview" one. Data produce with ForPreview set
        /// to true should not be written back to a DNG file, except as a preview image.

        bool ForPreview () const
            {
            return fForPreview;
            }

        /// Setter for the minimum preview size.
        /// \param size Minimum pixel size (long side of image).

        void SetMinimumSize (uint32 size)
            {
            fMinimumSize = size;
            }

        /// Getter for the minimum preview size.

        uint32 MinimumSize () const
            {
            return fMinimumSize;
            }

        /// Setter for the preferred preview size.
        /// \param size Preferred pixel size (long side of image).

        void SetPreferredSize (uint32 size)
            {
            fPreferredSize = size;
            }

        /// Getter for the preferred preview size.

        uint32 PreferredSize () const
            {
            return fPreferredSize;
            }

        /// Setter for the maximum preview size.
        /// \param size Maximum pixel size (long side of image).

        void SetMaximumSize (uint32 size)
            {
            fMaximumSize = size;
            }

        /// Getter for the maximum preview size.

        uint32 MaximumSize () const
            {
            return fMaximumSize;
            }

        /// Setter for the perform fast save to DNG.
        /// \param flag True if the host is being used to perform a negative
        /// read for fast conversion to DNG, false otherwise.

        void SetForFastSaveToDNG (bool flag,
                                  uint32 size)
            {
            fForFastSaveToDNG = flag;
            fFastSaveToDNGSize = size;
            }

        /// Getter for the Boolean value that indicates whether this host is
        /// being used to perform a negative read for fast conversion to DNG.

        bool ForFastSaveToDNG () const
            {
            return fForFastSaveToDNG;
            }

        uint32 FastSaveToDNGSize () const
            {
            return fFastSaveToDNGSize;
            }

        /// Setter for the cropping factor.
        /// \param cropFactor Fraction of image to be used after crop.

        void SetCropFactor (real64 cropFactor)
            {
            fCropFactor = cropFactor;
            }

        /// Getter for the cropping factor.

        real64 CropFactor () const
            {
            return fCropFactor;
            }

        /// Makes sures minimum, preferred, and maximum sizes are reasonable.

        void ValidateSizes ();

        /// Setter for what version to save DNG file compatible with.
        /// \param version What version to save DNG file compatible with.

        void SetSaveDNGVersion (uint32 version)
            {
            fSaveDNGVersion = version;
            }

        /// Getter for what version to save DNG file compatible with.

        virtual uint32 SaveDNGVersion () const;

        /// Setter for flag determining whether to force saving a linear DNG file.
        /// \param linear If true, we should force saving a linear DNG file.

        void SetSaveLinearDNG (bool linear)
            {
            fSaveLinearDNG = linear;
            }

        /// Getter for flag determining whether to save a linear DNG file.

        virtual bool SaveLinearDNG (const dng_negative &negative) const;

        /// Getter for flag determining whether to save DNG with lossy
        /// compressed mosaic if possible.

        bool LossyMosaicJXL () const
            {
            return fLossyMosaicJXL;
            }

        /// Setter for flag determining whether to save DNG with lossy
        /// compressed mosaic if possible.
        /// \param want If true, attempt to save lossy compressed mosaic.

        bool SetLossyMosaicJXL (bool want)
            {
            return fLossyMosaicJXL = want;
            }

        /// Getter for flag determining whether to save DNG with lossless
        /// compression if possible.

        bool LosslessJXL () const
            {
            return fLosslessJXL;
            }

        /// Setter for flag determining whether to save DNG with lossless
        /// compression if possible.
        /// \param want If true, attempt to save using lossless JXL.

        bool SetLosslessJXL (bool want)
            {
            return fLosslessJXL = want;
            }

        /// Setter for flag determining whether to keep original raw file data.
        /// \param keep If true, original raw data will be kept.

        void SetKeepOriginalFile (bool keep)
            {
            fKeepOriginalFile = keep;
            }

        /// Getter for flag determining whether to keep original raw file data.

        bool KeepOriginalFile ()
            {
            return fKeepOriginalFile;
            }

        /// Getter for ignored enhanced IFD flag.

        bool IgnoreEnhanced () const
            {
            return fIgnoreEnhanced;
            }

        /// Setter for ignored enhanced IFD flag.

        void SetIgnoreEnhanced (bool state)
            {
            fIgnoreEnhanced = state;
            }

        /// Determine if an error is the result of a temporary, but planned-for
        /// occurence such as user cancellation or memory exhaustion. This method is
        /// sometimes used to determine whether to try and continue processing a DNG
        /// file despite errors in the file format, etc. In such cases, processing will
        /// be continued if IsTransientError returns false. This is so that user cancellation
        /// and memory exhaustion always terminate processing.
        /// \param code Error to test for transience.

        virtual bool IsTransientError (dng_error_code code);

        /// General top-level botttleneck for image processing tasks.
        /// Default implementation calls dng_area_task::PerformAreaTask method on
        /// task. Can be overridden in derived classes to support multiprocessing,
        /// for example.
        /// \param task Image processing task to perform on area.
        /// \param area Rectangle over which to perform image processing task.

        virtual void PerformAreaTask (dng_area_task &task,
                                      const dng_rect &area,
                                      dng_area_task_progress *progress = NULL);

        /// How many multiprocessing threads does PerformAreaTask use?
        /// Default implementation always returns 1 since it is single threaded.

        virtual uint32 PerformAreaTaskThreads ();

        /// Factory method for dng_exif class. Can be used to customize allocation or
        /// to ensure a derived class is used instead of dng_exif.

        virtual dng_exif * Make_dng_exif ();

        /// Factory method for dng_xmp class. Can be used to customize allocation or
        /// to ensure a derived class is used instead of dng_xmp.

        #if qDNGUseXMP
        virtual dng_xmp * Make_dng_xmp ();
        #endif

        /// Factory method for dng_shared class. Can be used to customize allocation
        /// or to ensure a derived class is used instead of dng_shared.

        virtual dng_shared * Make_dng_shared ();

        /// Factory method for dng_ifd class. Can be used to customize allocation or
        /// to ensure a derived class is used instead of dng_ifd.

        virtual dng_ifd * Make_dng_ifd ();

        /// Factory method for dng_negative class. Can be used to customize allocation
        /// or to ensure a derived class is used instead of dng_negative.

        virtual dng_negative * Make_dng_negative ();

        /// Factory method for dng_image class. Can be used to customize allocation
        /// or to ensure a derived class is used instead of dng_simple_image.

        virtual dng_image * Make_dng_image (const dng_rect &bounds,
                                            uint32 planes,
                                            uint32 pixelType);

        /// Factory method for parsing dng_opcode based class. Can be used to
        /// override opcode implementations.

        virtual dng_opcode * Make_dng_opcode (uint32 opcodeID,
                                              dng_stream &stream);

        /// Factory method for making a dng_rgb_to_rgb_table_data based class.

        virtual dng_rgb_to_rgb_table_data *
            Make_dng_rgb_to_rgb_table_data (const dng_rgb_table &table);

        /// Factory method to apply a dng_opcode_list. Can be used to override
        /// opcode list applications.

        virtual void ApplyOpcodeList (dng_opcode_list &list,
                                      dng_negative &negative,
                                      AutoPtr<dng_image> &image);

        /// Factory method to resample an image.  Can be used to override
        /// image method used to resample images.

        virtual void ResampleImage (const dng_image &srcImage,
                                    dng_image &dstImage);

        /// Getter for flag determining whether we should preserve the stage 2
        /// image after building the stage 3 image.

        bool WantsPreserveStage2 () const
            {
            return fPreserveStage2;
            }

        /// Setter for flag determining whether we should preserve the stage 2
        /// image after building the stage 3 image.

        void SetWantsPreserveStage2 (bool flag)
            {
            fPreserveStage2 = flag;
            }

        /// JXL compression API.

        void SetJXLEncodeSettings (const dng_jxl_encode_settings &settings);

        const dng_jxl_encode_settings * JXLEncodeSettings () const
            {
            return fJXLEncodeSettings.get ();
            }

        void SetJXLColorSpaceInfo (std::shared_ptr<const dng_jxl_color_space_info> info)
            {
            fJXLColorSpaceInfo = info;
            }

        const dng_jxl_color_space_info * JXLColorSpaceInfo () const
            {
            return fJXLColorSpaceInfo.get ();
            }

        std::shared_ptr<const dng_jxl_color_space_info> ShareJXLColorSpaceInfo () const
            {
            return fJXLColorSpaceInfo;
            }

        enum use_case_enum
            {
            use_case_LossyMosaic,
            use_case_LosslessMosaic,
            use_case_MainImage,
            use_case_LosslessMainImage,
            use_case_EncodedMainImage,
            use_case_ProxyImage,
            use_case_EnhancedImage,
            use_case_LosslessEnhancedImage,
            use_case_MergeResults,
            use_case_Transparency,
            use_case_LosslessTransparency,
            use_case_Depth,
            use_case_LosslessDepth,
            use_case_SemanticMask,
            use_case_LosslessSemanticMask,
            use_case_RenderedPreview,
            use_case_GainMap,
            use_case_LosslessGainMap
            };

        virtual dng_jxl_encode_settings *
            MakeJXLEncodeSettings (use_case_enum useCase,
                                   const dng_image &image,
                                   const dng_negative *negative = nullptr) const;

    };

/*****************************************************************************/

#endif  //  __dng_host__

/*****************************************************************************/
