static PHP_METHOD(midgard_object_class, get_object_by_guid)
{
	RETVAL_FALSE;
	MidgardConnection *mgd = mgd_handle(TSRMLS_C);
	CHECK_MGD(mgd);

	char *guid;
	int guid_length;
	const gchar *type_name;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &guid, &guid_length) == FAILURE)
		return;

	MidgardObject *object = midgard_schema_object_factory_get_object_by_guid(mgd, guid);

	if (!object) {
		php_midgard_error_exception_throw(mgd TSRMLS_CC);
		return;
	}

	type_name = G_OBJECT_TYPE_NAME(G_OBJECT(object));
	zend_class_entry *ce = zend_fetch_class((gchar *)type_name, strlen(type_name), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);

	if (ce == NULL) {
		php_error(E_WARNING, "Can not find %s class", type_name);
		return;
	}

	php_midgard_gobject_new_with_gobject(return_value, ce, G_OBJECT(object), TRUE TSRMLS_CC);
}
static PyObject *
pymidgard_schema_object_factory_get_object_by_guid (PyGObject *self, PyObject *args)
{
    gchar *guid;

    if (!PyArg_ParseTuple (args, "s", &guid))
        return NULL;

    MidgardConnection *mgd = _py_midgard_connection_singleton_get ();
    MidgardObject *mobject = midgard_schema_object_factory_get_object_by_guid (mgd, guid);

    if (mobject)
        return Py_BuildValue ("O", pygobject_new (G_OBJECT (mobject)));

    Py_RETURN_NONE;
}
gboolean _nodes2object(GObject *object, xmlNode *node, gboolean force)
{
	g_assert(object);
	g_assert(node);

	xmlNode *cur = NULL;
	GObject *prop_object;
	gchar *nodeprop = NULL;
	xmlChar *decoded;
	xmlParserCtxtPtr parser;
	MidgardObject *mobject = NULL;
	MidgardObject *lobject = NULL;
	MidgardReflectionProperty *mrp = NULL;
	const gchar *linktype = NULL;

	if(MIDGARD_IS_OBJECT(object)) {
		mobject = MIDGARD_OBJECT(object);
		MidgardObjectClass *klass =
			MIDGARD_OBJECT_GET_CLASS(mobject);
		if(klass)
			mrp = midgard_reflection_property_new(
					MIDGARD_DBOBJECT_CLASS(klass));
	}

	gpointer set_from_xml_func = MIDGARD_DBOBJECT_GET_CLASS(object)->dbpriv->set_from_xml_node;
	if(set_from_xml_func != NULL) {
		MIDGARD_DBOBJECT_GET_CLASS(object)->dbpriv->set_from_xml_node(MIDGARD_DBOBJECT(object), node);
		return TRUE;
	}

	for (cur = node; cur; cur = cur->next) {
		if (cur->type == XML_ELEMENT_NODE) {
		
			linktype = NULL;
	
			GParamSpec *pspec = g_object_class_find_property(
					G_OBJECT_GET_CLASS(G_OBJECT(object)), 
					(const gchar *)cur->name);
			if(pspec) {
				GValue pval = {0, };
				g_value_init(&pval, pspec->value_type);
				
				if(nodeprop)
					g_free(nodeprop);

				nodeprop = (gchar *)xmlNodeGetContent(cur);

				if(mrp) {
					if(midgard_reflection_property_is_link(
								mrp, pspec->name)){
						linktype =
							midgard_reflection_property_get_link_name(
									mrp, pspec->name);
					}
				}

				/* moved out from mrp condition check to avoid nested indents */

				if(linktype && midgard_is_guid(
							(const gchar *) nodeprop)){

					/* Just set property quickly, if property holds a guid */
					GType mtype = midgard_reflection_property_get_midgard_type(mrp, pspec->name);
					if (mtype == MGD_TYPE_GUID) {
						
						g_value_unset(&pval);
						g_object_set(mobject, (const gchar *)cur->name, nodeprop, NULL);
						continue;	
					}

					/* we can use nodeprop directly */
					lobject = midgard_schema_object_factory_get_object_by_guid (
							MIDGARD_DBOBJECT (mobject)->dbpriv->mgd,
							(const gchar *) nodeprop);

					if(!lobject && !force){
						g_object_unref(mrp);
						g_value_unset(&pval);
						midgard_set_error(MGD_OBJECT_CNC (mobject), 
								MGD_GENERIC_ERROR, 
								MGD_ERR_MISSED_DEPENDENCE, 
								" Can not import %s. "
								"No '%s' object identified by '%s'",
								G_OBJECT_TYPE_NAME(object),
								linktype, nodeprop); 
						g_clear_error(&MIDGARD_DBOBJECT (mobject)->dbpriv->mgd->err);	
						return FALSE;
					}
					
					/* When force parameter is set we do not translate guids to ids */
					if(force && !lobject && midgard_is_guid(
								(const gchar *) nodeprop)) {
						
						switch(pspec->value_type) {
							
							case G_TYPE_UINT:
								g_value_set_uint(&pval, 0);
								break;
							
							case G_TYPE_INT:
								g_value_set_int(&pval, 0);
								break;
							
							default:
								goto set_property_unchecked;
								break;
						}
						
						g_object_set_property(
								G_OBJECT(object),
								(const gchar *) cur->name,
								&pval);
						g_value_unset(&pval);
						continue;
					}

					GValue tval = {0, };
					g_value_init(&tval, pspec->value_type);

					g_object_get_property(G_OBJECT(lobject),
							"id", &tval);

					if(G_VALUE_TYPE(&pval) == G_TYPE_INT)
						g_value_transform((const GValue *) &tval,
								&pval);
					else
						g_value_copy((const GValue*) &tval,
								&pval);

					g_object_set_property(
							G_OBJECT(object),
							(const gchar *) cur->name,
							&pval);
					g_value_unset(&pval);
					g_object_unref(lobject);
					g_value_unset(&tval);
					continue;					
				}

				set_property_unchecked:
				switch (G_TYPE_FUNDAMENTAL (pspec->value_type)) {
				
					case G_TYPE_STRING:
						parser = xmlNewParserCtxt();
						decoded = 
							xmlStringDecodeEntities(parser,
									(const xmlChar *) nodeprop, 	
									XML_SUBSTITUTE_REF, 
									0, 0, 0);
						g_value_set_string(&pval, 
								(gchar *)decoded);
						g_free(decoded);
						xmlFreeParserCtxt(parser);
						break;

					case G_TYPE_INT:
						if(nodeprop) 
							g_value_set_int(&pval, 
									(gint)atoi((gchar *)nodeprop));
						break;

					case G_TYPE_UINT:
						if(nodeprop)
							g_value_set_uint(&pval,
									(guint)atoi((gchar *)nodeprop));
						break;

					case G_TYPE_FLOAT:
						g_value_set_float(&pval,
								(gfloat)atof((gchar *)nodeprop));
						break;

					case G_TYPE_BOOLEAN:
						g_value_set_boolean(&pval,
								(gboolean)atoi((gchar*)nodeprop));
						break;

					case G_TYPE_OBJECT:
						g_object_get(G_OBJECT(object),
								(const gchar *) cur->name,
								&prop_object, NULL);
						if (prop_object) {
							_nodes2object(prop_object, cur->children, force);	
							g_value_set_object(&pval, prop_object);
						} else {
							g_warning ("Failed to unserialize '%s' object property. Expected to be initialized by given '%s' instance", (const gchar *) cur->name, G_OBJECT_TYPE_NAME (object));
						}

						break;

					default:
						/* do nothing */
						break;						
				}
				g_object_set_property(
						G_OBJECT(object), 
						(const gchar *) cur->name, 
						&pval);
				g_value_unset(&pval);
			} else {
				g_warning("Undefined property '%s' for '%s'",
						cur->name, G_OBJECT_TYPE_NAME(object));
			}
		}		
	}

	if(nodeprop)
		g_free(nodeprop);

	if(mrp)
		g_object_unref(mrp);

	return TRUE;
}
/**
 * midgard_replicator_import_from_xml:
 * @mgd: #MidgardConnection instance
 * @xml: data buffer which holds serialized object
 * @force: toggle to force import
 *
 * This method tries to import all objects which could be unserialized from gievn xml.
 * It's not atomic. Check error code returned from midgard_connection_get_error().
 *
 */ 
