#!/bin/sh

set -eu

libpath="/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/wayfire/libfiredecor.so"
if [ ! -e "$libpath" ]; then
	echo "$libpath does not exist" >&2
	exit 1
fi

cd "$AUTOPKGTEST_TMP"

cat << END > test.cc
#include <wayfire/plugin.hpp>
#include <errno.h>
#include <dlfcn.h>
#include <memory>
#include <stdexcept>
#include <stdio.h>
#include <inttypes.h>

namespace nonstd {
	template<class W> class observer_ptr {};
}

namespace wf {
	class toplevel_t {};
	class output_t {};
	class pointf_t {};
	class custom_data_t {};
	class object_base_t {
		virtual ~object_base_t() = default;
		void erase_data(std::string);
		void _fetch_data(std::string);
		void _store_data(std::unique_ptr<custom_data_t>, std::string);
	};
	class toplevel_view_interface_t {
		virtual ~toplevel_view_interface_t() = default;
		void toplevel() const;

	};
	class view_interface_t {
		virtual ~view_interface_t() = default;
		void get_surface_root_node() const;
	};
	using wayfire_view = nonstd::observer_ptr<wf::view_interface_t>;
	class view_matcher_t {
		view_matcher_t(const std::string&);
		~view_matcher_t();
		void matches(wayfire_view);
	};
	class render_target_t {
		void logic_scissor(wlr_box) const;
		void get_orthographic_projection() const;
	};
	struct point_t {};
	struct region_t {
		region_t();
		region_t(region_t const&);
		region_t(region_t &&);
		region_t(const wlr_box&);
		region_t& operator=(const region_t&);
		region_t& operator=(region_t&&);
		region_t operator+(const point_t&) const;
		region_t operator&(const region_t&) const;
		region_t& operator|=(const wlr_box&);
		void contains_point(const point_t&) const;
		void contains_pointf(const pointf_t&) const;
		void begin() const;
		void end() const;
		void clear();
		void empty() const;
		~region_t();
	};
	class compositor_core_t {
		void get_all_views();
	};
	class wl_idle_call {
		using callback_t = std::function<void ()>;
		wl_idle_call();
		~wl_idle_call();
		void run_once(callback_t);
	};
	class output_workarea_manager_t {
		void get_workarea();
	};
	class texture_t {
		texture_t(unsigned int);
	};
	struct framebuffer_t {};
	struct color_t {};
	struct dimensions_t {};
	using geometry_t = wlr_box;
	geometry_t clamp(geometry_t, geometry_t);
	void print_trace(bool);
	void dimensions(wlr_box const&);
	void get_core();
	void find_view_for_toplevel(std::shared_ptr<wf::toplevel_t>);
	void construct_box(wf::point_t const&, wf::dimensions_t const&);
	template<bool A> class wl_timer {
		using callback_t = std::function<std::conditional_t<A, bool, void>()>;
		~wl_timer();
		void is_connected();
		void set_timeout(uint32_t timeout_ms, callback_t call);
	};
	template class wl_timer<true>;
	template class wl_timer<false>;
	namespace detail {
		void option_wrapper_debug_message(const std::string&, const std::logic_error&);
		void option_wrapper_debug_message(const std::string&, const std::runtime_error&);
	};
	namespace txn {
		class transaction_object_t {
			virtual ~transaction_object_t() = default;
		};
		using transaction_object_sptr = std::shared_ptr<transaction_object_t>;
		class transaction_t {
			void get_objects() const;
		};
		class transaction_manager_t {
			void schedule_object(transaction_object_sptr);
		};
	};
	namespace scene {
		class node_t {
		public:
			node_t();
			node_t(bool);
			virtual ~node_t() = default;
			void keyboard_refocus(wf::output_t*);
			void to_local(wf::pointf_t const&);
			void to_global(wf::pointf_t const&);
			std::string stringify() const;
			void optimize_update(unsigned int);
		};
		using node_ptr = std::shared_ptr<node_t>;
		class floating_inner_node_t {
			void set_children_list(std::vector<node_ptr>);
			virtual ~floating_inner_node_t() = default;
		};
		void update(node_ptr changed_node, uint32_t flags);
	};
	namespace signal {
		class connection_base_t {
			void disconnect();
		};
	};
};

namespace glm {
	enum qualifier {};
	template<int A, typename B, qualifier C> class vec { virtual ~vec() = default; };
	typedef vec<4, float, qualifier(0)> vec4;
	template<int A, int B, typename C, qualifier D> class mat { virtual ~mat() = default; };
	typedef mat<4, 4, float, qualifier(0)> mat4;
}

namespace OpenGL {
	void render_rectangle(wf::geometry_t, wf::color_t, glm::mat4);
	void render_texture(wf::texture_t, const wf::render_target_t&, const wf::geometry_t&, glm::vec4 color, uint32_t bits);
	void render_begin(wf::framebuffer_t const&);
	void render_begin();
	void render_end();
};

