    """
    Input buffering code for AsyncThreadedAppServer.

    This module creates a file interface to data being received through
    an asynconous socket.

    Based entirely on code contributed by Vladimir Kralik.
    Tweaked by Jay Love.

    """

    import string

    class ATASStreamIn:
        # methods to simulating read file-access to ayncore.dispatcher,
        # idea from StringIO

        def __init__(self, dispatcher, buffersize=8192):
            self._dispatcher=dispatcher
            self._buffersize=buffersize
            self.reset()

        def reset(self):
            self.len = 0
            self.buflist = []
            self.closed = 0
            self.softspace = 0
            self._hasMore=1     # in socket
            self._notQueued=1   # in request queue

        def dataAvailable(self):
            return not self._hasMore

        def canRecv(self):
            return self._hasMore and self._notQueued

        def recv(self):
            assert self._hasMore and self._notQueued

            data = self._dispatcher.recv(8192)
            lendata=len(data)
            self.len=self.len+lendata

            if lendata > 0:
                self.buflist.append(data)
            else:
                self.buflist.append(data)
                self._hasMore=0 # all is readed

            if self._hasMore and self.len < self._buffersize:
                pass
            else:
                self._notQueued=0
                self._dispatcher.server.requestQueue.put(self._dispatcher)

        # file access
        def close(self):
            if not self.closed:
                self.closed = 1
                del self.buflist, self.len

        def isatty(self):
            if self.closed:
                raise ValueError, "I/O operation on closed file"
            return 0

        def read(self, n = -1):
            assert not self._notQueued

            if self.closed:
                raise ValueError, "I/O operation on closed file"
            if n==0: return ''
            elif n < 0: # read all data
                if self._hasMore: # has more data in socket, read it
                    sock=self._dispatcher.socket
                    try :
                        sock.setblocking(1)
                        while 1:
                            data=sock.recv(8192)
                            if not data: break
                            self.buflist.append(data)
                    finally:
                        sock.setblocking(0)
                        self._hasMore=0
                return string.joinfields(self.buflist,'')
            elif self.buflist:
                outlist=[]
                outlen=0
                while self.buflist:
                    data=self.buflist.pop(0)
                    lendata=len(data)
                    outlen=outlen+lendata
                    if outlen>n: break
                    outlist.append(data)
                if outlen>n:
                    diff=n-outlen+lendata
                    outlist.append(data[:diff])
                    self.buflist.insert(0, data[diff:])
                elif self._hasMore and outlen<n:
                    outlist.append(self.read(n-outlen))
                return string.joinfields(outlist,'')
            elif self._hasMore:
                sock=self._dispatcher.socket
                try :
                    sock.setblocking(1)
                    data=sock.recv(n)
                finally:
                    sock.setblocking(0)
                    self._hasMore=0
                return data
            else: return ''

        def _readlinedata(self,data,length,outlist):
            i = string.find(data, '\n')
            if i<0: # not found
                if length and len(data)>=length:
                    i=length
                else:
                    outlist.append(data)
                    return (0,length and length-len(data))
            elif length and i>=length: i=length
            else: i=i+1

            dd=data[:i]
            outlist.append(dd)
            self.buflist.insert(0,data[i:])
            return (1,length and length-len(data)) # read all

        def readline(self, length=None):
            assert not self._notQueued
            if self.closed:
                raise ValueError, "I/O operation on closed file"

            if length==0: return ''
            elif self.buflist:
                outlist=[]
                while self.buflist:
                    data=self.buflist.pop(0)
                    con,length = self._readlinedata(
                        data,length,outlist)
                    if con: break
                if self._hasMore and not con:
                    outlist.append(self.readline(length))
                return string.joinfields(outlist,'')
            elif self._hasMore:
                sock=self._dispatcher.socket
                try :
                    outlist=[]
                    sock.setblocking(1)
                    while 1:
                        if self.buflist:data=self.buflist.pop(0)
                        else:
                            data=sock.recv(8192)
                            if not data:
                                self._hasMore=0
                                break
                        con,length = self._readlinedata(
                            data,length,outlist)
                        if con: break
                    return string.joinfields(outlist,'')
                finally:
                    sock.setblocking(0)
            else: return ''

        def readlines(self):
            lines = []
            line = self.readline()
            while line:
                lines.append(line)
                line = self.readline()
            return lines

        def flush(self):
            if self.closed:
                raise ValueError, "I/O operation on closed file"