/* tag.c generated by valac 0.24.0, the Vala compiler
 * generated from tag.vala, do not modify */

/* 
 * SmartSim - Digital Logic Circuit Designer and Simulator
 *   
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *   
 *   This program 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, see <http://www.gnu.org/licenses/>.
 *   
 *   Filename: tag.vala
 *   
 *   Copyright Ashley Newson 2013
 */

#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include <float.h>
#include <math.h>
#include <gobject/gvaluecollector.h>


#define TYPE_TAG (tag_get_type ())
#define TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TAG, Tag))
#define TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TAG, TagClass))
#define IS_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TAG))
#define IS_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TAG))
#define TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TAG, TagClass))

typedef struct _Tag Tag;
typedef struct _TagClass TagClass;
typedef struct _TagPrivate TagPrivate;

#define TYPE_FLOW (flow_get_type ())

#define TYPE_DIRECTION (direction_get_type ())
#define _g_free0(var) (var = (g_free (var), NULL))
#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL)))
#define _cairo_surface_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_surface_destroy (var), NULL)))
typedef struct _ParamSpecTag ParamSpecTag;

typedef enum  {
	FLOW_NONE,
	FLOW_IN,
	FLOW_OUT,
	FLOW_BIDIRECTIONAL
} Flow;

typedef enum  {
	DIRECTION_NONE,
	DIRECTION_RIGHT,
	DIRECTION_DOWN,
	DIRECTION_LEFT,
	DIRECTION_UP,
	DIRECTION_HORIZONTAL,
	DIRECTION_VERTICAL,
	DIRECTION_DIAGONAL
} Direction;

struct _Tag {
	GTypeInstance parent_instance;
	volatile int ref_count;
	TagPrivate * priv;
	gchar* text;
	gint xTag;
	gint yTag;
	gint xWire;
	gint yWire;
	gint pinid;
	Flow flow;
	Direction direction;
	gint rightBound;
	gint downBound;
	gint leftBound;
	gint upBound;
};

struct _TagClass {
	GTypeClass parent_class;
	void (*finalize) (Tag *self);
};

struct _ParamSpecTag {
	GParamSpec parent_instance;
};


static gpointer tag_parent_class = NULL;

gpointer tag_ref (gpointer instance);
void tag_unref (gpointer instance);
GParamSpec* param_spec_tag (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags);
void value_set_tag (GValue* value, gpointer v_object);
void value_take_tag (GValue* value, gpointer v_object);
gpointer value_get_tag (const GValue* value);
GType tag_get_type (void) G_GNUC_CONST;
GType flow_get_type (void) G_GNUC_CONST;
GType direction_get_type (void) G_GNUC_CONST;
enum  {
	TAG_DUMMY_PROPERTY
};
Tag* tag_new (gint xWire, gint yWire, gint xTag, gint yTag);
Tag* tag_construct (GType object_type, gint xWire, gint yWire, gint xTag, gint yTag);
void tag_calculate_bounds (Tag* self);
void tag_render (Tag* self, cairo_t* context);
static void tag_finalize (Tag* obj);


/**
 * Creates a new Tag, which joins at (//xWire//, //yWire//), and goes
 * to (//xTag//, //yTag//).
 */
