/* This file is part of GQ
 *
 * AUTHORS
 *     Sven Herzberg  <herzi@gnome-de.org>
 *
 * Copyright (C) 2006  Sven Herzberg <herzi@gnome-de.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include "gq-server-dn.h"

#include <string.h>

#warning "FIXME: come up with a better name"

struct GqServerDnPrivate {
	GqServer* server;
	gchar   * dn;

	gchar   **object_class;
};
#define P(i) (G_TYPE_INSTANCE_GET_PRIVATE((i), GQ_TYPE_SERVER_DN, struct GqServerDnPrivate))

GqServerDn*
gq_server_dn_new(gchar const* d,
		 GqServer   * s)
{
#warning "FIXME: Use GObject properties"
	GqServerDn *dos = g_object_new(GQ_TYPE_SERVER_DN, NULL);

	P(dos)->dn     = g_strdup(d);
	P(dos)->server = g_object_ref(s);

	return dos;
}

gchar const*
gq_server_dn_get_dn(GqServerDn const* self)
{
	g_return_val_if_fail(GQ_IS_SERVER_DN(self), NULL);

	return P(self)->dn;
}

gchar * const *
gq_server_dn_get_object_class(GqServerDn* self)
{
	g_return_val_if_fail(GQ_IS_SERVER_DN(self), NULL);

	if(G_UNLIKELY(!P(self)->object_class)) {
		LDAPMessage* response,
			   * entry;
		gchar* attrs[] = {"objectClass", NULL};
		gint result;
		if(!gq_server_is_connected(P(self)->server)) {
			g_warning("FIXME: connect to server and queue this task");
			return NULL;
		}
		result = ldap_search_s(gq_server_get_connection(P(self)->server),
				       P(self)->dn, LDAP_SCOPE_BASE,
				       "objectClass=*", attrs,
				       FALSE /* attrs only */,
				       &response);

		switch(result)
		{
		case LDAP_SUCCESS:
			entry = ldap_first_entry(gq_server_get_connection(P(self)->server),
						 response);
			if(!entry) {
				g_warning("Got empty response");
				break;
			}
		       	else {
				BerElement *ber;
				gchar* attr = ldap_first_attribute(gq_server_get_connection(P(self)->server), entry, &ber);
				if(G_LIKELY(attr && !strcmp(attr, "objectClass"))) {
					gchar const* classname;
					struct berval **bervals = ldap_get_values_len(gq_server_get_connection(P(self)->server),
										      response,
										      attr);
					struct berval **it;
					GArray* array = g_array_new(TRUE, FALSE, sizeof(gchar*));
					for(it = bervals; it && *it; it++) {
						classname = g_strndup((*it)->bv_val, (*it)->bv_len);
						g_array_append_val(array, classname);
					}
					P(self)->object_class = (gchar**)array->data;
					g_array_free(array, FALSE);
					ldap_value_free_len(bervals);
				}
				else {
#warning "FIXME: not good"
				}
			}
			break;
		default:
#warning "FIXME: print a warning"
			break;
		}
	}

	return P(self)->object_class;
}

GqServer*
gq_server_dn_get_server(GqServerDn const* self)
{
	g_return_val_if_fail(GQ_IS_SERVER_DN(self), NULL);

	return P(self)->server;
}

/* GType */
G_DEFINE_TYPE(GqServerDn, gq_server_dn, G_TYPE_OBJECT);

static void
gq_server_dn_init(GqServerDn* self G_GNUC_UNUSED)
{}

static void
server_dn_dispose(GObject *object)
{
	GqServerDn* self = GQ_SERVER_DN(object);

	if(P(self)->server) {
		g_object_unref(P(self)->server);
		P(self)->server = NULL;
	}

	G_OBJECT_CLASS(gq_server_dn_parent_class)->dispose(object);
}

static void
server_dn_finalize(GObject* object)
{
	GqServerDn* self = GQ_SERVER_DN(object);

	g_free(P(self)->dn);
	P(self)->dn = NULL;

	g_strfreev(P(self)->object_class);
	P(self)->object_class = NULL;

	G_OBJECT_CLASS(gq_server_dn_parent_class)->finalize(object);
}

static void
gq_server_dn_class_init(GqServerDnClass* self_class)
{
	GObjectClass* object_class = G_OBJECT_CLASS(self_class);

	object_class->dispose  = server_dn_dispose;
	object_class->finalize = server_dn_finalize;

	g_type_class_add_private(self_class, sizeof(struct GqServerDnPrivate));
}

