/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "modules/skunicode/src/SkUnicode_icu_bidi.h"

#include "include/core/SkTypes.h"
#include "include/private/SkDebug.h"
#include "include/private/SkTFitsIn.h"
#include "src/core/SkUTF.h"

#include <unicode/ubidi.h>
#include <unicode/umachine.h>
#include <unicode/utypes.h>

#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace {
using SkUnicodeBidi = std::unique_ptr<UBiDi, SkBidiFactory::BidiCloseCallback>;

class SkBidiIterator_icu : public SkBidiIterator {
public:
    SkBidiIterator_icu(SkUnicodeBidi bidi, sk_sp<SkBidiFactory> fact)
            : fBidi(std::move(bidi)), fBidiFact(std::move(fact)) {}

    Position getLength() override { return fBidiFact->bidi_getLength(fBidi.get()); }

    Level getLevelAt(Position pos) override { return fBidiFact->bidi_getLevelAt(fBidi.get(), pos); }

private:
    SkUnicodeBidi fBidi;
    sk_sp<SkBidiFactory> fBidiFact;
};
}  // namespace

std::unique_ptr<SkBidiIterator> SkBidiFactory::MakeIterator(const uint16_t utf16[],
                                                            int utf16Units,
                                                            SkBidiIterator::Direction dir) const {
    UErrorCode status = U_ZERO_ERROR;
    SkUnicodeBidi bidi(this->bidi_openSized(utf16Units, 0, &status), this->bidi_close_callback());
    if (U_FAILURE(status)) {
        SkDEBUGF("Bidi error: %s", this->errorName(status));
        return nullptr;
    }
    SkASSERT(bidi);
    uint8_t bidiLevel = (dir == SkBidiIterator::kLTR) ? UBIDI_LTR : UBIDI_RTL;
    // The required lifetime of utf16 isn't well documented.
    // It appears it isn't used after ubidi_setPara except through ubidi_getText.
    this->bidi_setPara(bidi.get(), (const UChar*)utf16, utf16Units, bidiLevel, nullptr, &status);
    if (U_FAILURE(status)) {
        SkDEBUGF("Bidi error: %s", this->errorName(status));
        return nullptr;
    }
    return std::unique_ptr<SkBidiIterator>(
            new SkBidiIterator_icu(std::move(bidi), sk_ref_sp(this)));
}

std::unique_ptr<SkBidiIterator> SkBidiFactory::MakeIterator(const char utf8[],
                                                            int utf8Units,
                                                            SkBidiIterator::Direction dir) const {
    // Convert utf8 into utf16 since ubidi only accepts utf16
    if (!SkTFitsIn<int32_t>(utf8Units)) {
        SkDEBUGF("Bidi error: text too long");
        return nullptr;
    }

    // Getting the length like this seems to always set U_BUFFER_OVERFLOW_ERROR
    int utf16Units = SkUTF::UTF8ToUTF16(nullptr, 0, utf8, utf8Units);
    if (utf16Units < 0) {
        SkDEBUGF("Bidi error: Invalid utf8 input");
        return nullptr;
    }
    std::unique_ptr<uint16_t[]> utf16(new uint16_t[utf16Units]);
    SkDEBUGCODE(int dstLen =) SkUTF::UTF8ToUTF16(utf16.get(), utf16Units, utf8, utf8Units);
    SkASSERT(dstLen == utf16Units);

    return MakeIterator(utf16.get(), utf16Units, dir);
}

/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
static inline SkUnichar utf8_next(const char** ptr, const char* end) {
    SkUnichar val = SkUTF::NextUTF8(ptr, end);
    return val < 0 ? 0xFFFD : val;
}

bool SkBidiFactory::ExtractBidi(const char utf8[],
                                int utf8Units,
                                SkUnicode::TextDirection dir,
                                std::vector<SkUnicode::BidiRegion>* bidiRegions) const {
    // Convert to UTF16 since for now bidi iterator only operates on utf16
    auto utf16 = SkUnicode::convertUtf8ToUtf16(utf8, utf8Units);

    // Create bidi iterator
    UErrorCode status = U_ZERO_ERROR;
    SkUnicodeBidi bidi(this->bidi_openSized(utf16.size(), 0, &status), this->bidi_close_callback());
    if (U_FAILURE(status)) {
        SkDEBUGF("Bidi error: %s", this->errorName(status));
        return false;
    }
    SkASSERT(bidi);
    uint8_t bidiLevel = (dir == SkUnicode::TextDirection::kLTR) ? UBIDI_LTR : UBIDI_RTL;
    // The required lifetime of utf16 isn't well documented.
    // It appears it isn't used after ubidi_setPara except through ubidi_getText.
    this->bidi_setPara(
            bidi.get(), (const UChar*)utf16.c_str(), utf16.size(), bidiLevel, nullptr, &status);
    if (U_FAILURE(status)) {
        SkDEBUGF("Bidi error: %s", this->errorName(status));
        return false;
    }

    // Iterate through bidi regions and the result positions into utf8
    const char* start8 = utf8;
    const char* end8 = utf8 + utf8Units;
    SkUnicode::BidiLevel currentLevel = 0;

    SkUnicode::Position pos8 = 0;
    SkUnicode::Position pos16 = 0;
    SkUnicode::Position end16 = this->bidi_getLength(bidi.get());

    if (end16 == 0) {
        return true;
    }
    if (this->bidi_getDirection(bidi.get()) != UBIDI_MIXED) {
        // The entire paragraph is unidirectional.
        bidiRegions->emplace_back(0, utf8Units, this->bidi_getLevelAt(bidi.get(), 0));
        return true;
    }

    while (pos16 < end16) {
        auto level = this->bidi_getLevelAt(bidi.get(), pos16);
        if (pos16 == 0) {
            currentLevel = level;
        } else if (level != currentLevel) {
            SkUnicode::Position end = start8 - utf8;
            bidiRegions->emplace_back(pos8, end, currentLevel);
            currentLevel = level;
            pos8 = end;
        }
        SkUnichar u = utf8_next(&start8, end8);
        pos16 += SkUTF::ToUTF16(u);
    }
    SkUnicode::Position end = start8 - utf8;
    if (end != pos8) {
        bidiRegions->emplace_back(pos8, end, currentLevel);
    }
    return true;
}