Tag* tag_construct (GType object_type, gint xWire, gint yWire, gint xTag, gint yTag) {
	Tag* self = NULL;
	gint xDiff = 0;
	gint _tmp0_ = 0;
	gint _tmp1_ = 0;
	gint yDiff = 0;
	gint _tmp2_ = 0;
	gint _tmp3_ = 0;
	gint _tmp4_ = 0;
	gint _tmp5_ = 0;
	gint xDiffAbs = 0;
	gint _tmp8_ = 0;
	gint _tmp9_ = 0;
	gint yDiffAbs = 0;
	gint _tmp12_ = 0;
	gint _tmp13_ = 0;
	gint _tmp14_ = 0;
	gint _tmp15_ = 0;
	gint _tmp16_ = 0;
	gint _tmp17_ = 0;
	self = (Tag*) g_type_create_instance (object_type);
	_tmp0_ = xTag;
	_tmp1_ = xWire;
	xDiff = _tmp0_ - _tmp1_;
	_tmp2_ = yTag;
	_tmp3_ = yWire;
	yDiff = _tmp2_ - _tmp3_;
	_tmp5_ = xDiff;
	if (_tmp5_ > 0) {
		gint _tmp6_ = 0;
		_tmp6_ = xDiff;
		_tmp4_ = _tmp6_;
	} else {
		gint _tmp7_ = 0;
		_tmp7_ = xDiff;
		_tmp4_ = -_tmp7_;
	}
	xDiffAbs = _tmp4_;
	_tmp9_ = yDiff;
	if (_tmp9_ > 0) {
		gint _tmp10_ = 0;
		_tmp10_ = yDiff;
		_tmp8_ = _tmp10_;
	} else {
		gint _tmp11_ = 0;
		_tmp11_ = yDiff;
		_tmp8_ = -_tmp11_;
	}
	yDiffAbs = _tmp8_;
	_tmp12_ = xTag;
	self->xTag = _tmp12_;
	_tmp13_ = yTag;
	self->yTag = _tmp13_;
	_tmp14_ = xWire;
	self->xWire = _tmp14_;
	_tmp15_ = yWire;
	self->yWire = _tmp15_;
	_tmp16_ = xDiffAbs;
	_tmp17_ = yDiffAbs;
	if (_tmp16_ > _tmp17_) {
		gint _tmp18_ = 0;
		_tmp18_ = xDiff;
		if (_tmp18_ > 0) {
			self->direction = DIRECTION_RIGHT;
		} else {
			self->direction = DIRECTION_LEFT;
		}
	} else {
		gint _tmp19_ = 0;
		_tmp19_ = yDiff;
		if (_tmp19_ > 0) {
			self->direction = DIRECTION_DOWN;
		} else {
			self->direction = DIRECTION_UP;
		}
	}
	tag_calculate_bounds (self);
	return self;
}


Tag* tag_new (gint xWire, gint yWire, gint xTag, gint yTag) {
	return tag_construct (TYPE_TAG, xWire, yWire, xTag, yTag);
}


