#!/usr/bin/env python
# This is a modified version of gencontrol.py of the Debian kernel team
# Thanks to the Debian Kernel Team for their work.
# This program generates a proper control file on debian directory
# It need the proper linux-header-2.6.X package installed. There is
# a soft link on debian/arch point to /usr/linux-header-2.6.14/debian/arch
#
# Copyright by
# Debian Kernel Team <debian-kernel@lists.debian.org> 
# Victor Seva Lopez <linuxmaniac@torreviejawireless.org>
# License:
#
# This program 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.
#
# This program 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 with
# the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL;
# if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA  02111-1307  USA
#
# See /usr/share/common-licenses/GPL for the full text of the GPL.
import os, os.path, re, sys, textwrap, ConfigParser
sys.path.append("lib")
from debian_linux import *

class packages_list(sorted_dict):
    def append(self, package):
        self[package['Package']] = package

    def extend(self, packages):
        for package in packages:
            self[package['Package']] = package

def read_changelog():
    r = re.compile(r"""
^
(
(?P<header>
    (?P<header_source>
        \w[-+0-9a-z.]+
    )
    \ 
    \(
    (?P<header_version>
        [^\(\)\ \t]+
    )
    \)
    \s+
    (?P<header_distribution>
        [-0-9a-zA-Z]+
    )
    \;
)
)
""", re.VERBOSE)
    f = file("changelog")
    entries = []
    act_upstream = None
    while True:
        line = f.readline()
        if not line:
            break
        line = line.strip('\n')
        match = r.match(line)
        if not match:
            continue
        if match.group('header'):
            e = entry()
            e['Distribution'] = match.group('header_distribution')
            e['Source'] = match.group('header_source')
            version = parse_version(match.group('header_version'))
            e['Version'] = version
            if act_upstream is None:
                act_upstream = version['upstream']
            elif version['upstream'] != act_upstream:
                break
            entries.append(e)
    return entries

def read_rfc822(f):
    entries = []

    while True:
        e = entry()
        while True:
            line = f.readline()
            if not line:
                break
            line = line.strip('\n')
            if not line:
                break
            if line[0] in ' \t':
                if not last:
                    raise ValueError('Continuation line seen before first header')
                e[last] += '\n' + line.lstrip()
                continue
            i = line.find(':')
            if i < 0:
                raise ValueError("Not a header, not a continuation: ``%s''" % line)
            last = line[:i]
            e[last] = line[i+1:].lstrip()
        if not e:
            break

        entries.append(e)

    return entries

def read_template(name):
    return read_rfc822(file("templates/control.%s.in" % name))

def parse_version(version):
    version_re = ur"""
^
(?P<source>
    (?P<parent>
        \d+\.\d+\.\d+\+
    )?
    (?P<upstream>
        (?P<version>
            (?P<major>\d+\.\d+)
            \.
            \d+
        )
        (?:
            -
            (?P<modifier>
                .+?
            )
        )?
    )
    -
    (?P<debian>[^-]+)
)
$
"""
    match = re.match(version_re, version, re.X)
    ret = match.groupdict()
    if ret['parent'] is not None:
        ret['source_upstream'] = ret['parent'] + ret['upstream']
    else:
        ret['source_upstream'] = ret['upstream']
    return ret

def process_changelog(in_vars, config, changelog):
    ret = [None, None, None, None]
    ret[0] = version = changelog[0]['Version']
    vars = in_vars.copy()
    if version['modifier'] is not None:
        ret[1] = vars['abiname'] = version['modifier']
        ret[2] = ""
    else:
        ret[1] = vars['abiname'] = config['base']['abiname']
        ret[2] = "-%s" % vars['abiname']
    vars['version'] = version['version']
    vars['major'] = version['major']
    ret[3] = vars
    return ret

def process_depends(key, e, in_e, vars):
    in_dep = in_e[key].split(',')
    dep = []
    for d in in_dep:
        d = d.strip()
        d = substitute(d, vars)
        if d:
            dep.append(d)
    if dep:
        t = ', '.join(dep)
        e[key] = t

def process_description(e, in_e, vars):
    desc = in_e['Description']
    desc_short, desc_long = desc.split ("\n", 1)
    desc_pars = [substitute(i, vars) for i in desc_long.split ("\n.\n")]
    desc_pars_wrapped = []
    w = wrap(width = 74, fix_sentence_endings = True)
    for i in desc_pars:
        desc_pars_wrapped.append(w.fill(i))
    e['Description'] = "%s\n%s" % (substitute(desc_short, vars), '\n.\n'.join(desc_pars_wrapped))

def process_package(in_entry, vars):
    e = entry()
    for i in in_entry.iterkeys():
        if i in (('Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts')):
            process_depends(i, e, in_entry, vars)
        elif i == 'Description':
            process_description(e, in_entry, vars)
        elif i[:2] == 'X-':
            pass
        else:
            e[i] = substitute(in_entry[i], vars)
    return e

