#include "ldap_plugin.h"

/*open xml file check it an return pointer to first entry*/
int open_xml_file(ldap_connection *conn, xmlDocPtr *doc, xmlNodePtr *cur, char *file, char *topentry)
{
	*doc = xmlParseFile(file);

	if (!*doc) {
		ldap_debug(conn, 1, "Could not open: %s", file);
		return 1;
	}

	*cur = xmlDocGetRootElement(*doc);

	if (!*cur) {
		ldap_debug(conn, 0, "%s seems to be empty", file);
		xmlFreeDoc(*doc);
		return 1;
	}

	if (xmlStrcmp((*cur)->name, (const xmlChar *) topentry)) {
		ldap_debug(conn, 0, "%s seems not to be a valid configfile.\n", file);
		xmlFreeDoc(*doc);
		return 1;
	}

	*cur = (*cur)->xmlChildrenNode;
	return 0;
}

/*Load the state from a xml file and return it in the conn struct*/
int load_ldap_state(ldap_connection *conn)
{
	xmlDocPtr doc;
	xmlNodePtr cur;
	char *xmlstr;
	ldap_debug(conn, 2, "Loading state from file %s", conn->statefile);

	//set defaults
	conn->servername = "";
	conn->serverport = 389;
	conn->binddn = "";
	conn->pwd = "";
	conn->filter = "(cn=*)";
	conn->searchbase = "";
	conn->scope = 0;
	conn->debug_level = 0;
	conn->authmech = "SIMPLE";
	conn->encryption = 1;
	conn->anonymous = 0;
	conn->ldap_version = LDAP_VERSION3;

	if (open_xml_file(conn, &doc, &cur, conn->statefile, "config")) {
		return 1;
	}

	while (cur != NULL) {
		xmlstr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"serverport"))) {
			conn->serverport = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"scope"))) {
			conn->scope = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"encryption"))) {
			conn->encryption = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"write"))) {
			conn->write = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"anonymous"))) {
			conn->anonymous = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"debuglevel"))) {
			conn->debug_level = atoi(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"filter"))) {
			if (xmlstr) {
				conn->filter = g_strdup(xmlstr);
			} else {
				conn->filter = g_strdup("");
			}
		}

		if (!xmlstr) {
			cur = cur->next;
			continue;
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"servername"))) {
			conn->servername = g_strdup(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"binddn"))) {
			conn->binddn = g_strdup(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"pwd"))) {
			conn->pwd = g_strdup(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"searchbase"))) {
			conn->searchbase = g_strdup(xmlstr);
		}

		if ((!xmlStrcmp(cur->name, (const xmlChar *)"authmech"))) {
			conn->authmech = g_strdup(xmlstr);
		}

		free(xmlstr);
		cur = cur->next;
	}

	xmlFreeDoc(doc);
	ldap_debug(conn, 3, "end: load_ldap_state");
	return 0;
}

/*Save the state from the conn struct to a xmlfile*/
void save_ldap_state(ldap_connection *conn)
{
	xmlDocPtr doc;
	char port[256], debuglevel[256], scope[256], encryption[256], write[256], anonymous[256];
	ldap_debug(conn, 2, "Saving state to file %s", conn->statefile);

	doc = xmlNewDoc("1.0");
	doc->children = xmlNewDocNode(doc, NULL, "config", NULL);

	snprintf(port, 256, "%i", conn->serverport);
	snprintf(debuglevel, 256, "%i", conn->debug_level);
	snprintf(scope, 256, "%i", conn->scope);
	snprintf(encryption, 256, "%i", conn->encryption);
	snprintf(write, 256, "%i", conn->write);
	snprintf(anonymous, 256, "%i", conn->anonymous);

	xmlNewChild(doc->children, NULL, "servername", conn->servername);
	xmlNewChild(doc->children, NULL, "serverport", port);
	xmlNewChild(doc->children, NULL, "binddn", conn->binddn);
	xmlNewChild(doc->children, NULL, "pwd", conn->pwd);
	xmlNewChild(doc->children, NULL, "searchbase", conn->searchbase);
	xmlNewChild(doc->children, NULL, "filter", conn->filter);
	xmlNewChild(doc->children, NULL, "scope", scope);
	xmlNewChild(doc->children, NULL, "debuglevel", debuglevel);
	xmlNewChild(doc->children, NULL, "authmech", conn->authmech);
	xmlNewChild(doc->children, NULL, "encryption", encryption);
	xmlNewChild(doc->children, NULL, "write", write);
	xmlNewChild(doc->children, NULL, "anonymous", anonymous);

	xmlSaveFile(conn->statefile, doc);
	xmlFreeDoc(doc);
	ldap_debug(conn, 3, "end: save_ldap_state");
}

