Skip to content
Snippets Groups Projects
rugby-list-store.c 6.17 KiB
Newer Older
Bruce Cowan's avatar
Bruce Cowan committed
/*
 * SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
 * SPDX-License-Identifier: GPL-3.0-or-later
Bruce Cowan's avatar
Bruce Cowan committed
 */

Bruce Cowan's avatar
Bruce Cowan committed
#include "rugby-list-store.h"
#include "rugby-possibility.h"

#include <gio/gio.h>

struct _RugbyListStore
{
    GObject parent_instance;

Bruce Cowan's avatar
Bruce Cowan committed
    unsigned score;
Bruce Cowan's avatar
Bruce Cowan committed
    GPtrArray *items;
};

static void rugby_list_store_list_model_iface_init (GListModelInterface *iface);
Bruce Cowan's avatar
Bruce Cowan committed

G_DEFINE_TYPE_WITH_CODE (RugbyListStore, rugby_list_store, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
                                                rugby_list_store_list_model_iface_init))
Bruce Cowan's avatar
Bruce Cowan committed

enum
{
    PROP_0,
    PROP_SCORE,
    N_PROPS
};

static GParamSpec *properties[N_PROPS];
Bruce Cowan's avatar
Bruce Cowan committed

// Helper functions

Bruce Cowan's avatar
Bruce Cowan committed
static int
Bruce Cowan's avatar
Bruce Cowan committed
sort_func (gconstpointer a,
           gconstpointer b)
{
Bruce Cowan's avatar
Bruce Cowan committed
    int atries, autries;
    int btries, butries;
Bruce Cowan's avatar
Bruce Cowan committed

Bruce Cowan's avatar
Bruce Cowan committed
    g_object_get (*((gpointer *) a),
Bruce Cowan's avatar
Bruce Cowan committed
                  "tries", &atries,
                  "utries", &autries,
                  NULL);
Bruce Cowan's avatar
Bruce Cowan committed
    g_object_get (*((gpointer *) b),
Bruce Cowan's avatar
Bruce Cowan committed
                  "tries", &btries,
                  "utries", &butries,
                  NULL);

Bruce Cowan's avatar
Bruce Cowan committed
    int trydiff = (btries + butries) - (atries + autries);
Bruce Cowan's avatar
Bruce Cowan committed

    // Sort by total tries first, then converted
    if (trydiff != 0)
        return trydiff;
    else
        return atries - btries;
}

Bruce Cowan's avatar
Bruce Cowan committed
static void
notify_score_cb (GObject    *gobject,
                 GParamSpec *pspec,
                 gpointer    user_data)
Bruce Cowan's avatar
Bruce Cowan committed
{
    RugbyListStore *self = RUGBY_LIST_STORE (user_data);

Bruce Cowan's avatar
Bruce Cowan committed
    int max_tries = self->score / TRY_POINTS;
    int max_utries = self->score / UTRY_POINTS;
Bruce Cowan's avatar
Bruce Cowan committed

Bruce Cowan's avatar
Bruce Cowan committed
    unsigned old_length = self->items->len;
Bruce Cowan's avatar
Bruce Cowan committed
    g_ptr_array_remove_range (self->items, 0, self->items->len);

Bruce Cowan's avatar
Bruce Cowan committed
    for (int tries = 0; tries <= max_tries; tries++)
Bruce Cowan's avatar
Bruce Cowan committed
    {
Bruce Cowan's avatar
Bruce Cowan committed
        for (int utries = 0; utries <= max_utries; utries++)
Bruce Cowan's avatar
Bruce Cowan committed
        {
Bruce Cowan's avatar
Bruce Cowan committed
            int left = self->score - (tries * TRY_POINTS) - (utries * UTRY_POINTS);
Bruce Cowan's avatar
Bruce Cowan committed

            if (left < 0)
                break;

            if (left % KICK_POINTS == 0)
            {
Bruce Cowan's avatar
Bruce Cowan committed
                int kicks = left / KICK_POINTS;
Bruce Cowan's avatar
Bruce Cowan committed

                RugbyPossibility *possibility = rugby_possibility_new (tries,
                                                                       utries,
                                                                       kicks);
                g_ptr_array_add (self->items, possibility);
            }
        }
    }

    g_ptr_array_sort (self->items, sort_func);
    g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, self->items->len);
}

