/** \file liststore.c
 * Handling of the list store used for tree views and drop boxes
 */

/*
 *
 * Copyright 2016 Martin Fischer <m_fischer@users.sf.net>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#define GTK_DISABLE_SINGLE_INCLUDES
#define GDK_DISABLE_DEPRECATED
#define GTK_DISABLE_DEPRECATED
#define GSEAL_ENABLE

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include "gtkint.h"

/**
 * Get data of one row in a list
 * \param b IN list widget
 * \param inx IN row to retrieve
 * \param childR IN list for data (?)
 * \returns
 */

wListItem_p wlibListItemGet(
        GtkListStore *ls,
        wIndex_t inx,
        GList ** childR)
{
	wListItem_p id_p;

	assert(ls != NULL);

	if (childR) {
		*childR = NULL;
	}

	if (inx < 0) {
		return NULL;
	}

	id_p = wlibListStoreGetContext(ls, inx);

	return id_p;
}

/**
 * Get the context (user data) for a row in the list store
 *
 * \param ls IN list store
 * \param inx IN row
 * \returns pointer to data
 */

void *
wlibListStoreGetContext(GtkListStore *ls, int inx)
{
	GtkTreeIter iter;
	gchar *string = NULL;
	gboolean result;
	gint childs;

	childs = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(ls),
	                                        NULL);

	if (inx < childs) {
		result = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(ls),
		                                       &iter,
		                                       NULL,
		                                       inx);

		if (result) {
			gtk_tree_model_get(GTK_TREE_MODEL(ls),
			                   &iter,
			                   LISTCOL_DATA,
			                   &string,
			                   -1);
		} else {
			printf("Invalid index %d for list!\n", inx);

		}
	}

	return (string);
}


/**
 * Clear the list store. All data in the list store will be automatically
 * free'd when the list store is cleared.
 *
 * \param listStore IN
 */

void
wlibListStoreClear(GtkListStore *listStore)
{
	wListItem_p id_p;
	int i = 0;

	assert(listStore != NULL);

	id_p = wlibListStoreGetContext(listStore, i++);

	while (id_p) {
		if (id_p->label) {
			g_free(id_p->label);
		}
		g_free(id_p);
		id_p = wlibListStoreGetContext(listStore, i++);
	}

	gtk_list_store_clear(listStore);
}

/**
 * Create a list store. The list store will have one column for user
 * data that will not be displayed, a column for a bitmap and <cnt>
 * colors for data.
 *
 * \param colCnt IN number of additional columns
 * \returns the list store
 */

GtkListStore *
wlibNewListStore(int colCnt)
{
	GtkListStore *ls;
	GType *colTypes;
	int i;

	/* create the list store, using strings for all columns */
	colTypes = g_malloc(sizeof(GType) * (colCnt + LISTCOL_TEXT));
	colTypes[ LISTCOL_BITMAP ] = GDK_TYPE_PIXBUF;
	colTypes[ LISTCOL_DATA ] = G_TYPE_POINTER;

	for (i = 0; i < colCnt; i++) {
		colTypes[ LISTCOL_TEXT + i ] = G_TYPE_STRING;
	}

	ls = gtk_list_store_newv(colCnt + LISTCOL_TEXT, colTypes);
	g_free(colTypes);

	return (ls);
}

/**
 * Update the list store at the iter's position
 *
 * \param ls IN list store
 * \param iter IN iterator into list store
 * \param labels IN tab separated label string
 * \returns number of updated columns
 */

static int
wlibListStoreUpdateIter(GtkListStore *ls, GtkTreeIter *iter, char *labels)
{
	char *convertedLabels;
	char *text;
	char *start;
	int current = 0;

	convertedLabels = strdup(wlibConvertInput(labels));
	start = convertedLabels;

	while ((text = strchr(start, '\t')) != NULL) {
		*text = '\0';
		gtk_list_store_set(ls, iter, LISTCOL_TEXT + current, start, -1);
		start = text + 1;
		current++;
	}

	/* add the last piece of the string */
	gtk_list_store_set(ls, iter, LISTCOL_TEXT + current, start, -1);

	free(convertedLabels);
	return (current+1);
}

/**
 * Add a pixbuf to the list store. So pixbuf is unref'ed so it will be freed
 * with the list store.
 *
 * \param ls IN list store
 * \param iter IN position
 * \param pixbuf IN pixbuf to add
 */

void
wlibListStoreSetPixbuf(GtkListStore *ls, GtkTreeIter *iter, GdkPixbuf *pixbuf)
{
	gtk_list_store_set(ls, iter, LISTCOL_BITMAP, pixbuf, -1);
	g_object_ref_sink(pixbuf);
	g_object_unref(pixbuf);
}
/**
 * Add a row to the list store
 *
 * \param ls IN the list store
 * \param cols IN columns in list store
 * \param id IN id
 * \returns number columns added
 */

int
wlibListStoreAddData(GtkListStore *ls, GdkPixbuf *pixbuf, int cols,
                     wListItem_p id)
{
	GtkTreeIter iter;
	int count;

	gtk_list_store_append(ls, &iter);
	gtk_list_store_set(ls, &iter, LISTCOL_DATA, id, -1);

	if (pixbuf) {
		wlibListStoreSetPixbuf(ls, &iter, pixbuf);
	}

	count = wlibListStoreUpdateIter(ls, &iter, (char *)id->label);

	return (count);
}

/**
 * Change a row in the list store. The passed strings are placed
 * in the first cols text columns of the list store.
 *
 * \param ls IN list store
 * \param row IN row in list store
 * \param cols IN number of columns to set
 * \param labels IN tab separated list of texts
 * \param bm IN bitmap
 * \return count of updated text fields
 */

int
wlibListStoreUpdateValues(GtkListStore *ls, int row, int cols, char *labels,
                          wIcon_p bm)
{
	GtkTreeIter iter;
	int count;

	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(ls),
	                              &iter,
	                              NULL,
	                              row);

	count = wlibListStoreUpdateIter(ls, &iter, labels);

	if (bm) {
		GdkPixbuf *pixbuf;

		pixbuf = wlibMakePixbuf(bm);
		wlibListStoreSetPixbuf(ls, &iter, pixbuf);
	}

	return (count);
}

