import cStringIO
import Limits
import SuperStruct
import CSuper

SEEK_BEG = 0
SEEK_CUR = 1
SEEK_END = 2

class BinaryReader():
    def __init__(self, stream='', openMethod='rb'):
        self.openMethod = openMethod
        self.stream = stream
        self.name = ''
        self.EOF = 0
        self.startTell = 0

        self.remember = 0

        self.fopen(stream)

    def fopen(self, stream):
        if not self.openMethod:
            raise Exception("Open Method must be explicitly stated.")

        if self.openMethod == 'string':
            self.IODescriptor = cStringIO.StringIO(stream)
            self.name = 'cStringIO instance'
        else:
            self.IODescriptor = open(stream, self.openMethod)
            self.name = stream

    def GetRememberOffset(self):
        return self.remember

    def RememberOffset(self):
        self.remember = self.IODescriptor.tell()

    def JumpBack(self):
        self.seek(self.remember, SEEK_BEG)

    def GetEOF(self):
        if self.EOF:
            return self.EOF
        else:
            Remember = self.IODescriptor.tell()
            self.IODescriptor.seek(0, SEEK_END)
            self.EOF = self.IODescriptor.tell()
            self.IODescriptor.seek(Remember, SEEK_BEG)
            return self.GetEOF()

    def ReachedEOF(self):
        return self.tell() == self.GetEOF()

    def tell(self):
        return self.IODescriptor.tell()

    def seek(self, offset, whence=SEEK_BEG):
        self.IODescriptor.seek(offset, whence)
    
    def read(self, numbytes=0):
        if numbytes > 0:
            return self.IODescriptor.read(numbytes)
        else:
            return self.IODescriptor.read()

    def write(self, string):
        self.IODescriptor.write(string)

    def close(self):
        self.IODescriptor.close()

    #READ BINARY NUMBER
    def rBool(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.BOOL_BYTES), Limits.BOOL_DTYPE)

    def rU8(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.UCHAR_BYTES), Limits.UCHAR_DTYPE)

    def rS8(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SCHAR_BYTES), Limits.SCHAR_DTYPE)

    def rU16(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.USHORT_BYTES), Limits.USHORT_DTYPE)

    def rS16(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SSHORT_BYTES), Limits.SSHORT_DTYPE)

    def rU32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.UINT_BYTES), Limits.UINT_DTYPE)

    def rS32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SINT_BYTES), Limits.SINT_DTYPE)

    def rU64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.ULONGINT_BYTES), Limits.ULONGINT_DTYPE)

    def rS64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SLONGINT_BYTES), Limits.SLONGINT_DTYPE)

    def rF32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.FLOAT_BYTES), Limits.FLOAT_DTYPE)

    def rF64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.DOUBLE_BYTES), Limits.DOUBLE_DTYPE)

    def rPackNum(self):
        value = self.rS8()
        if value == Limits.SCHAR_MIN:
            return self.rS32()
        else:
            return value

    #READ BINARY NUMBER
    def rbBool(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.BOOL_BYTES), Limits.BOOL_DTYPE_BIG)

    def rbU8(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.UCHAR_BYTES), Limits.UCHAR_DTYPE_BIG)

    def rbS8(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SCHAR_BYTES), Limits.SCHAR_DTYPE_BIG)

    def rbU16(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.USHORT_BYTES), Limits.UCHAR_DTYPE_BIG)

    def rbS16(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SSHORT_BYTES), Limits.SSHORT_DTYPE_BIG)

    def rbU32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.UINT_BYTES), Limits.UINT_DTYPE_BIG)

    def rbS32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SINT_BYTES), Limits.SINT_DTYPE_BIG)

    def rbU64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.ULONGINT_BYTES), Limits.ULONGINT_DTYPE_BIG)

    def rbS64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.SLONGINT_BYTES), Limits.SLONGINT_DTYPE_BIG)

    def rbF32(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.FLOAT_BYTES), Limits.FLOAT_DTYPE_BIG)

    def rbF64(self):
        return SuperStruct.UnpackSimple(self.IODescriptor.read(Limits.DOUBLE_BYTES), Limits.DOUBLE_DTYPE_BIG)
