ANSI_COLOR_RESET = "\x1b[0m"
ANSI_COLOR_YELLOW = "\x1b[33m"
ANSI_BOLD = "\x1b[1m"
ANSI_COLOR_GREEN = "\x1b[32m"

CONSOLE_COLOR_DEFAULT = ANSI_COLOR_RESET
CONSOLE_COLOR_PROMPT = ANSI_COLOR_YELLOW
CONSOLE_COLOR_USER_INPUT = ANSI_BOLD + ANSI_COLOR_GREEN


# Iterative search
# Actively searches and prevents a pattern from being returned
class IterSearch:
    def __init__(self, pattern):
        self.pattern = list(pattern)
        self.buffer = []

    def __call__(self, char):
        self.buffer += [char]

        if self.pattern[: len(self.buffer)] == self.buffer:
            if len(self.buffer) >= len(self.pattern):
                self.buffer.clear()
            return []

        _tmp = self.buffer[:]
        self.buffer.clear()
        return _tmp


class Circle:
    def __init__(self, size, default=0):
        self.list = [default] * size
        self.maxsize = size
        self.size = 0
        self.offset = 0

    def append(self, elem):
        if self.size < self.maxsize:
            self.list[self.size] = elem
            self.size += 1
        else:
            self.list[self.offset] = elem
            self.offset = (self.offset + 1) % self.maxsize

    def __getitem__(self, val):
        if isinstance(val, int):
            if 0 > val or val >= self.size:
                raise IndexError("Index out of range")
            return (
                self.list[val]
                if self.size < self.maxsize
                else self.list[(self.offset + val) % self.maxsize]
            )
        elif isinstance(val, slice):
            start, stop, step = val.start, val.stop, val.step
            if step is None:
                step = 1
            if start is None:
                start = 0
            if stop is None:
                stop = self.size
            if start < 0:
                start = self.size + start
            if stop < 0:
                stop = self.size + stop

            indices = range(start, stop, step)
            return [
                self.list[(self.offset + i) % self.maxsize]
                for i in indices
                if i < self.size
            ]
        else:
            raise TypeError("Invalid argument type")


if __name__ == "__main__":
    c = Circle(5)

    c.append(1)
    print(c.list)
    print(c[:])
    assert c[0] == 1
    assert c[:5] == [1]

    for i in range(2, 5 + 1):
        c.append(i)
    print(c.list)
    print(c[:])
    assert c[0] == 1
    assert c[:5] == [1, 2, 3, 4, 5]

    for i in range(5 + 1, 9 + 1):
        c.append(i)
    print(c.list)
    print(c[:])
    assert c[0] == 5
    assert c[:5] == [5, 6, 7, 8, 9]
    # assert c[:-5] == [5,6,7,8,9]
    assert c[:10] == [5, 6, 7, 8, 9]