/*Load head data from the xml file and return it in a GList*/
GList *load_xml_entries(ldap_connection *conn)
{
	xmlDocPtr doc;
	xmlNodePtr cur;
	xmlNodePtr child;
	GList *xmlHeadList = NULL;
	struct data_entry *entry = NULL;

	ldap_debug(conn, 2, "Loading head data from file %s", conn->dbfile);

	if (open_xml_file(conn, &doc, &cur, conn->dbfile, "ldap_entries")) {
		ldap_debug(conn, 2, "%s not accessible", conn->dbfile);
		return NULL;
	}

	while (cur != NULL) {
		child = cur->xmlChildrenNode;
		entry = g_malloc0(sizeof(struct data_entry));

		while (child) {
			if ((!xmlStrcmp(child->name, (const xmlChar *)"modifyTimestamp"))) {
				entry->modifyTimestamp = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
			}
			if ((!xmlStrcmp(child->name, (const xmlChar *)"uid"))) {
				entry->uid = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
			}

			child = child->next;
		}

		ldap_debug(conn, 3, "Loaded entry: ModTs: %s, uid: %s", entry->modifyTimestamp, entry->uid);
		xmlHeadList = g_list_append(xmlHeadList, entry);
		cur = cur->next;
	}

	xmlFreeDoc(doc);

	ldap_debug(conn, 3, "end: load_xml_entries");
	return xmlHeadList;
}
/*
void add_xml_entry(ldap_connection *conn, char *uid) {
	struct data_entry *entry = NULL;
	xmlDocPtr doc;
	xmlNodePtr cur;
	xmlNodePtr child;

	ldap_debug(conn, 2, "Adding xml entry: %s", uid);

	//Load the data_entry for that uid
	entry = ldap_get_entry(conn, uid);

	//Load the current data from file
	if (open_xml_file(conn, &doc, &cur, conn->dbfile, "ldap_entries")) {
		ldap_debug(conn, 2, "%s not accessible", conn->dbfile);
		return;
	}

	//Add the new entry
	child = xmlNewChild(doc->children, NULL, "ldapentry", NULL);
	xmlNewChild(child, NULL, "modifyTimestamp", entry->modifyTimestamp);
	xmlNewChild(child, NULL, "uid", entry->uid);

	//Save it
	xmlSaveFile(conn->dbfile, doc);
	xmlFreeDoc(doc);
	ldap_debug(conn, 3, "done: add_xml_entry");
}

void delete_xml_entry(ldap_connection *conn, char *uid) {
	xmlDocPtr doc;
	xmlNodePtr cur;
	xmlNodePtr child;

	ldap_debug(conn, 2, "Delete xml entry: %s", uid);

	//Load the current data from file
	if (open_xml_file(conn, &doc, &cur, conn->dbfile, "ldap_entries")) {
		ldap_debug(conn, 2, "%s not accessible", conn->dbfile);
		return;
	}

	//Find the entry
	while (cur != NULL) {
		child = cur->xmlChildrenNode;
		while (child) {
			if ((!xmlStrcmp(child->name, (const xmlChar *)"uid"))) {
				if (!strcmp(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), uid)) {
					//Found it. Now remove it
					ldap_debug(conn, 2, "found it");
					if (cur->prev) {
						cur->prev->next = cur->next;
					} else {
						//This is the first entry
						xmlDocSetRootElement(doc, cur->next);
					}
					if (cur->next) {
						cur->next->prev = cur->prev;
					}
				}
				break;
			}
			child = child->next;
		}
		cur = cur->next;
	}

	//Save it
	xmlSaveFile(conn->dbfile, doc);
	xmlFreeDoc(doc);
	ldap_debug(conn, 3, "done: delete_xml_entry");
}*/

/*Load head data from server and save it to a file*/
void save_xml_entries(ldap_connection *conn)
{
	xmlDocPtr doc;
	xmlNodePtr child;
	GList *ldaplist = load_ldap_entries(conn);
	struct data_entry *entry;

	ldap_debug(conn, 2, "Saving head data to file %s", conn->dbfile);

	doc = xmlNewDoc("1.0");
	doc->children = xmlNewDocNode(doc, NULL, "ldap_entries", NULL);

	while (ldaplist) {
		entry = ((struct data_entry *)(ldaplist->data));
		ldap_debug(conn, 3, "Saving entry: ModTs: %s, uid: %s", entry->modifyTimestamp, entry->uid);

		child = xmlNewChild(doc->children, NULL, "ldapentry", NULL);
		xmlNewChild(child, NULL, "modifyTimestamp", entry->modifyTimestamp);
		xmlNewChild(child, NULL, "uid", entry->uid);

		ldaplist = ldaplist->next;
	}
	xmlSaveFile(conn->dbfile, doc);
	xmlFreeDoc(doc);
	free(ldaplist);
	ldap_debug(conn, 3, "end: save_xml_entries");
}
