#include <glib.h>

#include "edvhistory.h"


edv_history_struct *EDVHistoryNew(void);
edv_history_struct *EDVHistoryCopy(const edv_history_struct *h);
void EDVHistoryDelete(edv_history_struct *h);

void EDVHistorySetValues(
	edv_history_struct *h,
	gint type,
	gulong time_start,
	gulong time_end,
	gint status,
	const gchar *src_path,
	const gchar *tar_path,
	const gchar *comments
);

edv_history_struct *EDVHistoryListAppendNew(
	edv_history_struct ***list, gint *total,
	gint *n, gint max
);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	Creates a new history item.
 */
edv_history_struct *EDVHistoryNew(void)
{
	edv_history_struct *h = EDV_HISTORY(
	    g_malloc0(sizeof(edv_history_struct))
	);

	h->type = EDV_HISTORY_UNKNOWN;

	h->time_start = 0;
	h->time_end = 0;

	h->status = 0;

	h->src_path = NULL;
	h->tar_path = NULL;

	h->comments = NULL;

	return(h);
}

/*
 *	Coppies a history item
 */
edv_history_struct *EDVHistoryCopy(const edv_history_struct *h)
{
	const edv_history_struct *src = h;
	edv_history_struct *tar;

	if(src == NULL)
	    return(NULL);

	tar = EDVHistoryNew();

	tar->type = src->type;

	tar->time_start = src->time_start;
	tar->time_end = src->time_end;

	tar->status = src->status;

	tar->src_path = STRDUP(src->src_path);
	tar->tar_path = STRDUP(src->tar_path);

	tar->comments = STRDUP(src->comments);

	return(tar);
}

/*
 *	Deletes the history item
 */
void EDVHistoryDelete(edv_history_struct *h)
{
	if(h == NULL)
	    return;

	g_free(h->src_path);
	g_free(h->tar_path);

	g_free(h->comments);

	g_free(h);
}


/*
 *	Sets the given values to the given history item.
 */
void EDVHistorySetValues(
	edv_history_struct *h,
	gint type,
	gulong time_start, gulong time_end,
	gint status,
	const gchar *src_path, const gchar *tar_path,
	const gchar *comments
)
{
	if(h == NULL)
	    return;

	h->type = type;

	h->time_start = time_start;
	h->time_end = time_end;

	h->status = status;

	g_free(h->src_path);
	h->src_path = STRDUP(src_path);

	g_free(h->tar_path);
	h->tar_path = STRDUP(tar_path);

	g_free(h->comments);
	h->comments = STRDUP(comments);
}

/*
 *	Appends a new history item to the given list, reallocating the
 *	given list and increasing the total as needed.
 *
 *	Returns the pointer to the new history item structure and sets
 *	*n to the new index or -1 on error.
 *
 *	If max is positive and appending the new item would cause the
 *	maximum to be exceeded then the oldest (index 0) item will be
 *	deleted and the item pointers in the list will be shifted.
 *
 *	Can return NULL on error.
 */
edv_history_struct *EDVHistoryListAppendNew(
	edv_history_struct ***list, gint *total,
	gint *n, gint max
)
{
	gint i;
	edv_history_struct *h;


	if(n != NULL)
	    *n = -1;

	if((list == NULL) || (total == NULL))
	    return(NULL);

	/* Allocate one more pointer and append a new item */
	i = MAX(*total, 0);
	*total = i + 1;
	*list = (edv_history_struct **)g_realloc(
	    *list,
	    (*total) * sizeof(edv_history_struct *)
	);
	if(*list == NULL)
	{
	    *total = 0;
	    return(NULL);
	}

	/* Allocate a new item at the highest index */
	(*list)[i] = h = EDVHistoryNew();
	if(h == NULL)
	    return(NULL);


	/* Check if total has exceeded maximum */
	if(max > 0)
	{
	    while(*total > max)
	    {
		/* Delete oldest (index 0) item */
		EDVHistoryDelete((*list)[0]);

		/* Reduce total */
		i = *total;
		*total = i - 1;

		/* Shift pointers */
		for(i = 0; i < *total; i++)
		    (*list)[i] = (*list)[i + 1];

		/* Reallocate pointers */
		*list = (edv_history_struct **)g_realloc(
		    *list,
		    (*total) * sizeof(edv_history_struct *)
		);
		if(*list == NULL)
		{
		    *total = 0;
	    	    return(NULL);
		}
	    }
	}

	/* Update index return */
	i = *total;
	if(n != NULL)
	    *n = i - 1;

	return(h);
}