void 
midgard_replicator_import_from_xml (MidgardConnection *mgd,  const gchar *xml, gboolean force)
{
	g_return_if_fail (mgd != NULL);
	g_return_if_fail (xml != NULL);
	
	xmlDoc *doc = NULL;
	xmlNode *root_node = NULL;
	midgard_core_object_get_xml_doc(mgd, xml, &doc, &root_node);
	
	if(doc == NULL || root_node == NULL)
		return;

	xmlNodePtr child = _get_type_node(root_node->children);
	if(!child) {
		g_warning("Can not get midgard type name from the given xml");
		xmlFreeDoc(doc);
		return;
	}

	GType object_type = g_type_from_name((const gchar *)child->name);
	
	if(object_type == MIDGARD_TYPE_BLOB) {
		/* it will destroy xmlDoc */
		__import_blob_from_xml(mgd, doc, child);
		return;
	}

	xmlChar *attr, *guid_attr;
	MidgardObject *dbobject;

	for(; child; child = _get_type_node(child->next)) {
		
		attr = xmlGetProp(child, BAD_CAST "purge");
		guid_attr = xmlGetProp(child, BAD_CAST "guid");

		if(attr && g_str_equal(attr, "yes")) {
			
			dbobject = midgard_schema_object_factory_get_object_by_guid (mgd, (const gchar *)guid_attr);

			if(dbobject || 
					( !dbobject && 
					 (mgd->errnum == MGD_ERR_OBJECT_DELETED)
					 )) {
		
				midgard_object_purge(dbobject, FALSE);
				if(dbobject)
					g_object_unref(dbobject);
				xmlFree(attr);
				xmlFree(guid_attr);
				continue;
			}
		}

		xmlFree(attr);

		MidgardObject *object =
			midgard_object_new(mgd, (const gchar *)child->name, NULL);
		if(!object) {
			g_warning("Can not create %s instance", child->name);
			xmlFreeDoc(doc);
			xmlFree(attr);
			xmlFree(guid_attr);
			continue;
		}

		if (guid_attr) {
			MGD_OBJECT_GUID (object) = (const gchar *)g_strdup((gchar *)guid_attr);
		}

		if(!_nodes2object(G_OBJECT(object), child->children, force)) {
			xmlFree(guid_attr);
			g_object_unref(object);
			continue;
		}			
		
		if (!midgard_replicator_import_object (MIDGARD_DBOBJECT (object), force)) {

			xmlFree (guid_attr);
			g_object_unref (object);
			continue;

		} else {

			xmlFree (guid_attr);
			g_object_unref (object);
		}
	}

	xmlFreeDoc (doc);
}
static gboolean __import_blob_from_xml(	MidgardConnection *mgd,
					xmlDoc *doc, 
					xmlNode *node)
{
	gchar *content;
	struct stat statbuf;
	const gchar *guid = (const gchar *)xmlGetProp(node, BAD_CAST "guid");

	if (!guid) {
		MIDGARD_ERRNO_SET(mgd, MGD_ERR_INTERNAL);
		g_warning("Object's guid is empty. Can not import blob file.");
		g_free((gchar *)guid);
		xmlFreeDoc(doc);
		return FALSE;
	}

	if (!midgard_is_guid((const gchar *)guid)) {
		MIDGARD_ERRNO_SET(mgd, MGD_ERR_INTERNAL);
		g_warning("'%s' is not a valid guid", guid);
		g_free((gchar *)guid);
		xmlFreeDoc(doc);
		return FALSE;
	}

	MidgardObject *object = midgard_schema_object_factory_get_object_by_guid (mgd, guid);

	/* TODO , Add more error messages to inform about object state. 
	 * One is already set by midgard_object_class_get_object_by_guid */
	if (!object) {
		g_free((gchar *)guid);
		xmlFreeDoc(doc);
		return FALSE;
	}

	/* FIXME, define even macro to get blobdir ( core level only ) */
	gchar *blobdir = MIDGARD_DBOBJECT (object)->dbpriv->mgd->priv->config->blobdir;

	if (!blobdir || (*blobdir != '/')
			|| (stat(blobdir, &statbuf) != 0)
			|| !S_ISDIR(statbuf.st_mode)) {
		g_warning("Blobs directory is not set");
		g_free((gchar *)guid);
		xmlFreeDoc(doc);
		return FALSE;
	}

	gchar *location;
	gchar *blobpath = NULL;
	g_object_get(G_OBJECT(object), "location", &location, NULL);
	if (strlen(location) > 1) {
		blobpath = g_strconcat(blobdir, "/", location, NULL);
	}

	/* TODO, Find the way to get content and not its copy */
	/* node->content doesn't seem to hold it */
	content = (gchar *)xmlNodeGetContent(node);

	gsize content_length = (gsize) strlen(content);
	guchar *decoded = g_base64_decode(content, &content_length);
	g_free(content);

	FILE *fp = fopen(blobpath, "w+");
	if (NULL != fp) {
		g_free(decoded);
		g_free((gchar *)guid);
		xmlFreeDoc(doc);
		return FALSE;
	}
	size_t res_length = fwrite(decoded, sizeof(char), content_length, fp);
	fclose(fp);

	g_free(decoded);
	g_free((gchar *)guid);
	xmlFreeDoc(doc);

	if (res_length < content_length) {
		return FALSE;
	}

	return TRUE;
}
static PHP_METHOD(midgard_object_class, factory)
{
	MidgardConnection *mgd = mgd_handle(TSRMLS_C);
	CHECK_MGD(mgd);

	char *class_name;
	int class_name_length;
	zval *zvalue = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &class_name, &class_name_length, &zvalue) == FAILURE)
		return;

	zend_class_entry **pce = NULL;
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3
	if (zend_lookup_class_ex(class_name, class_name_length, NULL, 1, &pce TSRMLS_CC) == FAILURE) {
#else
	if (zend_lookup_class_ex(class_name, class_name_length, 1, &pce TSRMLS_CC) == FAILURE) {
#endif
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not find %s class", class_name);
		return;
	}

	zend_class_entry *ce = *pce;

	object_init_ex(return_value, ce); /* Initialize new object for which QB has been created for */

	/* Call class constructor on given instance */
	if (zvalue == NULL) {
		zend_call_method_with_0_params(&return_value, ce, &ce->constructor, "__construct", NULL);
	} else {
		zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, zvalue);
	}
}

ZEND_BEGIN_ARG_INFO_EX(arginfo_midgard_object_class_factory, 0, 0, 1)
	ZEND_ARG_INFO(0, classname)
	ZEND_ARG_INFO(0, id)
ZEND_END_ARG_INFO()

static PHP_METHOD(midgard_object_class, get_object_by_guid)
{
	RETVAL_FALSE;
	MidgardConnection *mgd = mgd_handle(TSRMLS_C);
	CHECK_MGD(mgd);

	char *guid;
	int guid_length;
	const gchar *type_name;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &guid, &guid_length) == FAILURE)
		return;

	MidgardObject *object = midgard_schema_object_factory_get_object_by_guid(mgd, guid);

	if (!object) {
		php_midgard_error_exception_throw(mgd TSRMLS_CC);
		return;
	}

	type_name = G_OBJECT_TYPE_NAME(G_OBJECT(object));
	zend_class_entry *ce = zend_fetch_class((gchar *)type_name, strlen(type_name), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);

	if (ce == NULL) {
		php_error(E_WARNING, "Can not find %s class", type_name);
		return;
	}

	php_midgard_gobject_new_with_gobject(return_value, ce, G_OBJECT(object), TRUE TSRMLS_CC);
}