void tag_calculate_bounds (Tag* self) {
	gint tagWidth = 0;
	cairo_text_extents_t textExtents = {0};
	cairo_surface_t* imageSurface = NULL;
	cairo_surface_t* _tmp0_ = NULL;
	cairo_t* context = NULL;
	cairo_surface_t* _tmp1_ = NULL;
	cairo_t* _tmp2_ = NULL;
	cairo_t* _tmp3_ = NULL;
	cairo_t* _tmp4_ = NULL;
	const gchar* _tmp5_ = NULL;
	cairo_text_extents_t _tmp6_ = {0};
	cairo_text_extents_t _tmp7_ = {0};
	gdouble _tmp8_ = 0.0;
	gint _tmp9_ = 0;
	Flow _tmp10_ = 0;
	Direction _tmp13_ = 0;
	g_return_if_fail (self != NULL);
	_tmp0_ = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
	imageSurface = _tmp0_;
	_tmp1_ = imageSurface;
	_tmp2_ = cairo_create (_tmp1_);
	context = _tmp2_;
	_tmp3_ = context;
	cairo_set_font_size (_tmp3_, (gdouble) 12);
	_tmp4_ = context;
	_tmp5_ = self->text;
	cairo_text_extents (_tmp4_, _tmp5_, &_tmp6_);
	textExtents = _tmp6_;
	_tmp7_ = textExtents;
	_tmp8_ = _tmp7_.width;
	tagWidth = ((gint) _tmp8_) + 2;
	_tmp9_ = tagWidth;
	if (_tmp9_ < 50) {
		tagWidth = 50;
	}
	_tmp10_ = self->flow;
	if (_tmp10_ == FLOW_BIDIRECTIONAL) {
		gint _tmp11_ = 0;
		_tmp11_ = tagWidth;
		tagWidth = _tmp11_ + 20;
	} else {
		gint _tmp12_ = 0;
		_tmp12_ = tagWidth;
		tagWidth = _tmp12_ + 10;
	}
	_tmp13_ = self->direction;
	switch (_tmp13_) {
		case DIRECTION_RIGHT:
		{
			gint _tmp14_ = 0;
			gint _tmp15_ = 0;
			gint _tmp16_ = 0;
			gint _tmp17_ = 0;
			gint _tmp18_ = 0;
			_tmp14_ = self->xTag;
			_tmp15_ = tagWidth;
			self->rightBound = _tmp14_ + _tmp15_;
			_tmp16_ = self->yTag;
			self->downBound = _tmp16_ + 10;
			_tmp17_ = self->xWire;
			self->leftBound = _tmp17_;
			_tmp18_ = self->yTag;
			self->upBound = _tmp18_ - 10;
			break;
		}
		case DIRECTION_DOWN:
		{
			gint _tmp19_ = 0;
			gint _tmp20_ = 0;
			gint _tmp21_ = 0;
			gint _tmp22_ = 0;
			gint _tmp23_ = 0;
			_tmp19_ = self->xTag;
			self->rightBound = _tmp19_ + 10;
			_tmp20_ = self->yTag;
			_tmp21_ = tagWidth;
			self->downBound = _tmp20_ + _tmp21_;
			_tmp22_ = self->xTag;
			self->leftBound = _tmp22_ - 10;
			_tmp23_ = self->yWire;
			self->upBound = _tmp23_;
			break;
		}
		case DIRECTION_LEFT:
		{
			gint _tmp24_ = 0;
			gint _tmp25_ = 0;
			gint _tmp26_ = 0;
			gint _tmp27_ = 0;
			gint _tmp28_ = 0;
			_tmp24_ = self->xWire;
			self->rightBound = _tmp24_;
			_tmp25_ = self->yTag;
			self->downBound = _tmp25_ + 10;
			_tmp26_ = self->xTag;
			_tmp27_ = tagWidth;
			self->leftBound = _tmp26_ - _tmp27_;
			_tmp28_ = self->yTag;
			self->upBound = _tmp28_ - 10;
			break;
		}
		case DIRECTION_UP:
		{
			gint _tmp29_ = 0;
			gint _tmp30_ = 0;
			gint _tmp31_ = 0;
			gint _tmp32_ = 0;
			gint _tmp33_ = 0;
			_tmp29_ = self->xTag;
			self->rightBound = _tmp29_ + 10;
			_tmp30_ = self->yWire;
			self->downBound = _tmp30_;
			_tmp31_ = self->xTag;
			self->leftBound = _tmp31_ - 10;
			_tmp32_ = self->yTag;
			_tmp33_ = tagWidth;
			self->upBound = _tmp32_ - _tmp33_;
			break;
		}
		default:
		break;
	}
	_cairo_destroy0 (context);
	_cairo_surface_destroy0 (imageSurface);
}


/**
 * Renders the tag.
 */
