/*****************************************************************************/
// 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 for holding a specific color transform.
*/

#ifndef __dng_color_spec__
#define __dng_color_spec__

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

#include "dng_classes.h"
#include "dng_matrix.h"
#include "dng_types.h"
#include "dng_xy_coord.h"

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

/// @brief Compute a 3x3 matrix which maps colors from white point white1 to
/// white point white2
///
/// Uses linearized Bradford adaptation matrix to compute a mapping from
/// colors measured with one white point (white1) to another (white2).

dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
                                const dng_xy_coord &white2);

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

/// Color transform taking into account white point and camera calibration and
/// individual calibration from DNG negative.

class dng_color_spec
    {

    private:

        uint32 fChannels;

        real64 fTemperature1;
        real64 fTemperature2;

        dng_illuminant_data fLight1;
        dng_illuminant_data fLight2;
        dng_illuminant_data fLight3;

        dng_matrix fColorMatrix1;
        dng_matrix fColorMatrix2;
        dng_matrix fColorMatrix3;

        dng_matrix fForwardMatrix1;
        dng_matrix fForwardMatrix2;
        dng_matrix fForwardMatrix3;

        dng_matrix fReductionMatrix1;
        dng_matrix fReductionMatrix2;
        dng_matrix fReductionMatrix3;

        dng_matrix fCameraCalibration1;
        dng_matrix fCameraCalibration2;
        dng_matrix fCameraCalibration3;

        dng_matrix fAnalogBalance;

        dng_xy_coord fWhiteXY;

        dng_vector fCameraWhite;
        dng_matrix fCameraToPCS;

        dng_matrix fPCStoCamera;

        // Should we use the 1, 2, or 3-illuminant model?

        uint32 fNumIlluminants = 1;

    public:

        /// Read calibration info from DNG negative and construct a
        /// dng_color_spec.

        dng_color_spec (const dng_negative &negative,
                        const dng_camera_profile *profile,
                        bool allowStubbed = false);

        virtual ~dng_color_spec ()
            {
            }

        /// Number of channels used for this color transform. Three
        /// for most cameras.

        uint32 Channels () const
            {
            return fChannels;
            }

        /// Setter for white point. Value is as XY colorspace coordinate.
        /// \param white White point to set as an XY value.

        void SetWhiteXY (const dng_xy_coord &white);

        /// Getter for white point. Value is as XY colorspace coordinate.
        /// \retval XY value of white point.

        const dng_xy_coord & WhiteXY () const;

        /// Return white point in camera native color coordinates.
        /// \retval A dng_vector with components ranging from 0.0 to 1.0
        /// that is normalized such that one component is equal to 1.0 .

        const dng_vector & CameraWhite () const;

        /// Getter for camera to Profile Connection Space color transform.
        /// \retval A transform that takes into account all camera calibration
        /// transforms and white point.

        const dng_matrix & CameraToPCS () const;

        /// Getter for Profile Connection Space to camera color transform.
        /// \retval A transform that takes into account all camera calibration
        /// transforms and white point.

        const dng_matrix & PCStoCamera () const;

        /// Return the XY value to use for SetWhiteXY for a given camera color
        /// space coordinate as the white point.
        /// \param neutral A camera color space value to use for white point.
        /// Components range from 0.0 to 1.0 and should be normalized such that
        /// the largest value is 1.0 .
        /// \retval White point in XY space that makes neutral map to this
        /// XY value as closely as possible.

        dng_xy_coord NeutralToXY (const dng_vector &neutral);

    private:

        dng_matrix FindXYZtoCamera (const dng_xy_coord &white,
                                    dng_matrix *forwardMatrix = NULL,
                                    dng_matrix *reductionMatrix = NULL,
                                    dng_matrix *cameraCalibration = NULL);

        dng_matrix FindXYZtoCamera_SingleOrDual (const dng_xy_coord &white,
                                                 dng_matrix *forwardMatrix = NULL,
                                                 dng_matrix *reductionMatrix = NULL,
                                                 dng_matrix *cameraCalibration = NULL);

        dng_matrix FindXYZtoCamera_Triple (const dng_xy_coord &white,
                                           dng_matrix *forwardMatrix = NULL,
                                           dng_matrix *reductionMatrix = NULL,
                                           dng_matrix *cameraCalibration = NULL);

        void CalculateTripleIlluminantWeights (const dng_xy_coord &white,
                                               real64 &w1,
                                               real64 &w2,
                                               real64 &w3) const;

    };

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

#endif

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