/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ECMASCRIPT_STRING_TREE_STRING_INL_H
#define ECMASCRIPT_STRING_TREE_STRING_INL_H

#include "securec.h"
#include "ecmascript/string/base_string.h"
#include "ecmascript/string/tree_string.h"

namespace panda::ecmascript {
template <typename Allocator, typename WriteBarrier,
          panda::objects_traits::enable_if_is_allocate<Allocator, common::BaseObject *>,
          common::objects_traits::enable_if_is_write_barrier<WriteBarrier>>
TreeString *TreeString::Create(Allocator &&allocator, WriteBarrier &&writeBarrier,
                               common::ReadOnlyHandle<BaseString> left, common::ReadOnlyHandle<BaseString> right,
                               uint32_t length, bool compressed)
{
    auto string = TreeString::Cast(std::invoke(std::forward<Allocator>(allocator),
        TreeString::SIZE, EcmaStringType::TREE_STRING));
    string->InitLengthAndFlags(length, compressed);
    string->SetMixHashcode(0);
    string->SetLeftSubString(std::forward<WriteBarrier>(writeBarrier), left.GetBaseObject());
    string->SetRightSubString(std::forward<WriteBarrier>(writeBarrier), right.GetBaseObject());
    return string;
}

template <typename ReadBarrier>
bool TreeString::IsFlat(ReadBarrier &&readBarrier) const
{
    auto strRight = BaseString::Cast(GetRightSubString<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
    return strRight->GetLength() == 0;
}

template <bool VERIFY, typename ReadBarrier>
uint16_t TreeString::Get(ReadBarrier &&readBarrier, int32_t index) const
{
    auto length = static_cast<int32_t>(GetLength());
    if constexpr (VERIFY) {
        if ((index < 0) || (index >= length)) {
            return 0;
        }
    }

    if (IsFlat(std::forward<ReadBarrier>(readBarrier))) {
        BaseString *left = BaseString::Cast(GetLeftSubString<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
        return left->At<VERIFY>(std::forward<ReadBarrier>(readBarrier), index);
    }
    const BaseString *string = this;
    while (true) {
        if (string->IsTreeString()) {
            BaseString *left = BaseString::Cast(
                TreeString::ConstCast(string)->GetLeftSubString<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
            if (static_cast<int32_t>(left->GetLength()) > index) {
                string = left;
            } else {
                index -= static_cast<int32_t>(left->GetLength());
                string = BaseString::Cast(TreeString::ConstCast(string)->GetRightSubString<BaseObject *>(
                    std::forward<ReadBarrier>(readBarrier)));
            }
        } else {
            return string->At<VERIFY>(std::forward<ReadBarrier>(readBarrier), index);
        }
    }
    UNREACHABLE_CC();
}
}  // namespace panda::ecmascript
#endif  // ECMASCRIPT_STRING_TREE_STRING_INL_H