/*
 * Copyright (c) 2024, Nico Weber <thakis@chromium.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include "Boxes.h"

namespace Gfx::ISOBMFF {

struct JPEG2000HeaderBox final : public SuperBox {
    BOX_SUBTYPE(JPEG2000HeaderBox);
};

// I.5.3.1 Image Header box
struct JPEG2000ImageHeaderBox final : public Box {
    BOX_SUBTYPE(JPEG2000ImageHeaderBox);

    u32 height { 0 };
    u32 width { 0 };
    u16 num_components { 0 };
    u8 bits_per_component { 0 };
    u8 compression_type { 0 };
    u8 is_colorspace_unknown { 0 };
    u8 contains_intellectual_property_rights { 0 };

    enum CompressionType {
        // T.800, I.5.3.1 Image Header box

        // "The value of this field shall be 7."
        Default = 7,

        // T.801, Table M.19 – Legal C values
        Uncompressed = 0,

        // "Rec. ITU-T T.4, the basic algorithm known as MH (Modified Huffman). This value is only permitted for bi-level images."
        T_4_Modified_Huffman = 1,

        // "Rec. ITU-T T.4, commonly known as MR (Modified READ). This value is only permitted for bi-level images."
        T_4_Modified_Read = 2,

        // "Rec. ITU-T T.6, commonly known as MMR (Modified Modified READ). This value is only permitted for bi-level images."
        T_4_Modified_Modified_Read = 3,

        // "Rec. ITU-T T.82 | ISO/IEC 11544. Commonly known as JBIG. This value is only permitted for bi-level images."
        JBIG_BILEVEL = 4,

        // "Rec. ITU-T T.81 | ISO/IEC 10918-1 or Rec. ITU-T T.84 | ISO/IEC 10918-3. Commonly known as JPEG. [...]
        //  This value is only permitted for continuous tone, greyscale or colour images."
        JPEG = 5,

        JPEG_LS = 6,

        JBIG2 = 8,

        // "Rec. ITU-T T.82 | ISO/IEC 11544. Commonly known as JBIG. This value is permitted for any image permitted by the JBIG standard."
        JBIG_ANY = 9,

        RUN_LENGTH = 10,
        JPEG_XR = 11,
        JPEG_XS = 12,
    };
};

// I.5.3.2 Bits Per Component box
struct JPEG2000BitsPerComponentBox final : public Box {
    BOX_SUBTYPE(JPEG2000BitsPerComponentBox);

    struct BitsPerComponent {
        u8 depth;
        bool is_signed;
    };
    Vector<BitsPerComponent> bits_per_components;
};

// I.5.3.3 Colour Specification box
struct JPEG2000ColorSpecificationBox final : public Box {
    BOX_SUBTYPE(JPEG2000ColorSpecificationBox);

    u8 method { 0 };
    i8 precedence { 0 };
    u8 approximation { 0 };
    u32 enumerated_color_space { 0 }; // Only set if method == Method::Enumerated
    ByteBuffer icc_data;              // Only set if method == Method::ICC_Restricted or Method::ICC_Any

    enum Method {
        // T.800, Table I.9 – Legal METH values

        // "Enumerated Colourspace. This colourspace specification box contains the enumerated value of the colourspace of this image. The
        //  enumerated value is found in the EnumCS field in this box."
        Enumerated = 1,

        // "Restricted ICC profile. This Colour Specification box contains an ICC profile in the PROFILE field. This profile shall specify the
        //  transformation needed to convert the decompressed image data into the PCSXYZ, and shall conform to either the Monochrome Input, the
        //  Three-Component Matrix-Based Input profile class, the Monochrome Display or the Three-Component Matrix-Based Display class and
        //  contain all the required tags specified therein"
        ICC_Restricted = 2,

        // "other values" "Reserved for other ITU-T | ISO uses. If the value of METH is not 1 or 2, there may be fields in this box following the APPROX field,
        //  and a conforming JP2 reader shall ignore the entire Colour Specification box."

        // T.801, Table M.22 – Legal METH values

        // "Any ICC method. This Colour Specification box indicates that the colourspace of the codestream is specified by an
        //  embedded input ICC profile. Contrary to the Restricted ICC method defined in the JP2 file format, this method allows
        //  for any input ICC profile"
        ICC_Any = 3,

        // "Vendor Colour method. This Colour Specification box indicates that the colourspace of the codestream is specified by
        //  a unique vendor defined code."
        Vendor = 4,

        // "Parameterized colourspace. This Colour Specification box indicates that the colourspace of the codestream is
        // parameterized"
        Parameterized = 5,
    };

    enum EnumCS {
        // T.800, Table I.10 – Legal EnumCS values

        // "sRGB as defined by IEC 61966-2-1 with Lmini=0 and Lmaxi=255. This colourspace shall be used with channels carrying unsigned values only."
        sRGB = 16,

        // "A greyscale space where image luminance is related to code values using the sRGB non-linearity given in Equations (2) to (4) of IEC 61966-2-1 (sRGB) specification. [...]
        //  This colourspace shall be used with channels carrying unsigned values only."
        Greyscale = 17,

        // "sYCC as defined by IEC 61966-2-1 Amd. 1with Lmini=0 and Lmaxi=255. This colourspace shall be used with channels carrying unsigned values only."
        sYCC = 18,

        // T.801, Table M.25 – Additional legal EnumCS values

        // "This value shall be used to indicate bi-level images. Each image sample is one bit: 0 = white, 1 = black."
        BiLevel = 0,

        YCbCr1 = 1,
        YCbCr2 = 3,
        YCbCr3 = 4,
        PhotoYCC = 9,
        CMY = 11,
        CMYK = 12,
        YCCK = 13,
        CIELab = 14,

        // "This value shall be used to indicate bi-level images. Each image sample is one bit: 1 = white, 0 = black."
        BiLevel2 = 15,

        // (T.801 also lists 18 for sYCC, but that's already in T.800 above.)

        CIEJab = 19,
        e_sRGB = 20,
        ROMM_RGB = 21,
        YPbPr_1125_60 = 22,
        YPbPr_1150_50 = 23,
        e_sYCC = 24,
        scRGB = 25,
        scRGB_Gray_Scale = 26, // [sic], inconsistent with the spelling of "greyscale" in T.800.
    };
};

// I.5.3.4 Palette box
struct JPEG2000PaletteBox final : public Box {
    BOX_SUBTYPE(JPEG2000PaletteBox);

    struct BitDepth {
        u8 depth;
        bool is_signed;
    };
    Vector<BitDepth> bit_depths;

    // BitDepth::depth is at most 38 per spec (Table I.13).
    // i64 is more than enough. Palettes don't have a ton of entries, so memory use here isn't critical.
    using Color = Vector<i64, 4>;
    Vector<Color> palette_entries;
};

// I.5.3.5 Component Mapping box
struct JPEG2000ComponentMappingBox final : public Box {
    BOX_SUBTYPE(JPEG2000ComponentMappingBox);

    struct Mapping {
        u16 component_index;

        enum Type {
            // "0: Direct use. This channel is created directly from an actual component in the codestream. The index of the
            //     component mapped to this channel is specified in the CMP^i field for this channel."
            Direct = 0,

            // "1: Palette mapping. This channel is created by applying the palette to an actual component in the codestream. The
            //     index of the component mapped into the palette is specified in the CMP^i field for this channel. The column from
            //     the palette to use is specified in the PCOL^i field for this channel."
            Palette = 1,

            // "2 to 255: Reserved for ITU-T | ISO use"
        };
        u8 mapping_type;

        u8 palette_component_index;
    };
    Vector<Mapping> component_mappings;
};

// I.5.3.6 Channel Definition box
struct JPEG2000ChannelDefinitionBox final : public Box {
    BOX_SUBTYPE(JPEG2000ChannelDefinitionBox);

    struct Channel {
        u16 channel_index;
        u16 channel_type;

        // "0              : This channel is associated as the image as a whole (for example, an independent opacity channel that
        //                   should be applied to all colour channels).
        //  1 to (2^16 – 2): This channel is associated with a particular colour as indicated by this value. This value is used to
        //                   associate a particular channel with a particular aspect of the specification of the colourspace of this
        //                   image. For example, indicating that a channel is associated with the red channel of an RGB image allows
        //                   the reader to associate that decoded channel with the Red input to an ICC profile contained within a
        //                   Colour Specification box. Colour indicators are specified in Table I.18.
        //  2^16 – 1       : This channel is not associated with any particular colour."
        u16 channel_association;

        enum Type {
            // T.800, Table I.16 – Typi field values

            // "This channel is the colour image data for the associated colour."
            Color = 0,

            // "Opacity. A sample value of 0 indicates that the sample is 100% transparent, and the maximum value of the
            //  channel (related to the bit depth of the codestream component or the related palette component mapped to this
            //  channel) indicates a 100% opaque sample. All opacity channels shall be mapped from unsigned components."
            Opacity = 1,

            // "Premultiplied opacity. An opacity channel as specified above, except that the value of the opacity channel has
            //  been multiplied into the colour channels for which this channel is associated."
            PremultipliedOpacity = 2,

            // 3 to (2^16 – 2) Reserved for ITU-T | ISO use

            // The type of this channel is not specified.
            Unspecified = 0xFFFF,
        };
    };
    Vector<Channel> channels;
};

// I.5.3.7 Resolution box (superbox)
struct JPEG2000ResolutionBox final : public SuperBox {
    BOX_SUBTYPE(JPEG2000ResolutionBox);
};

struct JPEG2000ResolutionSubboxBase : public Box {
    ErrorOr<void> read_from_stream(ConstrainedStream&);
    virtual void dump(String const& prepend) const override;

    u16 vertical_capture_grid_resolution_numerator { 0 };
    u16 vertical_capture_grid_resolution_denominator { 0 };
    u16 horizontal_capture_grid_resolution_numerator { 0 };
    u16 horizontal_capture_grid_resolution_denominator { 0 };
    i8 vertical_capture_grid_resolution_exponent { 0 };
    i8 horizontal_capture_grid_resolution_exponent { 0 };
};

// I.5.3.7.1 Capture Resolution box
struct JPEG2000CaptureResolutionBox final : public JPEG2000ResolutionSubboxBase {
    BOX_SUBTYPE(JPEG2000CaptureResolutionBox);
};

// I.5.3.7.2 Default Display Resolution box
struct JPEG2000DefaultDisplayResolutionBox final : public JPEG2000ResolutionSubboxBase {
    BOX_SUBTYPE(JPEG2000DefaultDisplayResolutionBox);
};

// I.5.4 Contiguous Codestream box
struct JPEG2000ContiguousCodestreamBox final : public Box {
    BOX_SUBTYPE(JPEG2000ContiguousCodestreamBox);

    ByteBuffer codestream;
};

struct JPEG2000SignatureBox final : public Box {
    BOX_SUBTYPE(JPEG2000SignatureBox);

    u32 signature { 0 };
};

// I.7.3 UUID Info boxes (superbox)
struct JPEG2000UUIDInfoBox final : public SuperBox {
    BOX_SUBTYPE(JPEG2000UUIDInfoBox);
};

// I.7.3.1 UUID List box
struct JPEG2000UUIDListBox final : public Box {
    BOX_SUBTYPE(JPEG2000UUIDListBox);

    Vector<Array<u8, 16>> uuids;
};

// I.7.3.2 Data Entry URL box
struct JPEG2000URLBox final : public Box {
    BOX_SUBTYPE(JPEG2000URLBox);

    ErrorOr<String> url_as_string() const;

    u8 version_number { 0 };
    u32 flag { 0 };
    ByteBuffer url_bytes;
};

}
