//- 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 "FormatOutput.h"
#include <memory.h>

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

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

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

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

bool CircularBuffer_IsEmpty(struct CircularBuffer * self)
{
    return self->index == self->outdex;
}

bool CircularBuffer_IsFull(struct CircularBuffer * self)
{
    return nextIndex(self, self->index) == self->outdex;
}

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);

    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);
    }

    return value;
}

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