/* 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/dep_spec.hh>

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

void expose_dep_spec()
{
    static pp::register_exception<p::PackageDepSpecError>
        PackageDepSpecError("PackageDepSpecError");

    bp::enum_<p::PackageDepSpecParseMode>
        pds_pm("PackageDepSpecParseMode");
    pds_pm.value("EAPI_0", p::pds_pm_eapi_0);
    pds_pm.value("EAPI_0_STRICT", p::pds_pm_eapi_0_strict);
    pds_pm.value("PERMISSIVE", p::pds_pm_permissive);
    pds_pm.value("UNSPECIFIC", p::pds_pm_unspecific);
    pds_pm.value("LAST", p::last_pds_pm);

    pp::register_shared_ptrs_to_python<p::DepSpec>();
    bp::class_<p::DepSpec, boost::noncopyable>
        ds("DepSpec",
                "Base class for a dependency spec.",
                bp::no_init
          );
    ds.def("as_use_dep_spec", &p::DepSpec::as_use_dep_spec,
            bp::return_value_policy<bp::reference_existing_object>(),
            "as_use_dep_spec() -> UseDepSpec\n"
            "Return us as a UseDepSpec, or None if we are not a UseDepSpec."
          );
    ds.def("as_package_dep_spec", &p::DepSpec::as_package_dep_spec,
            bp::return_value_policy<bp::reference_existing_object>(),
            "as_package_dep_spec() -> PackageDepSpec\n"
            "Return us as a PackageDepSpec, or None if we are not a UseDepSpec."
          );

    pp::register_shared_ptrs_to_python<p::CompositeDepSpec>();
    bp::class_<p::CompositeDepSpec, bp::bases<p::DepSpec>, boost::noncopyable>
        cds("CompositeDepSpec",
                "Iterable class for dependency specs that have a number of child dependency specs.",
                bp::no_init
          );
    cds.def("__iter__", bp::range(&p::CompositeDepSpec::begin, &p::CompositeDepSpec::end));

    bp::class_<p::AnyDepSpec, bp::bases<p::CompositeDepSpec>, boost::noncopyable>
        anyds("AnyDepSpec",
                "Represents a \"|| ( )\" dependency block.",
                bp::no_init
          );

    bp::class_<p::AllDepSpec, bp::bases<p::CompositeDepSpec>, boost::noncopyable>
        allds("AllDepSpec",
                "Represents a ( first second third ) or top level group of dependency specs.",
                bp::no_init
          );

    bp::class_<p::UseDepSpec, bp::bases<p::CompositeDepSpec>, boost::noncopyable>
        useds("UseDepSpec",
                "Represents a use? ( ) dependency spec.",
                bp::no_init
          );
    useds.add_property("flag", &p::UseDepSpec::flag,
            "[ro] UseFlagName\n"
            "Our use flag name."
            );
    useds.add_property("inverse", &p::UseDepSpec::inverse,
            "[ro] bool\n"
            "Are we a ! flag?"
            );

    bp::class_<p::StringDepSpec, bp::bases<p::DepSpec>, boost::noncopyable>
        strds("StringDepSpec",
                "A StringDepSpec represents a non-composite dep spec with an associated piece of text.",
                bp::no_init
             );

    bp::to_python_converter<std::pair<const p::UseFlagName, p::UseFlagState>,
            pp::pair_to_tuple<const p::UseFlagName, p::UseFlagState> >();
    bp::class_<p::UseRequirements>
        ur("UseRequirements",
                "A selection of USE flag requirements.",
                bp::no_init
          );
    ur.def("state", &p::UseRequirements::state,
            "state(UseFlagName) -> UseFlagState\n"
            "What state is desired for a particular use flag?"
          );
    ur.def("__iter__", bp::range(&p::UseRequirements::begin, &p::UseRequirements::end));
    pp::register_shared_ptrs_to_python<p::UseRequirements>();

    bp::class_<p::PackageDepSpec, std::tr1::shared_ptr<const p::PackageDepSpec>, bp::bases<p::StringDepSpec> >
        pkgds("PackageDepSpec",
                "A PackageDepSpec represents a package name (for example, 'app-editors/vim'),"
                " possibly with associated version and SLOT restrictions.",
                bp::init<const std::string &, const p::PackageDepSpecParseMode>(
                    "__init__(string, PackageDepSpecParseMode)"
                    )
           );
    pkgds.add_property("package", &p::PackageDepSpec::package_ptr,
            "[ro] QualifiedPackageName\n"
            "Qualified package name."
           );
    pkgds.add_property("package_name_part", &p::PackageDepSpec::package_name_part_ptr,
            "[ro] PackageNamePart\n"
            "Package name part (may be None)"
           );
    pkgds.add_property("category_name_part", &p::PackageDepSpec::category_name_part_ptr,
            "[ro] CategoryNamePart\n"
            "Category name part (may be None)."
           );
    std::tr1::shared_ptr<const p::VersionRequirements> (p::PackageDepSpec::*version_requirements)() const =
        &p::PackageDepSpec::version_requirements_ptr;
    pkgds.add_property("version_requirements", version_requirements,
            "[ro] VersionRequirements\n"
            "Version requirements (may be None)."
           );
    pkgds.add_property("version_requirements_mode", &p::PackageDepSpec::version_requirements_mode,
            "[ro] VersionRequirementsMode\n"
            "Version requirements mode."
           );
    pkgds.add_property("slot", &p::PackageDepSpec::slot_ptr,
            "[ro] SlotName\n"
            "Slot name (may be None)."
           );
    pkgds.add_property("repository", &p::PackageDepSpec::repository_ptr,
            "[ro] RepositoryName\n"
            "Repository name (may be None)."
           );
    pkgds.add_property("use_requirements", &p::PackageDepSpec::use_requirements_ptr,
            "[ro] UseRequirements\n"
            "Use requirements (may be None)."
           );
    pkgds.def(bp::self_ns::str(bp::self));

    bp::class_<p::PlainTextDepSpec, bp::bases<p::StringDepSpec>, boost::noncopyable >
        ptds("PlainTextDepSpec",
                "A PlainTextDepSpec represents a plain text entry (for example, a URI in SRC_URI).",
                bp::init<const std::string &>("__init__(string)")
           );
    ptds.def(bp::self_ns::str(bp::self));

    bp::class_<p::BlockDepSpec, bp::bases<p::StringDepSpec>, boost::noncopyable >
        bds("BlockDepSpec",
                "A BlockDepSpec represents a block on a package name (for example, 'app-editors/vim'),"
                "possibly with associated version and SLOT restrictions.",
                bp::init<std::tr1::shared_ptr<const p::PackageDepSpec> >("__init__(PackageDepSpec)")
           );
    bds.add_property("blocked_spec", &p::BlockDepSpec::blocked_spec,
            "[ro] PackageDepSpec\n"
            "The spec we're blocking."
           );
}
