/*
 *  Copyright (C) 2004 Mathias Andre <mathias@openbrookes.org>
 *
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#include <glib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <time.h>

#include "nb_note.h"

/* create and free object */
Note * 
nb_note_new (void)
{
	Note * self = g_malloc (sizeof (Note));
	self->title = NULL;
	self->text = NULL;
	self->date = g_date_new ();
	self->update = g_date_new ();
	nb_note_set_date (self, NULL);
	nb_note_set_lastupdate (self, NULL);
	self->type = NOTE;
	self->status = NONE;
	self->attachments = nb_attachment_list_new ();

	return self;
}

void
nb_note_free (Note * self)
{
	g_free (self->title);
	g_free (self->text);
	g_date_free (self->date);
	g_date_free (self->update);
	nb_attachment_list_free (self->attachments);
	g_free (self);
}

/* read/write from/to xml doc */
Note *
nb_note_new_from_xml_doc (xmlDocPtr doc, xmlNodePtr cur)
{
	Note * n = nb_note_new ();
	xmlChar * ctype = NULL;
	xmlChar * cstatus = NULL;

	/* set default values */
	nb_note_set_type (n, NOTE);
	nb_note_set_status (n, NONE);

	/* get the type */
	ctype = xmlGetProp (cur, "type");

	if ( !xmlStrcmp (ctype, (const xmlChar *) "personal") )
		nb_note_set_type (n, PERSONAL);
	else if ( !xmlStrcmp (ctype, (const xmlChar *) "problem") )
		nb_note_set_type (n, PROBLEM);
	else if ( !xmlStrcmp (ctype, (const xmlChar *) "trick") )
		nb_note_set_type (n, TIPNTRICK);
	else if ( !xmlStrcmp (ctype, (const xmlChar *) "bookmark") )
		nb_note_set_type (n, BOOKMARK);

	/* get the status */
	cstatus = xmlGetProp (cur, "status");

	if ( !xmlStrcmp (cstatus, (const xmlChar *) "open") )
		nb_note_set_status (n, OPEN);
	else if ( !xmlStrcmp (cstatus, (const xmlChar *) "solved") )
		nb_note_set_status (n, SOLVED);


	cur = cur->xmlChildrenNode;

	while ( cur != NULL )
	{
		/* get the title */
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "title") )
			nb_note_set_title (n, xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));

		/* get the date */
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "date") )
		{
			nb_note_set_date (n, nb_date_new_from_xml_doc (doc, cur));

			if ( n->date == NULL ) /* Note is invalid */
			{
				nb_note_free (n);
				return NULL;
			}
		}

		/* get the lastupdate */
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "lastupdate") )
			nb_note_set_lastupdate (n, nb_date_new_from_xml_doc (doc, cur));

		/* get the attachments */
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "attachment") )
			nb_note_add_attachment (n, nb_attachment_new_from_xml_doc (doc, cur));

		cur = cur->next;
	}

	if ( n->update == NULL )
		nb_note_set_lastupdate (n, g_memdup (n->date, sizeof (GDate)));

	return n;
}

GDate *
nb_date_new_from_xml_doc (xmlDocPtr doc, xmlNodePtr cur)
{
	GDate * date;
	int day;
	int month;
	int year;

	cur = cur->xmlChildrenNode;

	while ( cur != NULL )
	{
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "day") )
			day = atoi (xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));

		if ( !xmlStrcmp (cur->name, (const xmlChar *) "month") )
			month = atoi (xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));

		if ( !xmlStrcmp (cur->name, (const xmlChar *) "year") )
			year = atoi (xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));

		cur = cur->next;
	}

	date = g_date_new_dmy (day, month, year);

	if ( g_date_valid (date) )
		return date;

	return NULL;
}

gchar *
nb_note_get_text_from_file (xmlDocPtr doc, xmlNodePtr cur)
{
	cur = cur->xmlChildrenNode;

	xmlChar * text = NULL;

	while ( cur != NULL )
	{
		if ( !xmlStrcmp (cur->name, (const xmlChar *) "content") )
		{
			text = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			break;
		}

		cur = cur->next;
	}

	return text;
}

