#include "catch.hpp"

#include <type_traits>

#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/tags/matcher.hpp>

static_assert(std::is_default_constructible<osmium::TagMatcher>::value, "TagMatcher should be default constructible");
static_assert(std::is_copy_constructible<osmium::TagMatcher>::value, "TagMatcher should be copy constructible");
static_assert(std::is_move_constructible<osmium::TagMatcher>::value, "TagMatcher should be move constructible");
static_assert(std::is_copy_assignable<osmium::TagMatcher>::value, "TagMatcher should be copyable");
static_assert(std::is_move_assignable<osmium::TagMatcher>::value, "TagMatcher should be moveable");

TEST_CASE("Tag matcher") {
    osmium::memory::Buffer buffer{10240};

    const auto pos = osmium::builder::add_tag_list(buffer,
        osmium::builder::attr::_tags({
            { "highway", "primary" },
            { "name", "Main Street" },
            { "source", "GPS" }
    }));
    const osmium::TagList& tag_list = buffer.get<osmium::TagList>(pos);

    SECTION("Matching keys only") {
        osmium::TagMatcher m{osmium::StringMatcher::equal{"highway"}};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching keys only with shortcut const char*") {
        osmium::TagMatcher m{"highway"};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching keys only with shortcut std::string") {
        std::string s{"highway"};
        osmium::TagMatcher m{s};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching key and value") {
        osmium::TagMatcher m{osmium::StringMatcher::equal{"highway"},
                             osmium::StringMatcher::equal{"primary"}};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching key and value with shortcut") {
        osmium::TagMatcher m{"highway", "primary", false};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching key and value") {
        osmium::TagMatcher m{osmium::StringMatcher::equal{"highway"},
                             osmium::StringMatcher::equal{"secondary"}};
        REQUIRE_FALSE(m(tag_list));
    }

    SECTION("Matching key and value inverted") {
        osmium::TagMatcher m{osmium::StringMatcher::equal{"highway"},
                             osmium::StringMatcher::equal{"secondary"},
                             true};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }

    SECTION("Matching key and value list") {
        osmium::TagMatcher m{osmium::StringMatcher::equal{"highway"},
                             osmium::StringMatcher::list{{"primary", "secondary"}}};
        REQUIRE(m(tag_list));

        REQUIRE(m(*tag_list.begin()));
        REQUIRE_FALSE(m(*std::next(tag_list.begin())));
    }
}

