// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#include "exprs/vbloom_predicate.h"

#include <cstddef>
#include <utility>

#include "common/status.h"
#include "core/block/block.h"
#include "core/block/column_numbers.h"
#include "core/block/column_with_type_and_name.h"
#include "core/column/column.h"
#include "core/column/column_nullable.h"
#include "core/column/column_vector.h"
#include "core/data_type/data_type.h"
#include "core/data_type/data_type_nullable.h"
#include "core/types.h"
#include "exprs/bloom_filter_func.h"
#include "runtime/runtime_state.h"

namespace doris {
class RowDescriptor;
class TExprNode;

} // namespace doris

namespace doris {
#include "common/compile_check_begin.h"

class VExprContext;

VBloomPredicate::VBloomPredicate(const TExprNode& node) : VExpr(node), _filter(nullptr) {}

Status VBloomPredicate::prepare(RuntimeState* state, const RowDescriptor& desc,
                                VExprContext* context) {
    RETURN_IF_ERROR_OR_PREPARED(VExpr::prepare(state, desc, context));

    if (_children.size() != 1) {
        return Status::InternalError("Invalid argument for VBloomPredicate.");
    }

    _prepare_finished = true;
    return Status::OK();
}

Status VBloomPredicate::open(RuntimeState* state, VExprContext* context,
                             FunctionContext::FunctionStateScope scope) {
    DCHECK(_prepare_finished);
    RETURN_IF_ERROR(VExpr::open(state, context, scope));
    _open_finished = true;
    return Status::OK();
}

void VBloomPredicate::close(VExprContext* context, FunctionContext::FunctionStateScope scope) {
    VExpr::close(context, scope);
}

Status VBloomPredicate::_do_execute(VExprContext* context, const Block* block,
                                    const uint8_t* __restrict filter, Selector* selector,
                                    size_t count, ColumnPtr& result_column) const {
    DCHECK(_open_finished || block == nullptr);
    DCHECK(!(filter != nullptr && selector != nullptr))
            << "filter and selector can not be both set";
    DCHECK_EQ(_children.size(), 1);

    ColumnPtr argument_column;
    RETURN_IF_ERROR(_children[0]->execute_column(context, block, selector, count, argument_column));
    argument_column = argument_column->convert_to_full_column_if_const();

    size_t sz = argument_column->size();
    auto res_data_column = ColumnUInt8::create(sz);

    res_data_column->resize(sz);
    auto* ptr = ((ColumnUInt8*)res_data_column.get())->get_data().data();

    _filter->find_fixed_len(argument_column, ptr, filter);

    result_column = std::move(res_data_column);
    DCHECK_EQ(result_column->size(), count);
    return Status::OK();
}

Status VBloomPredicate::execute_column(VExprContext* context, const Block* block,
                                       Selector* selector, size_t count,
                                       ColumnPtr& result_column) const {
    return _do_execute(context, block, nullptr, selector, count, result_column);
}

Status VBloomPredicate::execute_runtime_filter(VExprContext* context, const Block* block,
                                               const uint8_t* __restrict filter, size_t count,
                                               ColumnPtr& result_column,
                                               ColumnPtr* arg_column) const {
    return _do_execute(context, block, filter, nullptr, count, result_column);
}
const std::string& VBloomPredicate::expr_name() const {
    return EXPR_NAME;
}

void VBloomPredicate::set_filter(std::shared_ptr<BloomFilterFuncBase> filter) {
    _filter = filter;
}

uint64_t VBloomPredicate::get_digest(uint64_t seed) const {
    seed = _children[0]->get_digest(seed);
    if (seed) {
        char* data;
        int len;
        _filter->get_data(&data, &len);
        return HashUtil::hash64(data, len, seed);
    }
    return 0;
}

#include "common/compile_check_end.h"
} // namespace doris