# -*- coding: utf-8 -*-

from savate import helpers
from savate import looping


class StreamSource(looping.BaseIOEventHandler):

    # Incoming maximum buffer size
    RECV_BUFFER_SIZE = 64 * 2**10

    def __init__(self, server, sock, address, content_type, request_parser = None, path = None):
        self.server = server
        self.sock = sock
        self.address = address
        self.content_type = content_type
        self.request_parser = request_parser
        self.path = path or self.request_parser.request_path

    def __str__(self):
        return '<%s for %s, %s, %s>' % (
            self.__class__.__name__,
            self.path,
            self.address,
            self.content_type,
            )

    def close(self):
        self.server.remove_source(self)
        looping.BaseIOEventHandler.close(self)

    def recv_packet(self, buffer_size = RECV_BUFFER_SIZE):
        packet = helpers.handle_eagain(self.sock.recv, buffer_size)
        if packet:
            self.server.update_activity(self)
        return packet

    def handle_event(self, eventmask):
        if eventmask & looping.POLLIN:
            while True:
                packet = self.recv_packet(self.RECV_BUFFER_SIZE)
                if packet == None:
                    # EAGAIN
                    break
                elif packet == b'':
                    # End of stream
                    self.server.logger.warn('End of stream for %s', self)
                    self.close()
                    # FIXME: publish "EOS" packet
                    break
                else:
                    self.handle_packet(packet)
        else:
            self.server.logger.error('%s: unexpected eventmask %s', self, eventmask)

    def handle_packet(self, packet):
        # By default, we do nothing and directly feed it to
        # publish_packet(). This is meant to be overriden in
        # subclasses.
        self.publish_packet(packet)

    def publish_packet(self, packet):
        self.server.publish_packet(self, packet)

    def new_client(self, client):
        # Do nothing by default
        pass


class BufferedRawSource(StreamSource):

    # Temporary buffer size
    TEMP_BUFFER_SIZE = 64 * 2**10

    # Size of initial data burst for clients
    BURST_SIZE = 64 * 2**10

    def __init__(self, server, sock, address, content_type, request_parser = None , path = None):
        StreamSource.__init__(self, server, sock, address, content_type, request_parser, path)
        if request_parser:
            self.output_buffer_data = request_parser.body
        else:
            self.output_buffer_data = ''
        self.burst_packets = helpers.BurstQueue(self.BURST_SIZE)

    def handle_packet(self, packet):
        self.output_buffer_data = self.output_buffer_data + packet
        if len(self.output_buffer_data) >= self.TEMP_BUFFER_SIZE:
            self.publish_packet(self.output_buffer_data)
            self.burst_packets.append(self.output_buffer_data)
            self.output_buffer_data = ''

    def new_client(self, client):
        for packet in self.burst_packets:
            client.add_packet(packet)


class FixedPacketSizeSource(BufferedRawSource):

    def handle_packet(self, packet):
        self.output_buffer_data = self.output_buffer_data + packet
        if len(self.output_buffer_data) >= self.TEMP_BUFFER_SIZE:
            nb_packets, remaining_bytes = divmod(len(self.output_buffer_data),
                                                 self.PACKET_SIZE)
            if remaining_bytes:
                tmp_data = self.output_buffer_data[:(nb_packets * self.PACKET_SIZE)]
                self.output_buffer_data = self.output_buffer_data[-remaining_bytes:]
            else:
                tmp_data = self.output_buffer_data
                self.output_buffer_data = ''
            self.publish_packet(tmp_data)
            self.burst_packets.append(tmp_data)

class MPEGTSSource(FixedPacketSizeSource):

    MPEGTS_PACKET_SIZE = 188
    PACKET_SIZE = MPEGTS_PACKET_SIZE

    # Incoming maximum buffer size; 188 * 7 = 1316 is the largest
    # multiple of 188 that is smaller than the typical MTU size of
    # 1500
    RECV_BUFFER_SIZE = 7 * MPEGTS_PACKET_SIZE

    TEMP_BUFFER_SIZE = 50 * RECV_BUFFER_SIZE
    BURST_SIZE = 50 * RECV_BUFFER_SIZE


# Note that recvmmsg() requires Linux >= 2.6.33 and glibc >= 2.12
# FIXME: add a configuration option
try:
    from savate.recvmmsg import recvmmsg

    class MPEGTSSource(MPEGTSSource):
        """
        A specialised MPEG-TS over UDP input class that uses
        recvmmsg() to provide a more efficient alternative than
        multiple recv() calls.
        """

        RECV_BUFFER_COUNT_MIN = 1
        RECV_BUFFER_COUNT_MAX = 512

        def __init__(self, server, sock, address, content_type, request_parser = None, path = None):
            super(MPEGTSSource, self).__init__(server, sock, address, content_type, request_parser, path)
            self.recv_buffer_count = self.RECV_BUFFER_COUNT_MIN

        def recv_packet(self, _buffer_size = None):
            # We ignore _buffer_size altogether here
            buffers = [bytearray(self.RECV_BUFFER_SIZE) for i in range(self.recv_buffer_count)]
            buffers = helpers.handle_eagain(recvmmsg, self.sock.fileno(), buffers) or ()
            # Automagically grow/shrink the buffer count as needed
            if len(buffers) >= self.recv_buffer_count:
                self.recv_buffer_count = min(self.recv_buffer_count * 2, self.RECV_BUFFER_COUNT_MAX)
            else:
                self.recv_buffer_count = max(len(buffers), self.RECV_BUFFER_COUNT_MIN)
            if buffers:
                self.server.update_activity(self)
                return bytearray('').join(buffers)
            else:
                return None

except ImportError:
    # recvmmsg() is not available, we'll use regular recv() instead
    pass


from savate.flv_source import FLVSource

sources_mapping = {
    b'video/x-flv': FLVSource,
    b'application/x-flv': FLVSource,
    b'audio/x-hx-aac-adts': BufferedRawSource,
    b'application/octet-stream': BufferedRawSource,
    b'video/MP2T': MPEGTSSource,
    }

@@ -6027,55 +6027,8 @@
 ce,%0A
-    b'audio/x-hx-aac-adts': BufferedRawSource,%0A
     

remove dubious, unused "audio/x-hx-aac-adts" Content-Type