void tag_render (Tag* self, cairo_t* context) {
	cairo_t* _tmp0_ = NULL;
	gint _tmp1_ = 0;
	gint _tmp2_ = 0;
	cairo_t* _tmp3_ = NULL;
	gint _tmp4_ = 0;
	gint _tmp5_ = 0;
	cairo_t* _tmp6_ = NULL;
	cairo_matrix_t oldMatrix = {0};
	cairo_t* _tmp7_ = NULL;
	cairo_matrix_t _tmp8_ = {0};
	cairo_t* _tmp9_ = NULL;
	gint _tmp10_ = 0;
	gint _tmp11_ = 0;
	gdouble angle = 0.0;
	Direction _tmp12_ = 0;
	cairo_t* _tmp13_ = NULL;
	gdouble _tmp14_ = 0.0;
	cairo_text_extents_t textExtents = {0};
	cairo_t* _tmp15_ = NULL;
	cairo_t* _tmp16_ = NULL;
	const gchar* _tmp17_ = NULL;
	cairo_text_extents_t _tmp18_ = {0};
	gdouble tagWidth = 0.0;
	cairo_text_extents_t _tmp19_ = {0};
	gdouble _tmp20_ = 0.0;
	gdouble _tmp21_ = 0.0;
	Flow _tmp22_ = 0;
	cairo_t* _tmp86_ = NULL;
	cairo_matrix_t _tmp87_ = {0};
	g_return_if_fail (self != NULL);
	g_return_if_fail (context != NULL);
	_tmp0_ = context;
	_tmp1_ = self->xWire;
	_tmp2_ = self->yWire;
	cairo_move_to (_tmp0_, (gdouble) _tmp1_, (gdouble) _tmp2_);
	_tmp3_ = context;
	_tmp4_ = self->xTag;
	_tmp5_ = self->yTag;
	cairo_line_to (_tmp3_, (gdouble) _tmp4_, (gdouble) _tmp5_);
	_tmp6_ = context;
	cairo_stroke (_tmp6_);
	_tmp7_ = context;
	cairo_get_matrix (_tmp7_, &_tmp8_);
	oldMatrix = _tmp8_;
	_tmp9_ = context;
	_tmp10_ = self->xTag;
	_tmp11_ = self->yTag;
	cairo_translate (_tmp9_, (gdouble) _tmp10_, (gdouble) _tmp11_);
	angle = (gdouble) 0;
	_tmp12_ = self->direction;
	switch (_tmp12_) {
		case DIRECTION_RIGHT:
		{
			angle = (gdouble) 0;
			break;
		}
		case DIRECTION_DOWN:
		{
			angle = G_PI * 0.5;
			break;
		}
		case DIRECTION_LEFT:
		{
			angle = G_PI;
			break;
		}
		case DIRECTION_UP:
		{
			angle = G_PI * 1.5;
			break;
		}
		default:
		break;
	}
	_tmp13_ = context;
	_tmp14_ = angle;
	cairo_rotate (_tmp13_, _tmp14_);
	_tmp15_ = context;
	cairo_set_font_size (_tmp15_, (gdouble) 12);
	_tmp16_ = context;
	_tmp17_ = self->text;
	cairo_text_extents (_tmp16_, _tmp17_, &_tmp18_);
	textExtents = _tmp18_;
	_tmp19_ = textExtents;
	_tmp20_ = _tmp19_.width;
	tagWidth = _tmp20_ + 2;
	_tmp21_ = tagWidth;
	if (_tmp21_ < ((gdouble) 50)) {
		tagWidth = (gdouble) 50;
	}
	_tmp22_ = self->flow;
	switch (_tmp22_) {
		case FLOW_IN:
		{
			cairo_t* _tmp23_ = NULL;
			gdouble _tmp24_ = 0.0;
			cairo_t* _tmp25_ = NULL;
			gdouble _tmp26_ = 0.0;
			cairo_t* _tmp27_ = NULL;
			cairo_t* _tmp28_ = NULL;
			cairo_t* _tmp29_ = NULL;
			cairo_t* _tmp30_ = NULL;
			cairo_t* _tmp31_ = NULL;
			Direction _tmp32_ = 0;
			cairo_t* _tmp41_ = NULL;
			const gchar* _tmp42_ = NULL;
			_tmp23_ = context;
			_tmp24_ = tagWidth;
			cairo_move_to (_tmp23_, _tmp24_ + 10, (gdouble) (-10));
			_tmp25_ = context;
			_tmp26_ = tagWidth;
			cairo_line_to (_tmp25_, _tmp26_ + 10, (gdouble) 10);
			_tmp27_ = context;
			cairo_line_to (_tmp27_, (gdouble) 10, (gdouble) 10);
			_tmp28_ = context;
			cairo_line_to (_tmp28_, (gdouble) 0, (gdouble) 0);
			_tmp29_ = context;
			cairo_line_to (_tmp29_, (gdouble) 10, (gdouble) (-10));
			_tmp30_ = context;
			cairo_close_path (_tmp30_);
			_tmp31_ = context;
			cairo_stroke (_tmp31_);
			_tmp32_ = self->direction;
			if (_tmp32_ == DIRECTION_LEFT) {
				cairo_t* _tmp33_ = NULL;
				cairo_t* _tmp34_ = NULL;
				gdouble _tmp35_ = 0.0;
				cairo_text_extents_t _tmp36_ = {0};
				gdouble _tmp37_ = 0.0;
				_tmp33_ = context;
				cairo_rotate (_tmp33_, G_PI);
				_tmp34_ = context;
				_tmp35_ = tagWidth;
				_tmp36_ = textExtents;
				_tmp37_ = _tmp36_.height;
				cairo_move_to (_tmp34_, (-8) - _tmp35_, _tmp37_ / 2);
			} else {
				cairo_t* _tmp38_ = NULL;
				cairo_text_extents_t _tmp39_ = {0};
				gdouble _tmp40_ = 0.0;
				_tmp38_ = context;
				_tmp39_ = textExtents;
				_tmp40_ = _tmp39_.height;
				cairo_move_to (_tmp38_, (gdouble) 10, _tmp40_ / 2);
			}
			_tmp41_ = context;
			_tmp42_ = self->text;
			cairo_show_text (_tmp41_, _tmp42_);
			break;
		}
		case FLOW_OUT:
		{
			cairo_t* _tmp43_ = NULL;
			cairo_t* _tmp44_ = NULL;
			cairo_t* _tmp45_ = NULL;
			gdouble _tmp46_ = 0.0;
			cairo_t* _tmp47_ = NULL;
			gdouble _tmp48_ = 0.0;
			cairo_t* _tmp49_ = NULL;
			gdouble _tmp50_ = 0.0;
			cairo_t* _tmp51_ = NULL;
			cairo_t* _tmp52_ = NULL;
			Direction _tmp53_ = 0;
			cairo_t* _tmp62_ = NULL;
			const gchar* _tmp63_ = NULL;
			_tmp43_ = context;
			cairo_move_to (_tmp43_, (gdouble) 0, (gdouble) (-10));
			_tmp44_ = context;
			cairo_line_to (_tmp44_, (gdouble) 0, (gdouble) 10);
			_tmp45_ = context;
			_tmp46_ = tagWidth;
			cairo_line_to (_tmp45_, _tmp46_, (gdouble) 10);
			_tmp47_ = context;
			_tmp48_ = tagWidth;
			cairo_line_to (_tmp47_, _tmp48_ + 10, (gdouble) 0);
			_tmp49_ = context;
			_tmp50_ = tagWidth;
			cairo_line_to (_tmp49_, _tmp50_, (gdouble) (-10));
			_tmp51_ = context;
			cairo_close_path (_tmp51_);
			_tmp52_ = context;
			cairo_stroke (_tmp52_);
			_tmp53_ = self->direction;
			if (_tmp53_ == DIRECTION_LEFT) {
				cairo_t* _tmp54_ = NULL;
				cairo_t* _tmp55_ = NULL;
				gdouble _tmp56_ = 0.0;
				cairo_text_extents_t _tmp57_ = {0};
				gdouble _tmp58_ = 0.0;
				_tmp54_ = context;
				cairo_rotate (_tmp54_, G_PI);
				_tmp55_ = context;
				_tmp56_ = tagWidth;
				_tmp57_ = textExtents;
				_tmp58_ = _tmp57_.height;
				cairo_move_to (_tmp55_, -_tmp56_, _tmp58_ / 2);
			} else {
				cairo_t* _tmp59_ = NULL;
				cairo_text_extents_t _tmp60_ = {0};
				gdouble _tmp61_ = 0.0;
				_tmp59_ = context;
				_tmp60_ = textExtents;
				_tmp61_ = _tmp60_.height;
				cairo_move_to (_tmp59_, (gdouble) 2, _tmp61_ / 2);
			}
			_tmp62_ = context;
			_tmp63_ = self->text;
			cairo_show_text (_tmp62_, _tmp63_);
			break;
		}
		case FLOW_BIDIRECTIONAL:
		{
			cairo_t* _tmp64_ = NULL;
			cairo_t* _tmp65_ = NULL;
			cairo_t* _tmp66_ = NULL;
			gdouble _tmp67_ = 0.0;
			cairo_t* _tmp68_ = NULL;
			gdouble _tmp69_ = 0.0;
			cairo_t* _tmp70_ = NULL;
			gdouble _tmp71_ = 0.0;
			cairo_t* _tmp72_ = NULL;
			cairo_t* _tmp73_ = NULL;
			cairo_t* _tmp74_ = NULL;
			Direction _tmp75_ = 0;
			cairo_t* _tmp84_ = NULL;
			const gchar* _tmp85_ = NULL;
			_tmp64_ = context;
			cairo_move_to (_tmp64_, (gdouble) 0, (gdouble) 0);
			_tmp65_ = context;
			cairo_line_to (_tmp65_, (gdouble) 10, (gdouble) 10);
			_tmp66_ = context;
			_tmp67_ = tagWidth;
			cairo_line_to (_tmp66_, _tmp67_ + 10, (gdouble) 10);
			_tmp68_ = context;
			_tmp69_ = tagWidth;
			cairo_line_to (_tmp68_, _tmp69_ + 20, (gdouble) 0);
			_tmp70_ = context;
			_tmp71_ = tagWidth;
			cairo_line_to (_tmp70_, _tmp71_ + 10, (gdouble) (-10));
			_tmp72_ = context;
			cairo_line_to (_tmp72_, (gdouble) 10, (gdouble) (-10));
			_tmp73_ = context;
			cairo_close_path (_tmp73_);
			_tmp74_ = context;
			cairo_stroke (_tmp74_);
			_tmp75_ = self->direction;
			if (_tmp75_ == DIRECTION_LEFT) {
				cairo_t* _tmp76_ = NULL;
				cairo_t* _tmp77_ = NULL;
				gdouble _tmp78_ = 0.0;
				cairo_text_extents_t _tmp79_ = {0};
				gdouble _tmp80_ = 0.0;
				_tmp76_ = context;
				cairo_rotate (_tmp76_, G_PI);
				_tmp77_ = context;
				_tmp78_ = tagWidth;
				_tmp79_ = textExtents;
				_tmp80_ = _tmp79_.height;
				cairo_move_to (_tmp77_, (-8) - _tmp78_, _tmp80_ / 2);
			} else {
				cairo_t* _tmp81_ = NULL;
				cairo_text_extents_t _tmp82_ = {0};
				gdouble _tmp83_ = 0.0;
				_tmp81_ = context;
				_tmp82_ = textExtents;
				_tmp83_ = _tmp82_.height;
				cairo_move_to (_tmp81_, (gdouble) 10, _tmp83_ / 2);
			}
			_tmp84_ = context;
			_tmp85_ = self->text;
			cairo_show_text (_tmp84_, _tmp85_);
			break;
		}
		default:
		break;
	}
	_tmp86_ = context;
	_tmp87_ = oldMatrix;
	cairo_set_matrix (_tmp86_, &_tmp87_);
}