// GListModel implementation

static GType
rugby_list_store_get_item_type (GListModel *list)
{
    return RUGBY_TYPE_POSSIBILITY;
}

Bruce Cowan's avatar
Bruce Cowan committed
static unsigned
rugby_list_store_get_n_items (GListModel *list)
{
    RugbyListStore *self = RUGBY_LIST_STORE (list);

    return self->items->len;
}

static gpointer
rugby_list_store_get_item (GListModel *list,
Bruce Cowan's avatar
Bruce Cowan committed
                           unsigned    position)
{
    RugbyListStore *self = RUGBY_LIST_STORE (list);

    g_return_val_if_fail (position < self->items->len, NULL);

    return g_object_ref (g_ptr_array_index (self->items, position));
}

static void
rugby_list_store_list_model_iface_init (GListModelInterface *iface)
{
      iface->get_item_type = rugby_list_store_get_item_type;
      iface->get_n_items = rugby_list_store_get_n_items;
      iface->get_item = rugby_list_store_get_item;
}

// Class functions

Bruce Cowan's avatar
Bruce Cowan committed
static void
rugby_list_store_finalize (GObject *object)
{
    RugbyListStore *self = RUGBY_LIST_STORE (object);

    g_ptr_array_unref (self->items);

    G_OBJECT_CLASS (rugby_list_store_parent_class)->finalize (object);
}

static void
rugby_list_store_get_property (GObject    *object,
Bruce Cowan's avatar
Bruce Cowan committed
                               unsigned    prop_id,
Bruce Cowan's avatar
Bruce Cowan committed
                               GValue     *value,
                               GParamSpec *pspec)
{
    RugbyListStore *self = RUGBY_LIST_STORE (object);

    switch (prop_id)
    {
        case PROP_SCORE:
            g_value_set_uint (value, rugby_list_store_get_score (self));
Bruce Cowan's avatar
Bruce Cowan committed
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
rugby_list_store_set_property (GObject      *object,
Bruce Cowan's avatar
Bruce Cowan committed
                               unsigned      prop_id,
Bruce Cowan's avatar
Bruce Cowan committed
                               const GValue *value,
                               GParamSpec   *pspec)
{
    RugbyListStore *self = RUGBY_LIST_STORE (object);

    switch (prop_id)
    {
        case PROP_SCORE:
            rugby_list_store_set_score (self, g_value_get_uint (value));
Bruce Cowan's avatar
Bruce Cowan committed
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
rugby_list_store_class_init (RugbyListStoreClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    object_class->finalize = rugby_list_store_finalize;
    object_class->get_property = rugby_list_store_get_property;
    object_class->set_property = rugby_list_store_set_property;

    properties[PROP_SCORE] = g_param_spec_uint ("score",
                                                "Score",
                                                "Score of the match",
                                                0, 200, 0,
                                                G_PARAM_READWRITE);

    g_object_class_install_properties (object_class,
                                       N_PROPS,
                                       properties);
}

static void
rugby_list_store_init (RugbyListStore *self)
{
    self->score = 0;
    self->items = g_ptr_array_new_with_free_func (g_object_unref);

    g_signal_connect (self, "notify::score",
                      G_CALLBACK (notify_score_cb), self);
// Public functions

Bruce Cowan's avatar
Bruce Cowan committed
unsigned
Bruce Cowan's avatar
Bruce Cowan committed
rugby_list_store_get_score (RugbyListStore *self)
{
    g_return_val_if_fail (RUGBY_IS_LIST_STORE (self), 0);

    return self->score;
}

void
rugby_list_store_set_score (RugbyListStore *self,
Bruce Cowan's avatar
Bruce Cowan committed
                            unsigned        score)
Bruce Cowan's avatar
Bruce Cowan committed
{
    g_return_if_fail (RUGBY_IS_LIST_STORE (self));

    if (score != self->score)
    {
        self->score = score;
        g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]);
    }
}

RugbyListStore *
rugby_list_store_new (void)
{
    return g_object_new (RUGBY_TYPE_LIST_STORE, NULL);
}