#!/usr/bin/env python

# 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
# along with this program; if not, write to the Free Software Foundation.
#
# Copyright (C) 2013 Wind River Systems, Inc.
# Copyright (C) 2014 Intel Corporation
#
# - list available recipes which have PACKAGECONFIG flags
# - list available PACKAGECONFIG flags and all affected recipes
# - list all recipes and PACKAGECONFIG information

import sys
import optparse
import os


scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0])))
lib_path = os.path.abspath(scripts_path + '/../lib')
sys.path = sys.path + [lib_path]

import scriptpath

# For importing the following modules
bitbakepath = scriptpath.add_bitbake_lib_path()
if not bitbakepath:
    sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n")
    sys.exit(1)

import bb.cache
import bb.cooker
import bb.providers
import bb.tinfoil

def get_fnlist(bbhandler, pkg_pn, preferred):
    ''' Get all recipe file names '''
    if preferred:
        (latest_versions, preferred_versions) = bb.providers.findProviders(bbhandler.config_data, bbhandler.cooker.recipecache, pkg_pn)

    fn_list = []
    for pn in sorted(pkg_pn):
        if preferred:
            fn_list.append(preferred_versions[pn][1])
        else:
            fn_list.extend(pkg_pn[pn])

    return fn_list

def get_recipesdata(bbhandler, preferred):
    ''' Get data of all available recipes which have PACKAGECONFIG flags '''
    pkg_pn = bbhandler.cooker.recipecache.pkg_pn

    data_dict = {}
    for fn in get_fnlist(bbhandler, pkg_pn, preferred):
        data = bb.cache.Cache.loadDataFull(fn, bbhandler.cooker.collection.get_file_appends(fn), bbhandler.config_data)
        flags = data.getVarFlags("PACKAGECONFIG")
        flags.pop('doc', None)
        if flags:
            data_dict[fn] = data

    return data_dict

def collect_pkgs(data_dict):
    ''' Collect available pkgs in which have PACKAGECONFIG flags '''
    # pkg_dict = {'pkg1': ['flag1', 'flag2',...]}
    pkg_dict = {}
    for fn in data_dict:
        pkgconfigflags = data_dict[fn].getVarFlags("PACKAGECONFIG")
        pkgconfigflags.pop('doc', None)
        pkgname = data_dict[fn].getVar("P", True)
        pkg_dict[pkgname] = sorted(pkgconfigflags.keys())

    return pkg_dict

def collect_flags(pkg_dict):
    ''' Collect available PACKAGECONFIG flags and all affected pkgs '''
    # flag_dict = {'flag': ['pkg1', 'pkg2',...]}
    flag_dict = {}
    for pkgname, flaglist in pkg_dict.iteritems():
        for flag in flaglist:
            if flag in flag_dict:
                flag_dict[flag].append(pkgname)
            else:
                flag_dict[flag] = [pkgname]

    return flag_dict

def display_pkgs(pkg_dict):
    ''' Display available pkgs which have PACKAGECONFIG flags '''
    pkgname_len = len("RECIPE NAME") + 1
    for pkgname in pkg_dict:
        if pkgname_len < len(pkgname):
            pkgname_len = len(pkgname)
    pkgname_len += 1

    header = '%-*s%s' % (pkgname_len, str("RECIPE NAME"), str("PACKAGECONFIG FLAGS"))
    print header
    print str("").ljust(len(header), '=')
    for pkgname in sorted(pkg_dict):
        print('%-*s%s' % (pkgname_len, pkgname, ' '.join(pkg_dict[pkgname])))


def display_flags(flag_dict):
    ''' Display available PACKAGECONFIG flags and all affected pkgs '''
    flag_len = len("PACKAGECONFIG FLAG") + 5

    header = '%-*s%s' % (flag_len, str("PACKAGECONFIG FLAG"), str("RECIPE NAMES"))
    print header
    print str("").ljust(len(header), '=')

    for flag in sorted(flag_dict):
        print('%-*s%s' % (flag_len, flag, '  '.join(sorted(flag_dict[flag]))))

def display_all(data_dict):
    ''' Display all pkgs and PACKAGECONFIG information '''
    print str("").ljust(50, '=')
    for fn in data_dict:
        print('%s' % data_dict[fn].getVar("P", True))
        print fn
        packageconfig = data_dict[fn].getVar("PACKAGECONFIG", True) or ''
        if packageconfig.strip() == '':
            packageconfig = 'None'
        print('PACKAGECONFIG %s' % packageconfig)

        for flag,flag_val in data_dict[fn].getVarFlags("PACKAGECONFIG").iteritems():
            if flag == "doc":
                continue
            print('PACKAGECONFIG[%s] %s' % (flag, flag_val))
        print ''

def main():
    pkg_dict = {}
    flag_dict = {}

    # Collect and validate input
    parser = optparse.OptionParser(
        description = "Lists recipes and PACKAGECONFIG flags. Without -a or -f, recipes and their available PACKAGECONFIG flags are listed.",
        usage = """
    %prog [options]""")

    parser.add_option("-f", "--flags",
            help = "list available PACKAGECONFIG flags and affected recipes",
            action="store_const", dest="listtype", const="flags", default="recipes")
    parser.add_option("-a", "--all",
            help = "list all recipes and PACKAGECONFIG information",
            action="store_const", dest="listtype", const="all")
    parser.add_option("-p", "--preferred-only",
            help = "where multiple recipe versions are available, list only the preferred version",
            action="store_true", dest="preferred", default=False)

    options, args = parser.parse_args(sys.argv)

    bbhandler = bb.tinfoil.Tinfoil()
    bbhandler.prepare()
    print("Gathering recipe data...")
    data_dict = get_recipesdata(bbhandler, options.preferred)

    if options.listtype == 'flags':
        pkg_dict = collect_pkgs(data_dict)
        flag_dict = collect_flags(pkg_dict)
        display_flags(flag_dict)
    elif options.listtype == 'recipes':
        pkg_dict = collect_pkgs(data_dict)
        display_pkgs(pkg_dict)
    elif options.listtype == 'all':
        display_all(data_dict)

if __name__ == "__main__":
    main()
