/*
 * Copyright 2021 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkJpegxlCodec_DEFINED
#define SkJpegxlCodec_DEFINED

#include "include/codec/SkEncodedImageFormat.h"
#include "include/core/SkData.h"
#include "include/core/SkRefCnt.h"
#include "src/codec/SkScalingCodec.h"

#include <cstddef>
#include <memory>

class SkCodec;
class SkFrameHolder;
class SkJpegxlCodecPriv;
class SkStream;
struct SkEncodedInfo;
struct SkImageInfo;

/*
 *
 * This class implements the decoding for jpegxl images
 *
 */
class SkJpegxlCodec : public SkScalingCodec {
public:
    static bool IsJpegxl(const void*, size_t);

    /*
     * Assumes IsJpegxl was called and returned true
     * Takes ownership of the stream
     */
    static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*);

protected:
    /* TODO(eustas): implement when downscaling is supported. */
    /* SkISize onGetScaledDimensions(float desiredScale) const override; */

    /* TODO(eustas): implement when up-/down-scaling is supported. */
    /* bool onDimensionsSupported(const SkISize&) override; */

    SkEncodedImageFormat onGetEncodedFormat() const override {
        return SkEncodedImageFormat::kJPEGXL;
    }

    Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
                       const Options& options, int* rowsDecodedPtr) override;

    /* TODO(eustas): add support for transcoded JPEG images? */
    /* bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&,
                            SkYUVAPixmapInfo*) const override; */

    /* TODO(eustas): add support for transcoded JPEG images? */
    /* Result onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) override; */

    /* TODO(eustas): implement when cropped output is supported. */
    /* bool onGetValidSubset(SkIRect* desiredSubset) const override; */

    bool onRewind() override;

    /* TODO(eustas): top-down by default; do we need something else? */
    /* SkScanlineOrder onGetScanlineOrder() const override; */
    /* int onOutputScanline(int inputScanline) const override; */

    bool conversionSupported(const SkImageInfo&, bool, bool) override;

    int onGetFrameCount() override;

    bool onGetFrameInfo(int, FrameInfo*) const override;

    int onGetRepetitionCount() override;
    IsAnimated onIsAnimated() override;

private:
    const SkFrameHolder* getFrameHolder() const override;

    // Result onStartScanlineDecode(
    //    const SkImageInfo& /*dstInfo*/, const Options& /*options*/) override;
    // Result onStartIncrementalDecode(
    //     const SkImageInfo& /*dstInfo*/, void*, size_t, const Options&) override;
    // Result onIncrementalDecode(int*) override;
    // bool onSkipScanlines(int /*countLines*/) override;
    // int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) override;
    // SkSampler* getSampler(bool /*createIfNecessary*/) override;

    // Opaque codec implementation for lightweight header file.
    std::unique_ptr<SkJpegxlCodecPriv> fCodec;
    sk_sp<const SkData> fData;

    bool scanFrames();
    static void imageOutCallback(
        void* opaque, size_t x, size_t y, size_t num_pixels, const void* pixels);

    SkJpegxlCodec(std::unique_ptr<SkJpegxlCodecPriv> codec,
                  SkEncodedInfo&& info,
                  std::unique_ptr<SkStream> stream,
                  sk_sp<const SkData> data);

    using INHERITED = SkScalingCodec;
};

#endif
