/*****************************************************************************/
// 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.
/*****************************************************************************/

#ifndef __dng_xmp__
#define __dng_xmp__

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

#include "dng_flags.h"

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

#if qDNGUseXMP

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

#include "dng_classes.h"
#include "dng_types.h"
#include "dng_xmp_sdk.h"

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

class dng_xmp
    {

    protected:

        // Sync option bits.

        enum
            {
            ignoreXMP       = 1,        // Force XMP values to match non-XMP
            preferXMP       = 2,        // Prefer XMP values if conflict
            preferNonXMP    = 4,        // Prefer non-XMP values if conflict
            removeXMP       = 8,        // Remove XMP value after syncing
            requireXMP      = 16        // Require XMP tag even if default
            };

        dng_memory_allocator &fAllocator;

        dng_xmp_sdk *fSDK;

    public:

        dng_xmp (dng_memory_allocator &allocator);

        dng_xmp (const dng_xmp &xmp);

        virtual ~dng_xmp ();

        virtual dng_xmp * Clone () const;

        dng_memory_allocator & Allocator () const
            {
            return fAllocator;
            }

        void Parse (dng_host &host,
                    const void *buffer,
                    uint32 count);

        dng_memory_block * Serialize (bool asPacket = false,
                                      uint32 targetBytes = 0,
                                      uint32 padBytes = 4096,
                                      bool forJPEG = false,
                                      bool compact = true) const;

        // Kludge: Due to a bug in Premere Elements 9, we need to pass non-compact XMP
        // to the host, until we drop support for this Premere version.  This bug
        // is fixed in Premere Elements 10 and later.

        dng_memory_block * SerializeNonCompact () const
            {
            return Serialize (false,
                              0,
                              4096,
                              false,
                              false);
            }

        void PackageForJPEG (AutoPtr<dng_memory_block> &stdBlock,
                             AutoPtr<dng_memory_block> &extBlock,
                             dng_string &extDigest) const;

        void MergeFromJPEG (const dng_xmp &xmp);

        bool HasMeta () const;

        void RequireMeta ()
            {
            fSDK->RequireMeta ();
            }

        void * GetPrivateMeta ();

        bool Exists (const char *ns,
                     const char *path) const;

        bool HasNameSpace (const char *ns) const;

        bool IteratePaths (IteratePathsCallback *callback,
                           void *callbackData,
                           const char *ns = NULL,
                           const char *path = NULL,
                           bool justChildren = false) const;

        void DuplicateSubtree (const dng_xmp &source,
                               const char *sourceNS,
                               const char *sourceRoot,
                               const char *destNS = NULL,
                               const char *destRoot = NULL);

        void DuplicateNameSpace (const dng_xmp &source,
                                 const char *ns);

        void Remove (const char *ns,
                     const char *path);

        void RemoveProperties (const char *ns);

        void RemoveEmptyStringOrArray (const char *ns,
                                       const char *path);

        void RemoveEmptyStringsAndArrays (const char *ns = 0);

        void Set (const char *ns,
                  const char *path,
                  const char *text);

        bool GetString (const char *ns,
                        const char *path,
                        dng_string &s) const;

        void SetString (const char *ns,
                        const char *path,
                        const dng_string &s);

        bool GetStringList (const char *ns,
                            const char *path,
                            dng_string_list &list,
                            dng_abort_sniffer *sniffer = NULL) const;

        void SetStringList (const char *ns,
                            const char *path,
                            const dng_string_list &list,
                            bool isBag = false);

        void SetStructField (const char *ns,
                             const char *path,
                             const char *fieldNS,
                             const char *fieldName,
                             const dng_string &s);

        void SetStructField (const char *ns,
                             const char *path,
                             const char *fieldNS,
                             const char *fieldName,
                             const char *s);

        void DeleteStructField (const char *ns,
                                const char *path,
                                const char *fieldNS,
                                const char *fieldName);

        bool GetStructField (const char *ns,
                             const char *path,
                             const char *fieldNS,
                             const char *fieldName,
                             dng_string &s) const;

        void SetAltLangDefault (const char *ns,
                                const char *path,
                                const dng_string &s);

        void SetLocalString (const char *ns,
                             const char *path,
                             const dng_local_string &s);

        bool GetAltLangDefault (const char *ns,
                                const char *path,
                                dng_string &s,
                                bool silent = false) const;

        bool GetLocalString (const char *ns,
                             const char *path,
                             dng_local_string &s) const;

        bool GetBoolean (const char *ns,
                         const char *path,
                         bool &x) const;

        void SetBoolean (const char *ns,
                         const char *path,
                         bool x);

        bool Get_int32 (const char *ns,
                        const char *path,
                        int32 &x) const;

        void Set_int32 (const char *ns,
                        const char *path,
                        int32 x,
                        bool usePlus = false);

        bool Get_uint32 (const char *ns,
                         const char *path,
                         uint32 &x) const;

        void Set_uint32 (const char *ns,
                         const char *path,
                         uint32 x);

        bool Get_real64 (const char *ns,
                         const char *path,
                         real64 &x) const;

        void Set_real64 (const char *ns,
                         const char *path,
                         real64 x,
                         uint32 places = 6,
                         bool trim = true,
                         bool usePlus = false);

        bool Get_urational (const char *ns,
                            const char *path,
                            dng_urational &r) const;

        void Set_urational (const char *ns,
                            const char *path,
                            const dng_urational &r);

        bool Get_srational (const char *ns,
                            const char *path,
                            dng_srational &r) const;

        void Set_srational (const char *ns,
                            const char *path,
                            const dng_srational &r);

        bool GetFingerprint (const char *ns,
                             const char *path,
                             dng_fingerprint &print) const;

        void SetFingerprint (const char *ns,
                             const char *path,
                             const dng_fingerprint &print,
                             bool allowInvalid = false);

        void SetVersion2to4 (const char *ns,
                             const char *path,
                             uint32 version);

        dng_fingerprint GetIPTCDigest () const;

        void SetIPTCDigest (dng_fingerprint &digest);

        void ClearIPTCDigest ();

        void IngestIPTC (dng_metadata &metadata,
                         bool xmpIsNewer = false);

        void RebuildIPTC (dng_metadata &metadata,
                          dng_memory_allocator &allocator,
                          bool padForTIFF);

        virtual void SyncExif (dng_exif &exif,
                               const dng_exif *originalExif = NULL,
                               bool doingUpdateFromXMP = false,
                               bool removeFromXMP = false);

        void ValidateStringList (const char *ns,
                                 const char *path);

        void ValidateMetadata ();

        void UpdateDateTime (const dng_date_time_info &dt);

        void UpdateMetadataDate (const dng_date_time_info &dt);

        void UpdateExifDates (dng_exif &exif,
                              bool removeFromXMP = false);

        bool HasOrientation () const;

        dng_orientation GetOrientation () const;

        void ClearOrientation ();

        void SetOrientation (const dng_orientation &orientation);

        void SyncOrientation (dng_negative &negative,
                              bool xmpIsMaster);
            // FIX_ME_API: Backwards compatibility

        void SyncOrientation (dng_metadata &metadata,
                              bool xmpIsMaster);

        void ClearImageInfo ();

        void SetImageSize (const dng_point &size);

        void SetSampleInfo (uint32 samplesPerPixel,
                            uint32 bitsPerSample);

        void SetPhotometricInterpretation (uint32 pi);

        void SetResolution (const dng_resolution &res);

        void ComposeArrayItemPath (const char *ns,
                                   const char *arrayName,
                                   int32 itemNumber,
                                   dng_string &s) const;

        void ComposeStructFieldPath (const char *ns,
                                     const char *structName,
                                     const char *fieldNS,
                                     const char *fieldName,
                                     dng_string &s) const;

        int32 CountArrayItems (const char *ns,
                               const char *path) const;

        void AppendArrayItem (const char *ns,
                              const char *arrayName,
                              const char *itemValue,
                              bool isBag = true,
                              bool propIsStruct = false);

        static dng_string EncodeFingerprint (const dng_fingerprint &f,
                                             bool allowInvalid = false);

        static dng_fingerprint DecodeFingerprint (const dng_string &s);

        #if qDNGXMPDocOps

        void DocOpsOpenXMP (const char *srcMIME);

        void DocOpsPrepareForSave (const char *srcMIME,
                                   const char *dstMIME,
                                   bool newPath = true);

        void DocOpsUpdateMetadata (const char *srcMIME);

        #endif

    protected:

        static void TrimDecimal (char *s);

        static dng_string EncodeGPSVersion (uint32 version);

        static uint32 DecodeGPSVersion (const dng_string &s);

        static dng_string EncodeGPSCoordinate (const dng_string &ref,
                                               const dng_urational *coord);

        static void DecodeGPSCoordinate (const dng_string &s,
                                         dng_string &ref,
                                         dng_urational *coord);

        static dng_string EncodeGPSDateTime (const dng_string &dateStamp,
                                             const dng_urational *timeStamp);

        static void DecodeGPSDateTime (const dng_string &s,
                                       dng_string &dateStamp,
                                       dng_urational *timeStamp);

        bool SyncString (const char *ns,
                         const char *path,
                         dng_string &s,
                         uint32 options = 0);

        void SyncStringList (const char *ns,
                             const char *path,
                             dng_string_list &list,
                             bool isBag = false,
                             uint32 options = 0);

        bool SyncAltLangDefault (const char *ns,
                                 const char *path,
                                 dng_string &s,
                                 uint32 options = 0);

        void Sync_uint32 (const char *ns,
                          const char *path,
                          uint32 &x,
                          bool isDefault = false,
                          uint32 options = 0,
                          uint32 defaultValue = 0);

        void Sync_uint32_array (const char *ns,
                                const char *path,
                                uint32 *data,
                                uint32 &count,
                                uint32 maxCount,
                                uint32 options = 0);

        void Sync_urational (const char *ns,
                             const char *path,
                             dng_urational &r,
                             uint32 options = 0);

        void Sync_srational (const char *ns,
                             const char *path,
                             dng_srational &r,
                             uint32 options = 0);

        void SyncIPTC (dng_iptc &iptc,
                       uint32 options);

        void SyncFlash (uint32 &flashState,
                        uint32 &flashMask,
                        uint32 options);

        void SyncExifDate (const char *ns,
                           const char *path,
                           dng_date_time_info &exifDateTime,
                           bool canRemoveFromXMP,
                           bool removeFromXMP,
                           const dng_time_zone &fakeTimeZone);

        virtual void SyncApproximateFocusDistance (dng_exif &exif,
                                                   const uint32 readOnly);

        virtual void SyncLensName (dng_exif &exif);

        virtual void GenerateDefaultLensName (dng_exif &exif);

    private:

        // Hidden assignment operator.

        dng_xmp & operator= (const dng_xmp &xmp);

    };

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

#endif  // qDNGUseXMP

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

#endif  // __dng_xmp__

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