static void value_tag_init (GValue* value) {
	value->data[0].v_pointer = NULL;
}


static void value_tag_free_value (GValue* value) {
	if (value->data[0].v_pointer) {
		tag_unref (value->data[0].v_pointer);
	}
}


static void value_tag_copy_value (const GValue* src_value, GValue* dest_value) {
	if (src_value->data[0].v_pointer) {
		dest_value->data[0].v_pointer = tag_ref (src_value->data[0].v_pointer);
	} else {
		dest_value->data[0].v_pointer = NULL;
	}
}


static gpointer value_tag_peek_pointer (const GValue* value) {
	return value->data[0].v_pointer;
}


static gchar* value_tag_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
	if (collect_values[0].v_pointer) {
		Tag* object;
		object = collect_values[0].v_pointer;
		if (object->parent_instance.g_class == NULL) {
			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		}
		value->data[0].v_pointer = tag_ref (object);
	} else {
		value->data[0].v_pointer = NULL;
	}
	return NULL;
}


static gchar* value_tag_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
	Tag** object_p;
	object_p = collect_values[0].v_pointer;
	if (!object_p) {
		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
	}
	if (!value->data[0].v_pointer) {
		*object_p = NULL;
	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
		*object_p = value->data[0].v_pointer;
	} else {
		*object_p = tag_ref (value->data[0].v_pointer);
	}
	return NULL;
}


