#include "rugby-score-store.h"
#include "rugby-scoring.h"

enum
{
	FINISHED,
	LAST_SIGNAL
};

enum
{
	PROP_0,
	PROP_SCORE,
	PROP_LAST
};

static GParamSpec *pspecs[PROP_LAST];

struct _RugbyScoreStore
{
  	GtkListStore parent_instance;

	gint score;
};

G_DEFINE_TYPE (RugbyScoreStore, rugby_score_store, GTK_TYPE_LIST_STORE)

static guint signals[LAST_SIGNAL] = { 0, };

static void
rugby_score_store_set_property (GObject      *object,
                                guint         prop_id,
                                const GValue *value,
                                GParamSpec   *pspec)
{
	RugbyScoreStore *store = RUGBY_SCORE_STORE (object);

	switch (prop_id)
	{
		case PROP_SCORE:
			rugby_score_store_set_score (store, g_value_get_int (value));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
			break;
	}
}

static void
rugby_score_store_get_property (GObject    *object,
                                guint       prop_id,
                                GValue     *value,
                                GParamSpec *pspec)
{
	RugbyScoreStore *store = RUGBY_SCORE_STORE (object);

	switch (prop_id)
	{
		case PROP_SCORE:
			g_value_set_int (value, rugby_score_store_get_score (store));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
			break;
	}
}

static void
rugby_score_store_class_init (RugbyScoreStoreClass *klass)
{
	GObjectClass *obj_class = G_OBJECT_CLASS (klass);

	obj_class->get_property = rugby_score_store_get_property;
	obj_class->set_property = rugby_score_store_set_property;

	pspecs[PROP_SCORE] = g_param_spec_int ("score", "Score", "The score",
	                                       0, 200, 0,
	                                       G_PARAM_READWRITE);
	g_object_class_install_property (obj_class, PROP_SCORE, pspecs[PROP_SCORE]);

	/**
	 * RugbyScoreStore::finished:
	 * @store: the object which received the signal
	 *
	 * Emitted when possibilities checking has finished.
	 */
	signals[FINISHED] =
		g_signal_new ("finished",
		              G_TYPE_FROM_CLASS (obj_class),
		              G_SIGNAL_RUN_LAST,
		              0,
		              NULL, NULL, NULL,
		              G_TYPE_NONE, 1,
		              G_TYPE_INT);
}

static void
populate_store_foreach (gpointer data,
                        gpointer user_data)
{
    RugbyPossibility *possiblity = (RugbyPossibility *) data;
    GtkListStore *store = GTK_LIST_STORE (user_data);

    GtkTreeIter iter;
    gint tries = possiblity->tries;
    gint utries = possiblity->utries;
    gint kicks = possiblity->kicks;

    g_autofree gchar *tooltip = g_strdup_printf ("%d tries, %d converted, %d kicks",
                                                 tries, utries, kicks);

    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter,
                        RUGBY_SCORE_STORE_TRIES, tries,
                        RUGBY_SCORE_STORE_UTRIES, utries,
                        RUGBY_SCORE_STORE_KICKS, kicks,
                        RUGBY_SCORE_STORE_TOOLTIP, tooltip,
                        -1);
}

static void
populate_store (RugbyScoreStore *self)
{
	GtkListStore *store = GTK_LIST_STORE (self);

	g_autoptr(GPtrArray) possibilities = NULL;

	/* Clear the store */
	gtk_list_store_clear (store);

	possibilities = rugby_scoring_get_possibilities (self->score);
    if (possibilities->len == 0)
		return;

    g_ptr_array_foreach (possibilities, populate_store_foreach, store);

    g_signal_emit (self, signals[FINISHED], 0, (gint) possibilities->len);
}

static void
rugby_score_store_init (RugbyScoreStore *store)
{
	GType types[] = { G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING };

	gtk_list_store_set_column_types (GTK_LIST_STORE (store), RUGBY_SCORE_STORE_COLUMNS, types);
	store->score = 0;
}

/**
 * rugby_score_store_new:
 *
 * Creates a #RugbyScoreStore. This can be used to update a #GtkTreeView with
 * possibilities.
 *
 * Returns: a new #RugbyScoreStore
 */
RugbyScoreStore *
rugby_score_store_new (void)
{
	return g_object_new (RUGBY_TYPE_SCORE_STORE, NULL);
}

/**
 * rugby_score_store_get_score:
 * @scores: a #RugbyScoreStore
 *
 * Gets the current score.
 *
 * Returns: the current score
 */
gint
rugby_score_store_get_score (RugbyScoreStore *store)
{
	g_return_val_if_fail (RUGBY_IS_SCORE_STORE (store), 0);

	return store->score;
}

/**
 * rugby_score_store_set_score:
 * @scores: a #RugbyScoreStore
 * @score: the new score
 *
 * Sets the current score.
 */
void
rugby_score_store_set_score (RugbyScoreStore *store,
                             gint             score)
{
	g_return_if_fail (RUGBY_IS_SCORE_STORE (store));
	g_return_if_fail (score >= 0 && score <= 200);

	store->score = score;
	g_object_notify_by_pspec (G_OBJECT (store), pspecs[PROP_SCORE]);

	populate_store (store);
}