/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2007 Piotr Jaroszyński <peper@gentoo.org>
 *
 * This file is part of the Paludis package manager. Paludis is free software;
 * you can redistribute it and/or modify it under the terms of the GNU General
 * Public License version 2, as published by the Free Software Foundation.
 *
 * Paludis 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <paludis_python.hh>

#include <paludis/environment.hh>
#include <paludis/environments/environment_maker.hh>
#include <paludis/environments/paludis/paludis_environment.hh>
#include <paludis/environments/paludis/paludis_config.hh>
#include <paludis/environments/no_config/no_config_environment.hh>

namespace p = paludis;
namespace pp = paludis::python;
namespace bp = boost::python;

//struct EnvironmentWrapper :
//    p::Environment,
//    bp::wrapper<p::Environment>
//{
//    std::tr1::shared_ptr<const p::DestinationsCollection>
//    default_destinations() const
//    {
//        return this->get_override("default_destinations")();
//    }
//
//    bool
//    query_use(const p::UseFlagName & ufn, const p::PackageDatabaseEntry & pde) const
//    {
//        return this->get_override("query_use")(ufn, pde);
//    }
//
//    const p::FSEntry
//    root() const
//    {
//        return this->get_override("root")();
//    }
//
//    std::tr1::shared_ptr<const p::SetNameCollection>
//    set_names() const
//    {
//        return this->get_override("set_names")();
//    }
//
//    std::tr1::shared_ptr<p::DepSpec>
//    set(const p::SetName & sn) const
//    {
//        if (bp::override set = this->get_override("set"))
//            return this->set(sn);
//        return p::Environment::set(sn);
//    }
//
//    std::tr1::shared_ptr<p::DepSpec>
//    default_set(const p::SetName & sn) const
//    {
//        return p::Environment::set(sn);
//    }
//};

struct NoConfigEnvironmentWrapper :
    p::NoConfigEnvironment
{
    NoConfigEnvironmentWrapper(const p::FSEntry & env_dir, const p::FSEntry & cache_dir,
            const p::FSEntry & master_repo_dir) :
        p::NoConfigEnvironment(p::NoConfigEnvironmentParams(env_dir, cache_dir, false,
                    p::ncer_auto, master_repo_dir)
                )
    {
    }
};