wf::texture_t::texture_t(unsigned int) {};
void wf::construct_box(wf::point_t const&, wf::dimensions_t const&) {};
void wf::output_workarea_manager_t::get_workarea() {};
void wf::find_view_for_toplevel(std::shared_ptr<wf::toplevel_t>) {};
template<bool A> wf::wl_timer<A>::~wl_timer() {};
template<bool A> void wf::wl_timer<A>::is_connected() {};
template<bool A> void wf::wl_timer<A>::set_timeout(uint32_t, wf::wl_timer<A>::callback_t) {};
void wf::detail::option_wrapper_debug_message(const std::string&, const std::logic_error&) {};
void wf::detail::option_wrapper_debug_message(const std::string&, const std::runtime_error&) {};
void wf::get_core() {};
wf::wl_idle_call::wl_idle_call() {};
wf::wl_idle_call::~wl_idle_call() {};
void wf::wl_idle_call::run_once(wf::wl_idle_call::callback_t) {};
void operator+(wlr_box const&, wf::point_t const&) {};
void operator&(wlr_box const&, wf::point_t const&) {};
void wf::signal::connection_base_t::disconnect() {};
void wf::compositor_core_t::get_all_views() {};
void wlr_box_from_pixman_box(pixman_box32 const&) {};
wf::region_t::region_t() { };
wf::region_t::region_t(wf::region_t const&) { };
wf::region_t::region_t(wf::region_t &&) { };
wf::region_t::region_t(const wlr_box&) { };
wf::region_t& wf::region_t::operator=(const wf::region_t& v) { return *this; };
wf::region_t& wf::region_t::operator=(wf::region_t&& v) { return v; };
wf::region_t wf::region_t::operator+(const point_t& v) const { return wf::region_t(); };
wf::region_t wf::region_t::operator&(const region_t& v) const { return v; };
wf::region_t& wf::region_t::operator|=(const wlr_box& v) { return *this; };
wf::region_t::~region_t() { };
void wf::region_t::contains_point(const point_t& point) const {};
void wf::region_t::contains_pointf(const pointf_t& point) const {};
void wf::region_t::begin() const { };
void wf::region_t::end() const { };
void wf::region_t::clear() { };
void wf::region_t::empty() const { };
void OpenGL::render_texture(wf::texture_t, const wf::render_target_t&, const wf::geometry_t&, glm::vec4 color, uint32_t bits) {};
void OpenGL::render_rectangle(wlr_box, wf::color_t, glm::mat4) {};
void OpenGL::render_begin(wf::framebuffer_t const&) {};
void OpenGL::render_begin() {};
void OpenGL::render_end() {};
wf::geometry_t wf::clamp(wf::geometry_t, wf::geometry_t) { return wlr_box(); };
void wf::print_trace(bool) { };
void wf::dimensions(wlr_box const&) {};
void wf::render_target_t::logic_scissor(wlr_box) const {};
void wf::render_target_t::get_orthographic_projection() const {};
wf::view_matcher_t::view_matcher_t(const std::string&) {};
void wf::view_matcher_t::matches(wf::wayfire_view) {};
wf::view_matcher_t::~view_matcher_t() {};
void wf::plugin_interface_t::init() {};
void wf::plugin_interface_t::fini() {};
wf::scene::node_t::node_t() {};
wf::scene::node_t::node_t(bool) {};
void wf::scene::update(node_ptr changed_node, uint32_t flags) {};
void wf::scene::node_t::keyboard_refocus(wf::output_t*) {};
void wf::scene::node_t::to_local(wf::pointf_t const&) {};
void wf::scene::node_t::to_global(wf::pointf_t const&) {};
std::string wf::scene::node_t::stringify() const { return ""; };
void wf::scene::node_t::optimize_update(unsigned int) { };
void wf::view_interface_t::get_surface_root_node() const {};
void wf::txn::transaction_t::get_objects() const {};
void wf::txn::transaction_manager_t::schedule_object(wf::txn::transaction_object_sptr) {};
void gl_call(const char*, uint32_t, const char*) {};
void wf::toplevel_view_interface_t::toplevel() const {};
void wf::scene::floating_inner_node_t::set_children_list(std::vector<node_ptr>) {};
void wf::object_base_t::erase_data(std::string) {};
void wf::object_base_t::_fetch_data(std::string) {};
void wf::object_base_t::_store_data(std::unique_ptr<custom_data_t>, std::string) {};

// Create one instance to make sure the vtable is not optimized out.
static wf::object_base_t *ptr1 = new wf::object_base_t();
static wf::txn::transaction_object_t *ptr = new wf::txn::transaction_object_t();
static wf::scene::node_t *ptr2 = new wf::scene::node_t();
static wf::toplevel_view_interface_t *ptr3 = new wf::toplevel_view_interface_t();
static wf::scene::floating_inner_node_t *ptr4 = new wf::scene::floating_inner_node_t();
static wf::view_interface_t *ptr5 = new wf::view_interface_t();


int main(int argc, char* argv[]) {
	void *handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
	if (handle == NULL) {
		fprintf(stderr, "dlopen failed: %s\n", dlerror());
		return 1;
	}
	uint32_t (*version_func)() = (uint32_t (*)())dlsym(handle, "getWayfireVersion");
	if (version_func == NULL) {
		perror("dlsym failed");
		dlclose(handle);
		return 1;
	}
	int32_t plugin_abi_version = version_func();
	dlclose(handle);
	fprintf(stdout, "wayfire is: %" PRIu32 "\n", WAYFIRE_API_ABI_VERSION);
	fprintf(stdout, "plugin is: %" PRIu32 "\n", plugin_abi_version);
	if (WAYFIRE_API_ABI_VERSION != plugin_abi_version) {
		fprintf(stderr, "API/ABI version mismatch:\n");
		return 1;
	}
	return 0;
}
END

g++ -o test test.cc -Wall -ldl $(pkg-config --cflags pixman-1 wlroots-0.18) -DWLR_USE_UNSTABLE -rdynamic
./test "$libpath"
