# Copyright 1999-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

import collections
from itertools import chain

from portage.output import red
from portage.util import cmp_sort_key
from portage.output import blue


class UseFlagDisplay:
    __slots__ = ("name", "enabled", "forced")

    def __init__(self, name, enabled, forced):
        self.name = name
        self.enabled = enabled
        self.forced = forced

    def __str__(self):
        s = self.name
        if self.enabled:
            s = red(s)
        else:
            s = "-" + s
            s = blue(s)
        if self.forced:
            s = f"({s})"
        return s

    def _cmp_combined(a, b):
        """
        Sort by name, combining enabled and disabled flags.
        """
        return (a.name > b.name) - (a.name < b.name)

    sort_combined = cmp_sort_key(_cmp_combined)
    del _cmp_combined

    def _cmp_separated(a, b):
        """
        Sort by name, separating enabled flags from disabled flags.
        """
        enabled_diff = b.enabled - a.enabled
        if enabled_diff:
            return enabled_diff
        return (a.name > b.name) - (a.name < b.name)

    sort_separated = cmp_sort_key(_cmp_separated)
    del _cmp_separated


_flag_info = collections.namedtuple("_flag_info", ("flag", "display"))


def pkg_use_display(pkg, opts, modified_use=None):
    settings = pkg.root_config.settings
    use_expand = pkg.use.expand
    use_expand_hidden = pkg.use.expand_hidden
    alphabetical_use = "--alphabetical" in opts
    forced_flags = set(chain(pkg.use.force, pkg.use.mask))
    if modified_use is None:
        use = set(pkg.use.enabled)
    else:
        use = set(modified_use)
    use.discard(settings.get("ARCH"))
    use_expand_flags = set()
    use_enabled = {}
    use_disabled = {}
    for varname in use_expand:
        flag_prefix = varname.lower() + "_"
        for f in use:
            if f.startswith(flag_prefix):
                use_expand_flags.add(f)
                use_enabled.setdefault(varname.upper(), []).append(
                    _flag_info(f, f[len(flag_prefix) :])
                )

        for f in pkg.iuse.all:
            if f.startswith(flag_prefix):
                use_expand_flags.add(f)
                if f not in use:
                    use_disabled.setdefault(varname.upper(), []).append(
                        _flag_info(f, f[len(flag_prefix) :])
                    )

    var_order = set(use_enabled)
    var_order.update(use_disabled)
    var_order = sorted(var_order)
    var_order.insert(0, "USE")
    use.difference_update(use_expand_flags)
    use_enabled["USE"] = list(_flag_info(f, f) for f in use)
    use_disabled["USE"] = []

    for f in pkg.iuse.all:
        if f not in use and f not in use_expand_flags:
            use_disabled["USE"].append(_flag_info(f, f))

    flag_displays = []
    for varname in var_order:
        if varname.lower() in use_expand_hidden:
            continue
        flags = []
        for f in use_enabled.get(varname, []):
            flags.append(UseFlagDisplay(f.display, True, f.flag in forced_flags))
        for f in use_disabled.get(varname, []):
            flags.append(UseFlagDisplay(f.display, False, f.flag in forced_flags))
        if alphabetical_use:
            flags.sort(key=UseFlagDisplay.sort_combined)
        else:
            flags.sort(key=UseFlagDisplay.sort_separated)
        flag_displays.append(f"{varname}=\"{' '.join(f'{f}' for f in flags)}\"")

    return " ".join(flag_displays)
