// Copyright 2005 Ben Hutchings <ben@decadent.org.uk>.
// See the file "COPYING" for licence details.

#include "browser_widget.hpp"

#include <cassert>

#include <gtkmozembed_internal.h>

browser_widget::browser_widget()
	: Gtk::Bin(GTK_BIN(gtk_moz_embed_new()))
{
}
browser_widget::~browser_widget()
{
}

GtkMozEmbed * browser_widget::gobj()
{
    return GTK_MOZ_EMBED(gobject_);
}
const GtkMozEmbed * browser_widget::gobj() const
{
    return GTK_MOZ_EMBED(gobject_);
}

void browser_widget::load_uri(const char * uri)
{
    gtk_moz_embed_load_url(gobj(), uri);
}
void browser_widget::load_uri(const std::string & uri)
{
    return load_uri(uri.c_str());
}
void browser_widget::stop_load()
{
    gtk_moz_embed_stop_load(gobj());
}
void browser_widget::go_back()
{
    gtk_moz_embed_go_back(gobj());
}
void browser_widget::go_forward()
{
    gtk_moz_embed_go_forward(gobj());
}
void browser_widget::reload(gint32 flags)
{
    gtk_moz_embed_reload(gobj(), flags);
}

bool browser_widget::can_go_back() const
{
    return gtk_moz_embed_can_go_back(const_cast<GtkMozEmbed *>(gobj()));
}
bool browser_widget::can_go_forward() const
{
    return gtk_moz_embed_can_go_forward(const_cast<GtkMozEmbed *>(gobj()));
}

namespace
{
    template<typename T>
    class c_scoped_ptr
    {
    public:
	explicit c_scoped_ptr(T * p = 0) : p_(p) {}
	~c_scoped_ptr() { free(p_); }
	T * get() const { return p_; }
	T * release()
	{
	    T * p = p_;
	    p_ = NULL;
	    return p;
	}
	void reset(T * p = 0)
	{
	    free(p_);
	    p_ = p;
	}
    private:
	T * p_;
    };
}

std::string browser_widget::get_link_message() const
{
    c_scoped_ptr<char> str(
	gtk_moz_embed_get_link_message(const_cast<GtkMozEmbed *>(gobj())));
    return std::string(str.get());
}
std::string browser_widget::get_js_status() const
{
    c_scoped_ptr<char> str(
	gtk_moz_embed_get_js_status(const_cast<GtkMozEmbed *>(gobj())));
    return std::string(str.get());
}
std::string browser_widget::get_title() const
{
    c_scoped_ptr<char> str(
	gtk_moz_embed_get_title(const_cast<GtkMozEmbed *>(gobj())));
    return std::string(str.get());
}
std::string browser_widget::get_location() const
{
    c_scoped_ptr<char> str(
	gtk_moz_embed_get_location(const_cast<GtkMozEmbed *>(gobj())));
    return std::string(str.get());
}
already_AddRefed<nsIWebBrowser> browser_widget::get_browser()
{
    nsIWebBrowser * result = 0;
    gtk_moz_embed_get_nsIWebBrowser(gobj(), &result);
    assert(result);
    return dont_AddRef(result);
}

namespace
{
    void browser_widget_signal_link_message_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_link_message_info =
    {
	"link_message",
	(GCallback) &browser_widget_signal_link_message_callback,
	(GCallback) &browser_widget_signal_link_message_callback
    };

    void browser_widget_signal_js_status_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_js_status_info =
    {
	"js_status",
	(GCallback) &browser_widget_signal_js_status_callback,
	(GCallback) &browser_widget_signal_js_status_callback
    };

    void browser_widget_signal_location_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_location_info =
    {
	"location",
	(GCallback) &browser_widget_signal_location_callback,
	(GCallback) &browser_widget_signal_location_callback
    };

    void browser_widget_signal_title_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_title_info =
    {
	"title",
	(GCallback) &browser_widget_signal_title_callback,
	(GCallback) &browser_widget_signal_title_callback
    };

