/*
 *******************************************************************************
 *
 *  Copyright 2025 RIEGL Laser Measurement Systems
 *
 *  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.
 *
 *  SPDX-License-Identifier: Apache-2.0
 *
 *******************************************************************************
 */
/*!
 *******************************************************************************
 *
 * \file    transactions.cpp
 * \author  RIEGL LMS GmbH, Austria
 * \brief   Manage point cloud transactions (C++ wrapper code)
 * \version 2015-10-14/AW: Initial version
 * \version 2021-11-17/AW: New function to discard transaction data (#3843)
 * \version 2021-11-18/AW: New function to estimate transaction size (#3837)
 *
 *******************************************************************************
 */

//---< INCLUDES >---------------------------------------------------------------

#include <cstdlib>

#include "riegl/rdb.h"
#include "riegl/rdb.hpp"

//---< NAMESPACE >--------------------------------------------------------------

namespace riegl {
namespace rdb {
namespace pointcloud {

//---< Transactions::PUBLIC >---------------------------------------------------

Transactions::Transactions(riegl::rdb::PointcloudData* pointcloud):
    data(pointcloud)
{
}

Transaction::ID Transactions::begin(
    const std::string &title,
    const std::string &agent,
    const std::string &comments,
    const std::string &settings
)
{
    Transaction::ID result(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_begin(
        data->contextHandle(), data->pointcloud,
        title.c_str(), agent.c_str(), comments.c_str(), settings.c_str(),
        &result
    ));
    return result;
}

void Transactions::commit(
    Progress            progress,
    void               *userdata,
    const std::uint32_t signature,
    const std::uint32_t key_size,
    const void* const   key_data
)
{
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_commit_with_signature(
        data->contextHandle(), data->pointcloud,
        reinterpret_cast<RDBProgress>(progress),
        userdata, signature, key_size, key_data
    ));
}

void Transactions::rollback()
{
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_rollback(
        data->contextHandle(), data->pointcloud
    ));
}

std::vector<Transaction::ID> Transactions::list() const
{
    std::uint32_t count(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_list(
        data->contextHandle(), data->pointcloud, &count, 0 // = query count
    ));
    std::vector<Transaction::ID> result(count);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_list(
        data->contextHandle(), data->pointcloud, &count, result.data()
    ));
    return result;
}

Transaction::ID Transactions::current() const
{
    Transaction::ID result(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_current(
        data->contextHandle(), data->pointcloud, &result
    ));
    return result;
} // current()

bool Transactions::pending() const
{
    std::uint32_t result(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_pending(
        data->contextHandle(), data->pointcloud, &result
    ));
    return (result != 0);
} // pending()

Transaction Transactions::details(const Transaction::ID transaction) const
{
    TransactionWrapper buffer(data->contextHandle());
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_details(
        data->contextHandle(), data->pointcloud, transaction, buffer.handle
    ));
    Transaction result;
    transactionRead(data->contextHandle(), buffer.handle, result);
    return result;
}

void Transactions::restore(const Transaction::ID transaction)
{
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_restore(
        data->contextHandle(), data->pointcloud, transaction
    ));
}

void Transactions::discard(const Transaction::ID transaction)
{
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_discard(
        data->contextHandle(), data->pointcloud,
        static_cast<std::uint32_t>(1),
        static_cast<const RDBPointcloudTransactionID*>(&transaction)
    ));
}

void Transactions::discard(const std::vector<Transaction::ID> &transactions)
{
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_discard(
        data->contextHandle(), data->pointcloud,
        static_cast<std::uint32_t>(transactions.size()),
        static_cast<const RDBPointcloudTransactionID*>(transactions.data())
    ));
}

std::uint64_t Transactions::size(const Transaction::ID transaction) const
{
    std::uint64_t result(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_size(
        data->contextHandle(), data->pointcloud,
        static_cast<std::uint32_t>(1),
        static_cast<const RDBPointcloudTransactionID*>(&transaction),
        &result
    ));
    return result;
}

std::uint64_t Transactions::size(const std::vector<Transaction::ID> &transactions) const
{
    std::uint64_t result(0);
    ErrorImpl::check(data->contextHandle(), rdb_pointcloud_transaction_size(
        data->contextHandle(), data->pointcloud,
        static_cast<std::uint32_t>(transactions.size()),
        static_cast<const RDBPointcloudTransactionID*>(transactions.data()),
        &result
    ));
    return result;
}

}}} // namespace riegl::rdb::pointcloud
