/*****************************************************************************/
// Copyright 2007-2023 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.
/*****************************************************************************/

#ifndef __dng_preview__
#define __dng_preview__

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

#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_ifd.h"
#include "dng_opcode_list.h"
#include "dng_point.h"
#include "dng_sdk_limits.h"
#include "dng_string.h"
#include "dng_uncopyable.h"

#include <memory>

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

class dng_preview: private dng_uncopyable
	{
	
	public:
	
		dng_preview_info fInfo;
		
		bool fPreferJXL = false;
		
		bool fForNegativeCache = false;

	protected:
	
		std::shared_ptr<const dng_image> fImage;
		
		std::shared_ptr<const dng_compressed_image_tiles> fCompressedImage;
		
		mutable dng_ifd fIFD;

	protected:
	
		dng_preview ()
			{
			}
			
	public:
		
		virtual ~dng_preview ()
			{
			}
			
		virtual void SetIFDInfo (dng_host &host,
								 const dng_image &image);
		
		void FindTileSize (uint32 bytesPerTile)
			{
			fIFD.FindTileSize (bytesPerTile);
			}
			
		void SetImage (dng_host &host,
					   std::shared_ptr<const dng_image> image)
			{
			
			fImage = image;
			
			SetIFDInfo (host, *fImage);
			
			}
			
		void SetImage (dng_host &host,
					   AutoPtr<dng_image> &image)
			{
			
			std::shared_ptr<const dng_image> temp (image.Release ());
			
			SetImage (host, temp);
								
			}
		
		void SetImage (dng_host &host,
					   const dng_image *image)
			{
			
			std::shared_ptr<const dng_image> temp (image);
			
			SetImage (host, temp);
								
			}
		
		uint32 ImageWidth () const
			{
			return fIFD.fImageWidth;
			}
		
		uint32 ImageLength () const
			{
			return fIFD.fImageLength;
			}
			
		uint32 SamplesPerPixel () const
			{
			return fIFD.fSamplesPerPixel;
			}
		
		uint32 BitsPerSample () const
			{
			return fIFD.fBitsPerSample [0];
			}
		
		uint32 SampleFormat () const
			{
			return fIFD.fSampleFormat [0];
			}
		
		uint32 PhotometricInterpretation () const
			{
			return fIFD.fPhotometricInterpretation;
			}
		
		uint32 NewSubFileType () const
			{
			return fIFD.fNewSubFileType;
			}
		
		virtual dng_basic_tag_set * AddTagSet (dng_host &host,
											   dng_tiff_directory &directory) const;
		
		virtual void WriteData (dng_host &host,
								dng_image_writer &writer,
								dng_basic_tag_set &basic,
								dng_stream &stream) const;
								
		virtual uint64 MaxImageDataByteCount () const;
		
		virtual void Compress (dng_host &host,
							   dng_image_writer &writer);
		
	};
		
/*****************************************************************************/

class dng_image_preview: public dng_preview
	{
	
	public:
	
		dng_image_preview ()
			{
			}

	};

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

class dng_jpeg_preview: public dng_preview
	{
	
	public:
	
		dng_jpeg_preview ()
			{
			}
		
		void SetIFDInfo (dng_host &host,
						 const dng_image &image) override;
		
		void SetCompressionQuality (uint32 quality)
			{
			fIFD.fCompressionQuality = quality;
			}
		
		void SetYCbCr (uint32 subSampleH,
					   uint32 subSampleV)
			{
			
			fIFD.fPhotometricInterpretation = piYCbCr;
			
			fIFD.fYCbCrSubSampleH = subSampleH;
			fIFD.fYCbCrSubSampleV = subSampleV;
			
			}
			
		void SetCompressedData (AutoPtr<dng_memory_block> &compressedData);
		
		const dng_memory_block & CompressedData () const;
		
		dng_basic_tag_set * AddTagSet (dng_host &host,
									   dng_tiff_directory &directory) const override;
		
		void WriteData (dng_host &host,
						dng_image_writer &writer,
						dng_basic_tag_set &basic,
						dng_stream &stream) const override;
		
		uint64 MaxImageDataByteCount () const override;

		void Compress (dng_host &host,
					   dng_image_writer &writer) override;
		
		void SpoolAdobeThumbnail (dng_stream &stream) const;
		
	};

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

class dng_jxl_preview: public dng_preview
	{
	
	public:
	
		dng_jxl_preview ()
			{
			}
		
		void SetIFDInfo (dng_host &host,
						 const dng_image &image) override;
		
	};

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

class dng_raw_preview: public dng_preview
	{
	
	public:
	
		AutoPtr<dng_memory_block> fOpcodeList2Data;
  
		real64 fBlackLevel [kMaxColorPlanes];
		
		int32 fCompressionQuality = -1;

	public:
	
		dng_raw_preview ();
		
		virtual void SetIFDInfo (dng_host &host,
								 const dng_image &image);
		
		virtual dng_basic_tag_set * AddTagSet (dng_host &host,
											   dng_tiff_directory &directory) const;
		
	};

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

class dng_mask_preview: public dng_preview
	{
	
	public:
	
		int32 fCompressionQuality = -1;

	public:
	
		dng_mask_preview ()
			{
			}
		
		virtual void SetIFDInfo (dng_host &host,
								 const dng_image &image);
		
		virtual dng_basic_tag_set * AddTagSet (dng_host &host,
											   dng_tiff_directory &directory) const;
		
	};

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

class dng_semantic_mask_preview: public dng_preview
	{
	
	public:

		// Don't bother with including XMP block (if any) because this is just
		// a preview.
	
		dng_string fName;
	
		dng_string fInstanceID;

		int32 fCompressionQuality = -1;

		bool fOriginalSize = false;

		uint32 fMaskSubArea [4];

	private:
		
		mutable std::unique_ptr<tag_string> fTagName;
		mutable std::unique_ptr<tag_string> fTagInstanceID;
		
		mutable std::unique_ptr<tag_uint32_ptr> fTagMaskSubArea;
		
	public:
	
		dng_semantic_mask_preview ()
			{
			fMaskSubArea [0] = 0;
			fMaskSubArea [1] = 0;
			fMaskSubArea [2] = 0;
			fMaskSubArea [3] = 0;
			}
		
		virtual void SetIFDInfo (dng_host &host,
								 const dng_image &image);
		
		virtual dng_basic_tag_set * AddTagSet (dng_host &host,
											   dng_tiff_directory &directory) const;
		
	};

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

class dng_depth_preview: public dng_preview
	{
	
	public:
	
		int32 fCompressionQuality = -1;
  
		bool fFullResolution = false;

	public:
	
		dng_depth_preview ()
			{
			}
		
		virtual void SetIFDInfo (dng_host &host,
								 const dng_image &image);
		
		virtual dng_basic_tag_set * AddTagSet (dng_host &host,
											   dng_tiff_directory &directory) const;
		
	};

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

class dng_preview_list
	{
	
	private:
	
		std::vector<std::shared_ptr<const dng_preview>> fPreview;
		
	public:
	
		dng_preview_list ()
			{
			}
		
		uint32 Count () const
			{
			return (uint32) fPreview.size ();
			}
			
		const dng_preview & Preview (uint32 index) const
			{
			return *(fPreview [index]);
			}
			
		void Append (AutoPtr<dng_preview> &preview);
	
	};

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

#endif
	
/*****************************************************************************/
