#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 _RugbyScoreStorePrivate
{
	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, 150, 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,
		              G_STRUCT_OFFSET (RugbyScoreStoreClass, finished),
		              NULL, NULL, NULL,
		              G_TYPE_NONE, 1,
		              G_TYPE_INT);

	g_type_class_add_private (klass, sizeof (RugbyScoreStorePrivate));
}

static void
populate_store (GObject    *object,
                GParamSpec *pspec)
{
	GtkListStore *store = GTK_LIST_STORE (object);
	RugbyScoreStorePrivate *priv = RUGBY_SCORE_STORE (object)->priv;
	GVariant *possibilities;
	GVariant *possibility;
	GVariantIter iter;
	gsize total;

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

	possibilities = rugby_scoring_get_possibilities (priv->score);
	if (possibilities == NULL)
		return;

	total = g_variant_iter_init (&iter, possibilities);

	while ((possibility = g_variant_iter_next_value (&iter)))
	{
		gint tries, utries, pens;
		GString *tooltip;
		GtkTreeIter iter;

		g_variant_get (possibility, "(iii)", &tries, &utries, &pens);
		g_variant_unref (possibility);

		tooltip = g_string_new_len (NULL, 20);
		if (utries > 0 || tries > 0)
		{
			g_string_append_printf (tooltip, "%d tries, %d converted",
			                        tries + utries, tries);
			if (pens > 0)
				g_string_append_printf (tooltip, ", %d kicks",
				                        pens);
		}
		else if (utries == 0 && tries == 0)
				g_string_append_printf (tooltip, "%d kicks",
				                        pens);

		/* Put result in list store */
		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_PENS, pens,
		                    RUGBY_SCORE_STORE_TOOLTIP, tooltip->str,
		                    -1);

		g_string_free (tooltip, TRUE);
	}

	g_signal_emit (store, signals[FINISHED], 0, (gint) total);
}

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

	priv = G_TYPE_INSTANCE_GET_PRIVATE (store, RUGBY_TYPE_SCORE_STORE, RugbyScoreStorePrivate);

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

	g_signal_connect (store, "notify::score",
	                  G_CALLBACK (populate_store), NULL);

	store->priv = priv;
}

/**
 * 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->priv->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));

	store->priv->score = score;

	g_object_notify_by_pspec (G_OBJECT (store), pspecs[PROP_SCORE]);
}