/*
 *******************************************************************************
 *
 *  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    metaData.hpp
 * \author  RIEGL LMS GmbH, Austria
 * \brief   Manage point cloud meta data
 * \version 2015-10-14/AW: Initial version
 * \version 2017-11-24/AW: Constructors declared as "explicit" (#2825)
 * \version 2018-06-01/AW: New function to validate metadata entry (#3109)
 * \version 2020-03-30/AW: New functions for metadata signatures (#3570)
 *
 *******************************************************************************
 */

#ifndef RIEGL_RDB_POINTCLOUD_METADATA_HPP
#define RIEGL_RDB_POINTCLOUD_METADATA_HPP

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

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

#include "riegl/rdb/pointcloud/pointcloudData.hpp"

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

namespace riegl {
namespace rdb {
namespace pointcloud {

//---< CLASS MetaData >---------------------------------------------------------
/*!
 * \brief Manage point cloud meta data
 *
 * This class allows to manage database-wide properties (aka. "meta-data").
 * Arbitrary properties can be stored in key-value manner along with the
 * point cloud in the database. This might be used for example to store
 * comments, operator/software name or georeferencing information.
 *
 * \see riegl::rdb::Pointcloud::metaData()
 */
class MetaData
{
public:
    /*!
     * \brief Constructor
     * \note  You cannot create new MetaData objects directly,
     *        use riegl::rdb::Pointcloud::metaData() instead.
     */
    explicit MetaData(riegl::rdb::PointcloudData* pointcloud);

    /*!
     * \brief Query property names
     *
     * \returns a list of property names
     */
    std::vector<std::string> list() const;

    /*!
     * \brief Check if property exists
     *
     * \note Property names are case sensitive (i.e. "name" and "NAME" are different properties).
     * \returns true if a property with given name exists
     */
    bool exists(
        const std::string &name //!< [in] property name
    ) const;

    /*!
     * \brief Set property value
     *
     * \note Strings are truncated before the first zero byte (if any).
     */
    void set(
        const std::string &name, //!< [in] property name
        const std::string &value //!< [in] property value
    );

    /*!
     * \brief Get property value
     *
     * If the given property name could not be found, the function returns
     * the given default value.
     */
    std::string get(
        const std::string &name,             //!< [in] property name
        const std::string &defaultValue = "" //!< [in] default value
    ) const;

    /*!
     * \brief Delete property
     *
     * If the given property name could not be found, this function does not fail.
     */
    void remove(
        const std::string &name //!< [in] property name
     );

    /*!
     * \brief Validate property value
     *
     * This function validates the property given by 'name' against the
     * corresponding built-in schema for RIEGL default metadata entries.
     *
     * If the value does not correspond to the schema, an exception
     * is thrown and the reason can be found in the exception details.
     */
    void validate(
        const std::string &name //!< [in] name of property to be validated
    );

    /*!
     * \brief Validate value
     *
     * This function validates the given JSON value against the JSON schema.
     *
     * If the value does not correspond to the schema, an exception
     * is thrown and the reason can be found in the exception details.
     */
    void validate(
        const std::string &value, //!< [in] value to be validated
        const std::string &schema //!< [in] schema to be validated against
    );

    /*!
     * \brief Create a signature for a metadata entry.
     *
     * The signature is stored next to the metadata entry in the database file
     * and cannot be read out or modified. A transaction must be started first.
     *
     * Set 'method' to 0 to delete an existing signature ('key_size' and
     * 'key_data' are ignored in this case).
     *
     * \since 2.3.0
     */
    void createSignature(
        const std::string  &name,     //!< [in] name of metadata entry to sign
        const std::uint32_t method,   //!< [in] signature method (0: delete, 1: default)
        const std::uint32_t key_size, //!< [in] signature encryption key size (at least 32 byte)
        const void* const   key_data  //!< [in] signature encryption key buffer
    );

    /*!
     * \brief Verify the signature of a metadata entry.
     *
     * Returns 'false' if:
     *
     * - there is no signature for the metadata entry
     * - the signature does not match the current value
     * - a wrong signature encryption key was given
     *
     * Otherwise returns 'true'.
     *
     * Set 'method' to 0 to check if a signature exists, no matter if it is
     * valid or not ('key_size' and 'key_data' are ignored in this case).
     *
     * \since 2.3.0
     */
    bool verifySignature(
        const std::string  &name,     //!< [in] name of metadata entry to verify
        const std::uint32_t method,   //!< [in] signature method (0: exists, 1: default)
        const std::uint32_t key_size, //!< [in] signature encryption key size (at least 32 byte)
        const void* const   key_data  //!< [in] signature encryption key buffer
    ) const;

private:
    riegl::rdb::PointcloudData *data;
};

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

#endif // RIEGL_RDB_POINTCLOUD_METADATA_HPP