GParamSpec* param_spec_tag (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) {
	ParamSpecTag* spec;
	g_return_val_if_fail (g_type_is_a (object_type, TYPE_TAG), NULL);
	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
	G_PARAM_SPEC (spec)->value_type = object_type;
	return G_PARAM_SPEC (spec);
}


gpointer value_get_tag (const GValue* value) {
	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG), NULL);
	return value->data[0].v_pointer;
}


void value_set_tag (GValue* value, gpointer v_object) {
	Tag* old;
	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG));
	old = value->data[0].v_pointer;
	if (v_object) {
		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_TAG));
		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
		value->data[0].v_pointer = v_object;
		tag_ref (value->data[0].v_pointer);
	} else {
		value->data[0].v_pointer = NULL;
	}
	if (old) {
		tag_unref (old);
	}
}


void value_take_tag (GValue* value, gpointer v_object) {
	Tag* old;
	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG));
	old = value->data[0].v_pointer;
	if (v_object) {
		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_TAG));
		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
		value->data[0].v_pointer = v_object;
	} else {
		value->data[0].v_pointer = NULL;
	}
	if (old) {
		tag_unref (old);
	}
}


static void tag_class_init (TagClass * klass) {
	tag_parent_class = g_type_class_peek_parent (klass);
	TAG_CLASS (klass)->finalize = tag_finalize;
}


