// SPDX-FileCopyrightText: 2005 Dominik Seichter <domseichter@web.de>
// SPDX-License-Identifier: LGPL-2.0-or-later OR MPL-2.0

#ifndef PDF_COLOR_H
#define PDF_COLOR_H

#include "PdfName.h"
#include "PdfArray.h"

namespace PoDoFo {

using PdfColorRaw = std::array<double, 6>;

/** A color object can represent either a grayscale
 *  value, a RGB color, a CMYK color
 *
 *  All drawing functions in PoDoFo accept a PdfColor object
 *  to specify a drawing color in one of these colorspaces.
 */
class PODOFO_API PdfColor final
{
public:
    /** Create a PdfColor object that is grayscale black.
     */
    PdfColor();

    /** Create a new PdfColor object with
     *  a grayscale value.
     *
     *  \param gray a grayscale value between 0.0 and 1.0
     */
    explicit PdfColor(double gray);

    /** Create a new PdfColor object with
     *  a RGB color
     *
     *  \param red the value of the red component, must be between 0.0 and 1.0
     *  \param green the value of the green component, must be between 0.0 and 1.0
     *  \param blue the value of the blue component, must be between 0.0 and 1.0
     */
    PdfColor(double red, double green, double blue);

    /** Create a new PdfColor object with
     *  a CMYK color
     *
     *  \param cyan the value of the cyan component, must be between 0.0 and 1.0
     *  \param magenta the value of the magenta component, must be between 0.0 and 1.0
     *  \param yellow the value of the yellow component, must be between 0.0 and 1.0
     *  \param black the value of the black component, must be between 0.0 and 1.0
     */
    PdfColor(double cyan, double magenta, double yellow, double black);

    /** Copy constructor
     *
     *  \param rhs copy rhs into this object
     */
    PdfColor(const PdfColor& rhs) = default;

public:
    /** Creates a color object from a PdfArray which represents a color.
     *
     *  \param obj an object that must be a color PdfArray
     */
    static bool TryCreateFromObject(const PdfObject& obj, PdfColor& color);
    static PdfColor CreateFromObject(const PdfObject& obj);

    static PdfColor CreateTransparent();

public:
    /** Test if this is a grayscale color.
     *
     *  \returns true if this is a grayscale PdfColor object
     */
    bool IsGrayScale() const;

    /** Test if this is a RGB color.
     *
     *  \returns true if this is a RGB PdfColor object
     */
    bool IsRGB() const;

    /** Test if this is a CMYK color.
     *
     *  \returns true if this is a CMYK PdfColor object
     */
    bool IsCMYK() const;

    bool IsTransparent() const;

    /** Get the colorspace of this PdfColor object
     *
     *  \returns the colorspace of this PdfColor object
     */
    inline PdfColorSpaceType GetColorSpace() const { return m_ColorSpace; }

    /** Get the grayscale color value
     *  of this object.
     *
     *  Throws an exception if this is no grayscale color object.
     *
     *  \returns the grayscale color value of this object (between 0.0 and 1.0)
     *
     *  \see IsGrayScale
     */
    double GetGrayScale() const;

    /** Get the red color value
     *  of this object.
     *
     *  Throws an exception if this is no RGB color object.
     *
     *  \returns the red color value of this object (between 0.0 and 1.0)
     *
     *  \see IsRGB
     */
    double GetRed() const;

    /** Get the green color value
     *  of this object.
     *
     *  Throws an exception if this is no RGB color object.
     *
     *  \returns the green color value of this object (between 0.0 and 1.0)
     *
     *  \see IsRGB
     */
    double GetGreen() const;

    /** Get the blue color value
     *  of this object.
     *
     *  Throws an exception if this is no RGB color object.
     *
     *  \returns the blue color value of this object (between 0.0 and 1.0)
     *
     *  \see IsRGB
     */
    double GetBlue() const;

    /** Get the cyan color value
     *  of this object.
     *
     *  Throws an exception if this is no CMYK or separation color object.
     *
     *  \returns the cyan color value of this object (between 0.0 and 1.0)
     *
     *  \see IsCMYK
     */
    double GetCyan() const;

    /** Get the magenta color value
     *  of this object.
     *
     *  Throws an exception if this is no CMYK or separation color object.
     *
     *  \returns the magenta color value of this object (between 0.0 and 1.0)
     *
     *  \see IsCMYK
     */
    double GetMagenta() const;

    /** Get the yellow color value
     *  of this object.
     *
     *  Throws an exception if this is no CMYK or separation color object.
     *
     *  \returns the yellow color value of this object (between 0.0 and 1.0)
     *
     *  \see IsCMYK
     */
    double GetYellow() const;

    /** Get the black color value
     *  of this object.
     *
     *  Throws an exception if this is no CMYK or separation color object.
     *
     *  \returns the black color value of this object (between 0.0 and 1.0)
     *
     *  \see IsCMYK
     */
    double GetBlack() const;

    /** Converts the color object into a grayscale
     *  color object.
     *
     *  This is only a convenience function. It might be useful
     *  for on screen display but is in NO WAY suitable to
     *  professional printing!
     *
     *  \returns a grayscale color object
     *  \see IsGrayScale()
     */
    PdfColor ConvertToGrayScale() const;

    /** Converts the color object into a RGB
     *  color object.
     *
     *  This is only a convenience function. It might be useful
     *  for on screen display but is in NO WAY suitable to
     *  professional printing!
     *
     *  \returns a RGB color object
     *  \see IsRGB()
     */
    PdfColor ConvertToRGB() const;

    /** Converts the color object into a CMYK
     *  color object.
     *
     *  This is only a convenience function. It might be useful
     *  for on screen display but is in NO WAY suitable to
     *  professional printing!
     *
     *  \returns a CMYK color object
     *  \see IsCMYK()
     */
    PdfColor ConvertToCMYK() const;

    /** Creates a PdfArray which represents a color from a color.
     *  \returns a PdfArray object
     */
    PdfArray ToArray() const;

    /** Creates a color object from a string.
     *
     *  \param name a string describing a color.
     *
     *  Supported values are:
     *  - single gray values as string (e.g. '0.5')
     *  - a named color (e.g. 'aquamarine' or 'magenta')
     *  - hex values (e.g. #FF002A (RGB) or #FF12AB3D (CMYK))
     *  - PdfArray's
     *
     *  \returns a PdfColor object
     */
    static PdfColor CreateFromString(const std::string_view& name);

public:
    unsigned char GetComponentCount() const { return m_ComponentCount; }

    const PdfColorRaw& GetRawColor() const { return m_RawColor; }

    /** Assignment operator
     *
     *  \param rhs copy rhs into this object
     *
     *  \returns a reference to this color object
     */
    PdfColor& operator=(const PdfColor& rhs) = default;

    /** Test for equality of colors.
     *
     *  \param rhs color to compare to
     *
     *  \returns true if object color is equal to rhs
     */
    bool operator==(const PdfColor& rhs) const;

    /** Test for inequality of colors.
     *
     *  \param rhs color to compare to
     *
     *  \returns true if object color is not equal to rhs
     */
    bool operator!=(const PdfColor& rhs) const;

private:
    PdfColor(bool isTransparent, PdfColorSpaceType colorSpace, unsigned char componentCount, const PdfColorRaw& data);

    static bool tryCreateFromArray(const PdfArray& arr, PdfColor& color);

private:
    bool m_IsTransparent;
    PdfColorSpaceType m_ColorSpace;
    unsigned char m_ComponentCount;
    PdfColorRaw m_RawColor;
};

};

#endif // PDF_COLOR_H