void expose_environment()
{
    static pp::register_exception<p::NoSuchEnvironmentTypeError>
        NoSuchEnvironmentTypeError("NoSuchEnvironmentTypeError");
    static pp::register_exception<p::PaludisEnvironmentSoDirNotADirectoryError>
        PaludisEnvironmentSoDirNotADirectoryError("PaludisEnvironmentSoDirNotADirectoryError");
    static pp::register_exception<p::PaludisEnvironmentSoDirCannotDlopenError>
        PaludisEnvironmentSoDirCannotDlopenError("PaludisEnvironmentSoDirCannotDlopenError");
    static pp::register_exception<p::PaludisConfigError>
        PaludisConfigError("PaludisConfigError");
    static pp::register_exception<p::PaludisConfigNoDirectoryError>
        PaludisConfigNoDirectoryError("PaludisConfigNoDirectoryError");

    bp::class_<p::EnvironmentMaker, boost::noncopyable> em("EnvironmentMaker",
            "Virtual constructor for environments.",
            bp::no_init);
    em.def("make_from_spec", &p::EnvironmentMaker::make_from_spec,
            "make_from_spec(spec_string) -> Environment\n"
            "Make Environment from specification."
            );
    em.add_static_property("instance", bp::make_function(&p::EnvironmentMaker::get_instance,
                bp::return_value_policy<bp::reference_existing_object>()),
            "Singleton instance."
          );

    bp::enum_<p::MaskReasonsOption>
        mro("MaskReasonsOption");
    mro.value("OVERRIDE_UNKEYWORDED", p::mro_override_unkeyworded);
    mro.value("OVERRIDE_TILDE_KEYWORDS", p::mro_override_tilde_keywords);

    pp::class_options<p::MaskReasonsOptions>
    mrs("MaskReasonsOptions", "MaskReasonsOption",
            "Options for Environment.mask_reasons()."
       );

    //pp::register_shared_ptrs_to_python< std::tr1::shared_ptr<EnvironmentMaker> >();
    //pp::register_shared_ptrs_to_python< std::tr1::shared_ptr<p::Environment> >();
    //bp::class_<EnvironmentWrapper, std::tr1::shared_ptr<p::Environment>, boost::noncopyable>
    bp::class_<p::Environment, std::tr1::shared_ptr<p::Environment>, boost::noncopyable>
        e("Environment",
                "Represents a working environment, which contains an available packages database\n"
                "and provides various methods for querying package visibility and options.",
                bp::no_init
         );
    e.def("default_destinations", &p::Environment::default_destinations,
            "default_destinations() -> DestinationsCollection\n"
            "Default destination candidates for installing packages."
         );
    std::tr1::shared_ptr<p::PackageDatabase> (p::Environment::* package_database)() =
        &p::Environment::package_database;
    e.add_property("package_database", bp::make_function(package_database,
                bp::with_custodian_and_ward_postcall<0, 1>()),
            "[ro] PackageDatabase\n"
            "Our package database."
         );
    e.def("set", &p::Environment::set,
            "set(SetName) -> DepSpec\n"
            "Fetch a named set."
         );
    e.def("query_use", &p::Environment::query_use,
            "query_use(UseFlagName, PackageDatabaseEntry) -> bool\n"
            "Is a particular use flag enabled for a particular package?"
         );
    e.def("mask_reasons", &p::Environment::mask_reasons,
            (bp::arg("PackageDatabaseEntry"), bp::arg("MaskReasonOptions")=p::MaskReasonsOptions()),
            "mask_reasons(PackageDatabaseEntry, MaskReasonsOptions=MaskReasonsOptions())"
            " -> set of MaskReason\n"
            "Return the reasons for a package being masked."
         );
    e.def("root", &p::Environment::root,
            "root() -> string\n"
            "Our root location for installs."
         );
    e.def("set_names", &p::Environment::set_names,
            "set_names() -> SetNamesCollection\n"
            "Return all known named sets."
         );

    bp::class_<p::PaludisEnvironment, bp::bases<p::Environment>, boost::noncopyable>
        pe("PaludisEnvironment",
                "The PaludisEnvironment is an Environment that corresponds to the normal operating evironment.",
                bp::init<const std::string &>("__init__(string)")
          );
        pe.add_property("config_dir", &p::PaludisEnvironment::config_dir,
                "[ro] string\n"
                "The config directory."
              );

    bp::class_<NoConfigEnvironmentWrapper, bp::bases<p::Environment>, boost::noncopyable>
        nce("NoConfigEnvironment",
                "An environment that uses a single repository, with no user configuration.",
                bp::init<const p::FSEntry &, const p::FSEntry &, const p::FSEntry &>(
                    (bp::arg("environment_dir"), bp::arg("write_cache_dir")="/var/empty",
                     bp::arg("master_repository_dir")="/var/empty"),
                    "__init__(environment_dir, write_cache_dir=\"/var/empty\", "
                        "master_repository_dir=\"/var/empty\")"
                    )
          );
    std::tr1::shared_ptr<p::Repository> (p::NoConfigEnvironment::*main_repository)() =
        &p::NoConfigEnvironment::main_repository;
    nce.add_property("main_repository", main_repository,
            "[ro] Repository\n"
            "Main repository."
            );
    std::tr1::shared_ptr<p::Repository> (p::NoConfigEnvironment::*master_repository)()
        = &p::NoConfigEnvironment::master_repository;
    nce.add_property("master_repository", master_repository,
            "[ro] Repository\n"
            "Master repository."
            );
    nce.add_property("accept_unstable", bp::object(), &p::NoConfigEnvironment::set_accept_unstable,
            "[wo] bool\n"
            "Should we accept unstable keywords?"
           );
}