static void tag_instance_init (Tag * self) {
	self->ref_count = 1;
}


static void tag_finalize (Tag* obj) {
	Tag * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_TAG, Tag);
	_g_free0 (self->text);
}


/**
 * Used to define an interface with a higher-level of the hierarchy.
 */
GType tag_get_type (void) {
	static volatile gsize tag_type_id__volatile = 0;
	if (g_once_init_enter (&tag_type_id__volatile)) {
		static const GTypeValueTable g_define_type_value_table = { value_tag_init, value_tag_free_value, value_tag_copy_value, value_tag_peek_pointer, "p", value_tag_collect_value, "p", value_tag_lcopy_value };
		static const GTypeInfo g_define_type_info = { sizeof (TagClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) tag_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Tag), 0, (GInstanceInitFunc) tag_instance_init, &g_define_type_value_table };
		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
		GType tag_type_id;
		tag_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Tag", &g_define_type_info, &g_define_type_fundamental_info, 0);
		g_once_init_leave (&tag_type_id__volatile, tag_type_id);
	}
	return tag_type_id__volatile;
}


gpointer tag_ref (gpointer instance) {
	Tag* self;
	self = instance;
	g_atomic_int_inc (&self->ref_count);
	return instance;
}


void tag_unref (gpointer instance) {
	Tag* self;
	self = instance;
	if (g_atomic_int_dec_and_test (&self->ref_count)) {
		TAG_GET_CLASS (self)->finalize (self);
		g_type_free_instance ((GTypeInstance *) self);
	}
}



