#!/usr/bin/env python
#
#    make-worldconf: this file is part of the GRS suite
#    Copyright (C) 2015  Anthony G. Basile
#
#    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 3 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
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import configparser
import copy
import os
import re
import sys

from grs import CONST

from _emerge.main import parse_opts
from _emerge.actions import load_emerge_config, create_depgraph_params
from _emerge.depgraph import backtrack_depgraph


def useflags(config, p):
    # Get all IUSE, enabled USE and EXPAND_HIDDEN flags.
    try:
        iuse = list(p.iuse.all)
        use = list(p.use.enabled)
        # expand = list(p.use.expand)
        expand_hidden = list(p.use.expand_hidden)
    except AttributeError:
        return
    except TypeError:
        return

    # We only include select USE_EXPAND flags. Note becaue of how we match 'abi_',
    # for example, will match abi_ppc, abi_mips etc.  Hopefully this will not lead
    # to any false hits.
    expand = [ 'kernel_', 'elibc_', 'userland_', 'abi_', 'linguas_', 'python_' ]

    # Remove any selected USE_EXPAND and any EXPAND_HIDDEN flags from IUSE flags
    my_iuse = copy.deepcopy(iuse)
    for u in iuse:
        for e in expand + expand_hidden:
            while re.match(e, u):
                try:
                    my_iuse.remove(u)
                except ValueError:
                    break

    # Remove the same flags from the enabled USE flags
    my_use = copy.deepcopy(use)
    for u in use:
        for e in expand + expand_hidden:
            while re.match(e, u):
                try:
                    my_use.remove(u)
                except ValueError:
                    break

    # Remove the arch flag.
    # TODO: this needs to be generalized.
    my_use.remove('amd64')

    # Go through all the IUSE flags and put a - in front
    # of all the disabled USE flags.
    flags = []
    for i in my_iuse:
        if i in my_use:
            flags.append(i)
        else:
            flags.append('-%s' % i)

    # Insert nicely sorted flags.
    if len(flags) > 0:
        flags.sort()
        config[p.slot_atom]['package.use'] = p.slot_atom + ' ' + ' '.join(flags)


def keywords(config, p):
    # Stable means there is no keyword is needed.
    keyword = None
    try:
        if not p.stable:
            keyword = "??" # Something went wrong!
            if p.get_keyword_mask() == 'missing':
                keyword = '**'
            if p.get_keyword_mask() == 'unstable':
                # This needs to be generalized
                keyword = '~amd64'
    except AttributeError:
        pass
    if keyword:
        config[p.slot_atom]['package.accept_keywords'] = '=%s %s' % (p.cpv, keyword)


def from_etc_portage(config, p, subdir):
    # We could add better matching intelligence here so as to match
    # these subdirs+files for /etc/portage not maintained by GRS.
    fpath = os.path.join(CONST.PORTAGE_CONFIGDIR, '%s/%s' % \
        (subdir, re.sub('[/:]', '_', p.slot_atom)))
    if os.path.isfile(fpath):
        with open(fpath, 'r') as g:
            config[p.slot_atom][subdir] = g.read().strip()


def main():
    args = sys.argv[1:]
    if len(args) == 0:
        args =  [ '-e', '@world' ]

    myaction, myopts, myfiles = parse_opts(args, silent=True)
    emerge_config = load_emerge_config(action=myaction, args=myfiles, opts=myopts)
    mysettings, mytrees = emerge_config.target_config.settings, emerge_config.trees
    myparams = create_depgraph_params(myopts, myaction)
    success, mydepgraph, favorites = backtrack_depgraph(mysettings, mytrees, myopts, \
        myparams, myaction, myfiles, spinner=None)

    config = configparser.RawConfigParser(delimiters=':', allow_no_value=True, comment_prefixes=None)

    for p in mydepgraph.altlist():
        # Prepare an empty section for this atom
        try:
            config[p.slot_atom] = {}
        except AttributeError:
            continue

        # Populate package.use - these are read out of p
        useflags(config, p)

        # Populate package.accept_keywords - these are read out of p
        keywords(config, p)

        # Others - these are read out of /etc/portage
        from_etc_portage(config, p, 'package.mask')
        from_etc_portage(config, p, 'package.unmask')
        from_etc_portage(config, p, 'package.env')
        from_etc_portage(config, p, 'env')

        # Remove any empty sections
        if config[p.slot_atom] == {}:
            config.remove_section(p.slot_atom)

    # Recontruct a RawConfigParser from the above which has sorted sections.
    all_slot_atoms = config.sections()
    all_slot_atoms.sort()
    sorted_config = configparser.RawConfigParser(delimiters=':', allow_no_value=True, comment_prefixes=None)
    for s in all_slot_atoms:
        sorted_config[s] = config[s]

    with open('world.conf', 'w') as configfile:
        sorted_config.write(configfile)

if __name__ == "__main__":
    main()
