from itertools import chain, combinations

def powerset(iterable):
    # yanked from https://docs.python.org/2/library/itertools.html
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def showlevels(lattice, cats):
    """Print all the succesors and predecessors of each level.
    """
    # curr_clr:     current cleareance
    # curr_cats:    current categories
    # succ_clr:     succesor clearance
    # succ_cats:    succesor categories
    # pred_clr:     predecessor clearance
    # pred_cat:     predecessor categories

    # iterate through all the possible (curr_clr, curr_cat)
    # combinations, where curr_cats is a member of the 
    # powerset of cats
    p = '    '
    for curr_clr, curr_node in lattice.items():
        for curr_cats in map(set, powerset(cats)):
            print 'Security Level = {0}'.format((curr_clr, curr_cats))

            #--- Succesors ---#
            print 'Succesors:' 
            # Current clearance level:
            # (curr_clr, curr_cats) > (curr_clr, succ_cats) if 
            # succ_cats is a proper subset (subset, but not equal) of curr_cats.
            for succ_cats in map(set, powerset(cats)):
                if curr_cats > succ_cats:
                    print '{0}{1}'.format(p, (curr_clr, succ_cats))
            # Succesor clearance level:
            # (curr_clr, curr_cats) > (succ_clrs, succ_cats) if
            # curr_clr > succ_clr and succ_cats is a subset of curr_cats.
            for succ_clr in curr_node.children:
                for succ_cats in map(set, powerset(cats)):
                    if curr_cats >= succ_cats:
                        print '{0}{1}'.format(p, (succ_clr, succ_cats))
            
            #--- Predecessors ---#
            print 'Predecessors:'
            # Current clearance level:
            # (curr_clr, curr_cats) < (curr_clr, pred_cats) if 
            # curr_cats is a proper subset (subset, but not equal) of pred_cats.
            for pred_cats in map(set, powerset(cats)):
                if curr_cats < pred_cats:
                    print '{0}{1}'.format(p, (curr_clr, pred_cats))
            # Predecessor clearance level:
            # (curr_clr, curr_cats) < (pred_clrs, pred_cats) if
            # curr_clr < pred_clr and curr_cats is a subset of pred_cats.
            for pred_clr in curr_node.parents:
                for pred_cats in map(set, powerset(cats)):
                    if curr_cats <= pred_cats:
                        print '{0}{1}'.format(p, (pred_clr, pred_cats))
            print
