import sys
import types

class Buffer(object):
    """
    A fixed-length buffer
    """
    
    def __init__(self, len):
        """
        A Buffer is initialized with its size
        """
        self.buffer = [None]*len
        self.head = 0
        self.maxsize = len
        self.size = 0
            
    def __str__(self):
        return self.list().__str__()    

    def __getitem__(self, key):
        """
        Overloads the rvalue [] operator
        """
        if isinstance(key, types.SliceType):
            """
            slice retrieval is potentially inefficient, but works well
            """
            return self.list().__getitem__(key)
        elif isinstance(key, types.IntType):
            if self.size <= key:
                raise IndexError("buffer index out of range")
            return self.buffer[(self.head + key) % self.maxsize]
        else:
            raise IndexError("unsupported index type")
        
    def __setitem__(self, key, value):
        """
        Overloads the lvalue [] operator
        """
        if isinstance(key, types.SliceType):
            """
            slice-assignment is not implemented
            """
            raise IndexError("buffer does not support lvalue slices")
        elif isinstance(key, types.IntType):
            if self.size <= key:
                raise IndexError("buffer assignment index out of range")
            self.buffer[(self.head + key) % self.maxsize] = value
            return value
        else:
            raise IndexError("unsupported index type")
    
    def __len__(self):
        """
        Implements len(buffer); required for proper slice-handling
        """
        return self.size

    def append(self, item):
        """
        Add an item to the end of the buffer
        """
        if self.size == self.maxsize:
            raise IndexError("buffer full")
        
        self.buffer[(self.head + self.size) % self.maxsize] = item
        self.size = self.size + 1
        return item
    
    def remove(self):
        """
        Retrieve an item from the front of the buffer
        """
        if self.size == 0:
            raise IndexError("buffer empty")
    
        item = self.buffer[self.head]
        self.head = (self.head + 1) % self.maxsize
        self.size = self.size - 1
        return item
    
    def push(self, item):
        """
        Adds an item to the end of the buffer, pushing the front of the buffer out
        if necessary.  Returns the item removed; None is no item removed.
        """
        removed = None
        if self.size == self.maxsize:
            removed = self.remove()
            
        self.append(item)
        return removed
        

    def list(self):
        """
        Return a list representation of the buffer
        """
        return [i for i in self]
        
    def getBag(self):
        """
        Return a list representation of the buffer with extra features
        """
        retVal = [i.word for i in self]
        for i in range(5):
            feat = "__" + (self.buffer[(self.head - i) % self.maxsize].tag)
            retVal.append(feat)
            feat = "__" + (self.buffer[(self.head + i) % self.maxsize].tag)
            retVal.append(feat)
            feat = "__pre__" + (self.buffer[(self.head - i) % self.maxsize].word)
            retVal.append(feat)
            feat = "__post__" + (self.buffer[(self.head + i) % self.maxsize].word)
            retVal.append(feat)
        feat = "__pre__" + (self.buffer[(self.head - 1) % self.maxsize].word) + "__" + \
        (self.buffer[(self.head - 2) % self.maxsize].word)
        retVal.append(feat)
        feat = "__post__" + (self.buffer[(self.head + 1) % self.maxsize].word) + "__" + \
        (self.buffer[(self.head + 2) % self.maxsize].word)
        return retVal

