//- Copyright (c) 2008-2020 James Grenning --- All rights reserved
//- For exclusive use by participants in Wingman Software training courses.
//- Cannot be used by attendees to train others without written permission.
//- www.wingman-sw.com james@wingman-sw.com

#include "CircularBuffer.h"
#include <memory.h>

struct CircularBuffer
{
    size_t index;
    size_t outdex;
    size_t capacity;
    size_t count;
    int default_value;
    int values[];
};

struct CircularBuffer * CircularBuffer_Create(size_t capacity, int default_value)
{
    struct CircularBuffer * self = malloc(sizeof(*self) + (capacity) * sizeof(int));
    self->index = 0;
    self->outdex = 0;
    self->count = 0;
    self->capacity = capacity;
    self->default_value = default_value;
    return self;
}

void CircularBuffer_Destroy(struct CircularBuffer * self)
{
    free(self);
}

static size_t nextIndex(struct CircularBuffer * self, size_t dex)
{
    dex++;
    if (dex >= self->capacity+1)
        dex = 0;
    return dex;
}

bool CircularBuffer_IsEmpty(struct CircularBuffer * self)
{
    return self->count == 0;
}

bool CircularBuffer_IsFull(struct CircularBuffer * self)
{
    return self->count == self->capacity;
}

bool CircularBuffer_Put(struct CircularBuffer * self, int value)
{
    if (CircularBuffer_IsFull(self))
        return false;

    self->values[self->index] = value;
    self->index = nextIndex(self, self->index);
    self->count++;

    return true;
}

int CircularBuffer_Get(struct CircularBuffer * self)
{
    int value = self->default_value;
    if (!CircularBuffer_IsEmpty(self))
    {
        value = self->values[self->outdex];
        self->outdex = nextIndex(self, self->outdex);
        self->count--;
    }

    return value;
}

size_t CircularBuffer_Capacity(struct CircularBuffer * self)
{
    return self->capacity;
}
