/*
Copyright Contributors to the libdnf project.

This file is part of libdnf: https://github.com/rpm-software-management/libdnf/

Libdnf is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.

Libdnf is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef LIBDNF5_TRANSACTION_COMPS_ENVIRONMENT_HPP
#define LIBDNF5_TRANSACTION_COMPS_ENVIRONMENT_HPP

#include "comps_group.hpp"

#include "libdnf5/comps/group/package.hpp"
#include "libdnf5/defs.h"

#include <memory>
#include <vector>


namespace libdnf5::transaction {

class Transaction;
class CompsEnvironmentGroup;
class CompsEnvironmentDbUtils;
class CompsEnvironmentGroupDbUtils;


/// CompsEnvironment contains a copy of important data from comps::CompsEnvironment that is used
/// to perform comps transaction and then stored in the transaction (history) database.
///
// @replaces libdnf:transaction/CompsEnvironmentItem.hpp:class:CompsEnvironmentItem
class LIBDNF_API CompsEnvironment : public TransactionItem {
public:
    /// Get string representation of the object, which equals to environment_id
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.toStr()
    std::string to_string() const;

    CompsEnvironment(const CompsEnvironment & src);
    CompsEnvironment & operator=(const CompsEnvironment & src);
    CompsEnvironment(CompsEnvironment && src) noexcept;
    CompsEnvironment & operator=(CompsEnvironment && src) noexcept;
    ~CompsEnvironment();

private:
    friend Transaction;
    friend CompsEnvironmentDbUtils;
    friend CompsEnvironmentGroupDbUtils;

    LIBDNF_LOCAL explicit CompsEnvironment(const Transaction & trans);

    /// Get text id of the environment (xml element: `<comps><environment><id>VALUE</id>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.getEnvironmentId()
    LIBDNF_LOCAL const std::string & get_environment_id() const noexcept;

    /// Set text id of the environment (xml element: `<comps><environment><id>VALUE</id>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.setEnvironmentId(const std::string & value)
    LIBDNF_LOCAL void set_environment_id(const std::string & value);

    /// Get name of the environment (xml element: `<comps><environment><name>VALUE</name>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.getName()
    LIBDNF_LOCAL const std::string & get_name() const noexcept;

    /// Set name of the environment (xml element: `<comps><environment><name>VALUE</name>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.setName(const std::string & value)
    LIBDNF_LOCAL void set_name(const std::string & value);

    /// Get translated name of the environment in the current locale (xml element: `<comps><environment><name xml:lang="...">VALUE</name>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.getTranslatedName()
    LIBDNF_LOCAL const std::string & get_translated_name() const noexcept;

    /// Set translated name of the environment in the current locale (xml element: `<comps><environment><name xml:lang="...">VALUE</name>...`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.setTranslatedName(const std::string & value)
    LIBDNF_LOCAL void set_translated_name(const std::string & value);

    /// Get types of the packages to be installed with the environment (related xml elements: `<comps><group><packagelist><packagereq type="VALUE" ...>`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.getPackageTypes()
    LIBDNF_LOCAL libdnf5::comps::PackageType get_package_types() const noexcept;

    /// Set types of the packages to be installed with the environment (related xml elements: `<comps><group><packagelist><packagereq type="VALUE" ...>`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.setPackageTypes(libdnf::CompsPackageType value)
    LIBDNF_LOCAL void set_package_types(libdnf5::comps::PackageType value);

    /// Create a new CompsEnvironmentGroup object and return a reference to it.
    /// The object is owned by the CompsEnvironment.
    LIBDNF_LOCAL CompsEnvironmentGroup & new_group();

    /// Get list of groups associated with the environment.
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentItem.getGroups()
    LIBDNF_LOCAL std::vector<CompsEnvironmentGroup> & get_groups();

    // TODO(dmach): rewrite into TransactionSack.list_installed_environments(); how to deal with references to different transactions? We don't want all of them loaded into memory.
    //static std::vector< TransactionItemPtr > getTransactionItemsByPattern(
    //    libdnf5::utils::SQLite3Ptr conn,
    //    const std::string &pattern);

    class LIBDNF_LOCAL Impl;
    std::unique_ptr<Impl> p_impl;
};


// @replaces libdnf:transaction/CompsEnvironmentItem.hpp:class:CompsEnvironmentGroup
class LIBDNF_API CompsEnvironmentGroup {
public:
    ~CompsEnvironmentGroup();
    CompsEnvironmentGroup(const CompsEnvironmentGroup & src);
    CompsEnvironmentGroup & operator=(const CompsEnvironmentGroup & src);
    CompsEnvironmentGroup(CompsEnvironmentGroup && src) noexcept;
    CompsEnvironmentGroup & operator=(CompsEnvironmentGroup && src) noexcept;
    CompsEnvironmentGroup();

private:
    friend Transaction;
    friend CompsEnvironmentGroupDbUtils;

    /// Get database id (primary key)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.getId()
    LIBDNF_LOCAL int64_t get_id() const noexcept;

    /// Set database id (primary key)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.setId(int64_t value)
    LIBDNF_LOCAL void set_id(int64_t value);

    /// Get groupid of a group associated with a comps environment (xml element: `<comps><environment><grouplist><groupid>VALUE</groupid>`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.getGroupId()
    LIBDNF_LOCAL const std::string & get_group_id() const noexcept;

    /// Set groupid of a group associated with a comps environment (xml element: `<comps><environment><grouplist><groupid>VALUE</groupid>`)
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.setGroupId(const std::string & value)
    LIBDNF_LOCAL void set_group_id(const std::string & value);

    /// Get a flag that determines if the group was present after the transaction it's associated with has finished.
    /// If the group was installed before running the transaction, it's still counted as installed.
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.getInstalled()
    LIBDNF_LOCAL bool get_installed() const noexcept;

    /// Set a flag that determines if the group was present after the transaction it's associated with has finished.
    /// If the group was installed before running the transaction, it's still counted as installed.
    ///
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.setInstalled(bool value)
    LIBDNF_LOCAL void set_installed(bool value);

    // TODO(dmach): this is not entirely clear; investigate and document
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.getGroupType()
    LIBDNF_LOCAL libdnf5::comps::PackageType get_group_type() const noexcept;

    // TODO(dmach): this is not entirely clear; investigate and document
    // @replaces libdnf:transaction/CompsEnvironmentItem.hpp:method:CompsEnvironmentGroup.setGroupType(libdnf::CompsPackageType value)
    LIBDNF_LOCAL void set_group_type(libdnf5::comps::PackageType value);

    class LIBDNF_LOCAL Impl;
    std::unique_ptr<Impl> p_impl;
};

}  // namespace libdnf5::transaction

#endif  // LIBDNF5_TRANSACTION_COMPS_ENVIRONMENT_HPP