def process_packages(in_entries, vars):
    entries = []
    for i in in_entries:
        entries.append(process_package(i, vars))
    return entries

def process_real_image(in_entry, vars):
    in_entry = in_entry.copy()
    if vars.has_key('desc'):
        in_entry['Description'] += "\n.\n" + vars['desc']
    entry = process_package(in_entry, vars)
    for i in (('Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts')):
        value = []
        tmp = entry.get(i, None)
        if tmp:
            tmp = tmp.split(',')
            for t in tmp:
                value.append(t.strip())
        if i == 'Depends':
            t = vars.get('depends', None)
            if t is not None:
                value.append(t)
        elif i == 'Provides':
            t = vars.get('provides', None)
            if t is not None:
                value.append(t)
        elif i == 'Suggests':
            t = vars.get('suggests', None)
            if t is not None:
                value.append(t)
        elif i == 'Recommends':
            t = vars.get('recommends', None)
            if t is not None:
                value.append(t)
        elif i == 'Conflicts':
            t = vars.get('conflicts', None)
            if t is not None:
                value.append(t)
        entry[i] = ', '.join(value)
    return entry

def process_real_tree(in_entry, changelog, vars):
    entry = process_package(in_entry, vars)
    tmp = changelog[0]['Version']['upstream']
    versions = []
    for i in changelog:
        if i['Version']['upstream'] != tmp:
            break
        versions.insert(0, i['Version'])
    for i in (('Depends', 'Provides')):
        value = []
        tmp = entry.get(i, None)
        if tmp:
            value.extend([j.strip() for j in tmp.split(',')])
        if i == 'Depends':
            value.append("linux-patch-debian-%(version)s (= %(source)s)" % changelog[0]['Version'])
            value.append(' | '.join(["linux-source-%(version)s (= %(source)s)" % v for v in versions]))
        elif i == 'Provides':
            value.extend(["linux-tree-%(source)s" % v for v in versions])
        entry[i] = ', '.join(value)
    return entry

def substitute(s, vars):
    def subst(match):
        return vars[match.group(1)]
    return re.sub(r'@([a-z_]+)@', subst, s)

def write_control(list):
    write_rfc822(file("control", 'w'), list)

def write_makefile(list):
    f = file("rules.gen", 'w')
    for i in list:
        f.write("%s\n" % i[0])
        if i[1] is not None:
            list = i[1]
            if isinstance(list, basestring):
                list = list.split('\n')
            for j in list:
                f.write("\t%s\n" % j)

def write_rfc822(f, list):
    for entry in list:
        for key, value in entry.iteritems():
            f.write("%s:" % key)
            if isinstance(value, tuple):
                value = value[0].join(value[1])
            for k in value.split('\n'):
              f.write(" %s\n" % k)
        f.write('\n')

def process_real_arch(packages, config, arch, vars):
    config_entry = config[arch,]
    vars.update(config_entry)

    if not config_entry.get('available', True):
        return

    for subarch in config_entry['subarches']:
        process_real_subarch(packages, config, arch, subarch, vars.copy() )

def process_real_flavour(packages, config, arch, subarch, flavour, vars ):
    config_entry = config[arch, subarch, flavour]
    vars.update(config_entry)

    vars['flavour'] = flavour
    if not vars.has_key('class'):
        vars['class'] = '%s-class' % flavour
    if not vars.has_key('longclass'):
        vars['longclass'] = vars['class']

    module = read_template("modules")

    packages_own = []
    packages_own.append(process_package(module[0], vars))

    for package in packages_own:
        name = package['Package']
        if packages.has_key(name):
            package = packages.get(name)
            package['Architecture'][1].append(arch)
        else:
            package['Architecture'] = (' ', [arch])
            packages.append(package)

def process_real_main(packages, config, version, abiname, kpkg_abiname, changelog, vars):
    source = read_template("source")
    packages['source'] = process_package(source[0], vars)

    common = read_template("common")
    packages.extend(process_packages(common, vars))

    for arch in iter(config['base']['arches']):
        process_real_arch(packages, config, arch, vars.copy())

def process_real_subarch(packages, config, arch, subarch, vars ):
    if subarch == 'none':
        vars['subarch'] = ''
    else:
        vars['subarch'] = '%s-' % subarch

    config_entry = config[arch, subarch]
    vars.update(config_entry)

    for flavour in config_entry['flavours']:
        process_real_flavour(packages, config, arch, subarch, flavour, vars.copy() )

def main():
    changelog = read_changelog()

    c = config()

    version, abiname, kpkg_abiname, vars = process_changelog({}, c, changelog)

    packages = packages_list()

    process_real_main(packages, c, version, abiname, kpkg_abiname, changelog, vars)

    write_control(packages.itervalues())


if __name__ == '__main__':
    main()
