# Copyright 2012 David Mallows
#
# This file is part of dvipy.
# 
# Dvipy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# 
# Foobar is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with dvipy.  If not, see <http://www.gnu.org/licenses/>.

from newstream import *

def make_read(n, signed=True):
    assert n >= 1

    if signed:
        lim = 128 * (1 << 8 * (n - 1))
        sub = 2 * lim


    return ('''
def %s_%d(stream):
    # This function generated by genstream.py
    # **** do not edit it directly! ****
    total = next(stream)
    ''' % ('signed' if signed else 'unsigned', n) + '''
    total *= 256
    total += next(stream)''' * (n-1) + ('''

    return total
            ''' if not signed else '''

    # Convert to signed
    if total >= %d:
        total -= %d

    return total
           ''' % (lim, sub)))

#for i in xrange(1, 5):
#    print make_read(i, signed=False)

#for i in xrange(1, 5):
#    print make_read(i)


def fmt(*fields):
    names = [i.__name__ for i in fields]
    keywords = (', '.join('%s=%s' % (i,i) for i in set(names)))

    func = 'def fmt(stream, %s):\n' % keywords
    ind = '    '
    func += ind + 'return (\n'
    func += ',\n'.join(ind * 2 + i + "(stream)" for i in names)
    func += '\n' + 2*ind + ')'

    ns = dict(zip(names, fields))
    exec compile(func, '<string>', 'exec') in ns
    return ns['fmt']

from itertools import islice, imap

def read_string(stream, n):
    return ''.join(imap(chr, islice(stream, n)))

def read_bytes(stream, n):
    return bytearray(islice(stream, n))

def read_bytes_lazy(stream, n):
    return islice(stream, n)


def read_array(stream, typ, n):
    return [typ(stream) for _ in xrange(n)]



unsigned = (None, unsigned_1, unsigned_2, unsigned_3, unsigned_4)
signed = (None, signed_1, signed_2, signed_3, signed_4)

__all__ = ('fmt', 'signed', 'unsigned', 'read_string', 'read_array',
           'read_bytes', 'read_bytes_lazy')