    void browser_widget_signal_progress_callback(
	GtkMozEmbed * self, gint p0, gint p1, void * data)
    {
	typedef SigC::Slot2<void, gint, gint> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(p0, p1, slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_progress_info =
    {
	"progress",
	(GCallback) &browser_widget_signal_progress_callback,
	(GCallback) &browser_widget_signal_progress_callback
    };

    void browser_widget_signal_net_state_callback(
	GtkMozEmbed * self, const char * p0, gint p1, guint p2, void * data)
    {
	typedef SigC::Slot3<void, const char *, gint, guint> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(p0, p1, p2, slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_net_state_info =
    {
	"net_state_all",
	(GCallback) &browser_widget_signal_net_state_callback,
	(GCallback) &browser_widget_signal_net_state_callback
    };

    void browser_widget_signal_net_start_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_net_start_info =
    {
	"net_start",
	(GCallback) &browser_widget_signal_net_start_callback,
	(GCallback) &browser_widget_signal_net_start_callback
    };

    void browser_widget_signal_net_stop_callback(GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_net_stop_info =
    {
	"net_stop",
	(GCallback) &browser_widget_signal_net_stop_callback,
	(GCallback) &browser_widget_signal_net_stop_callback
    };

    void browser_widget_signal_new_window_callback(
	GtkMozEmbed * self, GtkMozEmbed ** p0, guint p1, void * data)
    {
	typedef SigC::Slot1<browser_widget *, guint> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		{
		    if (browser_widget * result =
			(*(SlotType::Proxy)(slot->proxy_))(p1, slot))
		    {
			*p0 = result->gobj();
			return;
		    }
		}
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}

	*p0 = NULL;
	return;
    }

    const Glib::SignalProxyInfo browser_widget_signal_new_window_info =
    {
	"new_window",
	(GCallback) &browser_widget_signal_new_window_callback,
	(GCallback) &browser_widget_signal_new_window_callback
    };

    void browser_widget_signal_visibility_callback(
	GtkMozEmbed * self, gboolean p0, void * data)
    {
	typedef SigC::Slot1<void, bool> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_visibility_info =
    {
	"visibility",
	(GCallback) &browser_widget_signal_visibility_callback,
	(GCallback) &browser_widget_signal_visibility_callback
    };

    void browser_widget_signal_destroy_browser_callback(
	GtkMozEmbed * self, void * data)
    {
	typedef SigC::Slot0<void> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    (*(SlotType::Proxy)(slot->proxy_))(slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}
    }

    const Glib::SignalProxyInfo browser_widget_signal_destroy_info =
    {
	"destroy_browser",
	(GCallback) &browser_widget_signal_destroy_browser_callback,
	(GCallback) &browser_widget_signal_destroy_browser_callback
    };

    gint browser_widget_signal_open_uri_callback(
	GtkMozEmbed * self, const char * p0, void * data)
    {
	typedef SigC::Slot1<bool, const char *> SlotType;

	if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
	{
	    try
	    {
		if (SigC::SlotNode * const slot =
		    Glib::SignalProxyNormal::data_to_slot(data))
		    return (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
	    }
	    catch(...)
	    {
		Glib::exception_handlers_invoke();
	    }
	}

	return 0;
    }

    const Glib::SignalProxyInfo browser_widget_signal_open_uri_info =
    {
	"open_uri",
	(GCallback) &browser_widget_signal_open_uri_callback,
	(GCallback) &browser_widget_signal_open_uri_callback
    };

} // namespace

Glib::SignalProxy0<void> browser_widget::signal_link_message()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_link_message_info);
}
Glib::SignalProxy0<void> browser_widget::signal_js_status()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_js_status_info);
}
Glib::SignalProxy0<void> browser_widget::signal_location()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_location_info);
}
Glib::SignalProxy0<void> browser_widget::signal_title()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_title_info);
}
Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> browser_widget::signal_progress()
{
    return Glib::SignalProxy2<void, gint, gint>(
	this, &browser_widget_signal_progress_info);
}
Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
browser_widget::signal_net_state()
{
    return Glib::SignalProxy3<void, const char *, gint, guint>(
	this, &browser_widget_signal_net_state_info);
}
Glib::SignalProxy0<void> browser_widget::signal_net_start()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_start_info);
}
Glib::SignalProxy0<void> browser_widget::signal_net_stop()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_stop_info);
}
Glib::SignalProxy1<browser_widget *, guint /*chromemask*/> browser_widget::signal_new_window()
{
    return Glib::SignalProxy1<browser_widget *, guint>(
	this, &browser_widget_signal_new_window_info);
}
Glib::SignalProxy1<void, bool /*visibility*/> browser_widget::signal_visibility()
{
    return Glib::SignalProxy1<void, bool>(
	this, &browser_widget_signal_visibility_info);
}
Glib::SignalProxy0<void> browser_widget::signal_destroy()
{
    return Glib::SignalProxy0<void>(this, &browser_widget_signal_destroy_info);
}
Glib::SignalProxy1<bool, const char * /*uri*/> browser_widget::signal_open_uri()
{
    return Glib::SignalProxy1<bool, const char *>(
	this, &browser_widget_signal_open_uri_info);
}

browser_widget::browser_widget(GObject * gobject, bool take_copy)
{
    assert(GTK_MOZ_EMBED(gobject));
    gobject_ = gobject;
    if (take_copy)
	reference();
}
Glib::ObjectBase * browser_widget::wrap_new(GObject * gobject)
{
    return new browser_widget(gobject, false);
}

browser_widget::initialiser::initialiser()
{
    gtk_moz_embed_set_comp_path(MOZ_LIB_DIR);
    gtk_moz_embed_push_startup();

    wrap_register(gtk_moz_embed_get_type(), wrap_new);
}

browser_widget::initialiser::~initialiser()
{
    gtk_moz_embed_pop_startup();
}

namespace Glib
{
    browser_widget * wrap(GtkMozEmbed * object, bool take_copy)
    {
	return dynamic_cast<browser_widget *>(
	    Glib::wrap_auto((GObject*)(object), take_copy));
    }
}