xmlNodePtr
nb_note_get_xml_pointer (Note * self, xmlNsPtr ns, gint index)
{
	/* TODO replace the snprintf by g_strdup_printf */
	int i;
	xmlNodePtr cur;
	xmlNodePtr date;
	xmlNodePtr update;
	xmlNodePtr attach;
	xmlChar * type;
	xmlChar * status;
	xmlChar cindex[5];
	xmlChar cday[3];
	xmlChar cmonth[3];
	xmlChar cyear[5];
	xmlChar cluday[3];
	xmlChar clumonth[3];
	xmlChar cluyear[5];

	Attachment * a;


	/* create a new note node */
	cur = xmlNewNode (ns, "note");

	/* add the index as a node attribute */
	snprintf (cindex, 4, "%d", index);
	xmlNewProp (cur, "index", cindex);

	/* add the type as a node attribute */
	if ( self->type == NOTE )
		type = "note";
	else if ( self->type == PERSONAL )
		type = "personal";
	else if ( self->type == PROBLEM )
		type = "problem";
	else if ( self->type == TIPNTRICK )
		type = "trick";
	else
		type = "bookmark";

	xmlNewProp (cur,"type", type);

	/* add the status as a node attribute */
	if ( self->status == NONE )
		status = "none";
	else if ( self->status == OPEN )
		status = "open";
	else
		status = "solved";

	xmlNewProp (cur, "status", status);

	/* set the children nodes */
	xmlNewTextChild (cur, ns, "title", self->title);
	xmlNewTextChild (cur, ns, "content", self->text);

	date = xmlNewTextChild (cur, ns, "date", NULL);

	snprintf (cday, 3, "%d", g_date_get_day (self->date));
	snprintf (cmonth, 3, "%d", g_date_get_month (self->date));
	snprintf (cyear, 5, "%d", g_date_get_year (self->date));

	xmlNewTextChild (date, ns, "day", cday);
	xmlNewTextChild (date, ns, "month", cmonth);
	xmlNewTextChild (date, ns, "year", cyear);

	update = xmlNewTextChild (cur, ns, "lastupdate", NULL);

	snprintf (cluday, 3, "%d", g_date_get_day (self->update));
	snprintf (clumonth, 3, "%d", g_date_get_month (self->update));
	snprintf (cluyear, 5, "%d", g_date_get_year (self->update));

	xmlNewTextChild (update, ns, "day", cluday);
	xmlNewTextChild (update, ns, "month", clumonth);
	xmlNewTextChild (update, ns, "year", cluyear);

	for ( i = 0 ; i < nb_note_get_nb_attachments (self) ; i++ )
	{
		a = g_ptr_array_index (self->attachments, i);
		attach = xmlNewTextChild (cur, ns, "attachment", NULL);
		xmlNewTextChild (attach, ns, "uri", a->uri);
		xmlNewTextChild (attach, ns, "mime", a->mime_type);
	}

	return cur;

}

/* update attributes */
void
nb_note_set_title (Note * self, gchar * title)
{
	g_free (self->title);
	self->title = title;
}

void
nb_note_set_text (Note * self, gchar * text)
{
	g_free (self->text);
	self->text = text;
}

void
nb_note_set_type (Note * self, NoteType type)
{
	self->type = type;
}

void
nb_note_set_status (Note * self, NoteStatus status)
{
	self->status = status;
}

void
nb_note_set_date (Note * self, GDate * date)
{
	/* if date is NULL set date to current time */
	if ( date != NULL )
	{
		g_date_free (self->date);
		self->date = date;
	}
	else
		g_date_set_time (self->date, time (NULL));
}

void
nb_note_set_lastupdate (Note * self, GDate * update)
{
	/* if update is NULL set date to current time */
	if ( update != NULL )
	{
		g_date_free (self->update);
		self->update = update;
	}
	else
		g_date_set_time (self->update, time (NULL));
}

void
nb_note_clear_text (Note * self)
{
	g_free (self->text);
	self->text = NULL;
}

/* attachments */
gboolean
nb_note_add_attachment (Note * self, Attachment * a)
{
	return nb_attachment_list_add (self->attachments, a);
}

gboolean
nb_note_remove_attachment (Note * self, Attachment * a)
{
	return nb_attachment_list_remove (self->attachments, a);
}

gint
nb_note_get_nb_attachments (Note * self)
{
	return nb_attachment_list_get_nb (self->attachments);
}

void
nb_note_check_attachments (Note * self)
{
	nb_attachment_list_check (self->attachments);
}

/* queries */
gboolean
nb_note_matches_query (Note * self, gchar * query)
{
	if ( g_strrstr ( g_utf8_casefold (self->title, -1), query) != NULL )
		return TRUE;
	else if ( ( self->text != NULL ) && ( g_strrstr (g_utf8_casefold (self->text, -1), query) != NULL ) )
		return TRUE;

	return FALSE;
}

gboolean
nb_note_matches_type (Note * self, ExportType * type)
{
	if ( (self->type == NOTE) && (type->note) )
		return TRUE;
	if ( (self->type == PERSONAL) && (type->personal) )
		return TRUE;
	if ( (self->type == PROBLEM) && (type->problem) )
		return TRUE;
	if ( (self->type == TIPNTRICK) && (type->trick) )
		return TRUE;
	if ( (self->type == BOOKMARK) && (type->bookmark) )
		return TRUE;

	return FALSE;
}
