/***********************************************************************
 * Element
 * Implementation of Elements as structure for a single integer
 * Although this implementation internally relies on integer, the whole
 * code should work with other impl. of `Element`.
 ***********************************************************************/
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>

#include "Element.h"

static const int MAX_VALUE = RAND_MAX;//Change this to a lower number for visualization

struct element_t
{
    int value;
};

bool areEqual(const Element* a, const Element* b)
{
    return a->value == b->value;
}

int getCode(const Element* element)
{
    return element->value;
}


static Element** createSequence(size_t length)
{
    if (length == 0)
        return NULL;

    Element** seq = (Element**) malloc(length * sizeof(Element*));
    if (!seq)
        return NULL;


    for (size_t i=0; i < length; i++)
    {
        seq[i] = (Element*) malloc(sizeof(Element));
        if (!seq[i])
        {
            deleteSequence(seq, length);
            return NULL;
        }
    }

    return seq;
}


Element** createRandomSequence(size_t length)
{

    Element** seq = createSequence(length);
    if (!seq)
        return NULL;

    for (size_t i=0; i < length; i++)
        seq[i]->value = rand() % MAX_VALUE;

    return seq;
}


Element** createMajoritySequence(size_t length)
{
    Element** seq = createSequence(length);
    if (!seq)
        return NULL;

    size_t nbMaj = length - (size_t)(rand() % ((length+1)/2));
    int majElemValue = rand() % MAX_VALUE;

    // Place the majority elements at the start
    for (size_t i=0; i < nbMaj; i++)
        seq[i]->value = majElemValue;

    // Draw other elements (might be the same as the majority elem)
    for (size_t i=nbMaj; i < length; i++)
        seq[i]->value = rand() % MAX_VALUE;

    // Shuffle: Fisher-Yates
    size_t i = length - 1;
    size_t j;
    Element* temp;

    while (i > 0)
    {
        j = (size_t)rand() % (i + 1);
        temp = seq[i];
        seq[i] = seq[j];
        seq[j] = temp;
        i--;
    }

    return seq;
}


Element** createFewUniquesSequence(size_t nbUniques, size_t length)
{
    Element** seq = createSequence(length);
    if (!seq)
        return NULL;

    for (size_t i=0; i < length; i++)
        seq[i]->value = rand() % nbUniques;

    return seq;
}


void deleteSequence(Element** sequence, size_t length)
{
    if (!sequence)
        return;

    for (size_t i=0; i < length; i++)
    {
        if (sequence[i])
            free(sequence[i]);
    }

    free(sequence);
}
