'''
Created on Oct 19, 2012

The elements of an mls specification
@author: carr
'''


from util.DirTree import DirTree
from util.SecurityLevelLattice import SecurityLevelLattice

from dtel import AssignOption

class MLSSpecification(object):


    def __init__(self,clearanceList,categorySet,assignDecls,userDecls):
        '''
        
        :param clearanceList: a list of security clearance levels
        :param categorySet: a set of possible categories for the clearance levels
        :param assignDecls: a list of assign statements in the specification
        :param userDecls: a list of user clearance declarations in the specification
        '''
 
        self.clearances = clearanceList
        self.categories = categorySet
        self.assignments = assignDecls
        
        self.userMap = dict() # a mapping from user name to the user declaration in the specification
        self.buildUserMap(userDecls)
        
        self.categoryPowerSet = self.powerset(self.categories) # a list the subsets of categorySet
                
        self.pathTree = DirTree() # a file system tree for the assign statements
  
        
        self.buildDirectoryTree()
        self.lattice = SecurityLevelLattice(self.clearances,self.categoryPowerSet) # build the lattice of clearnace, categorySet pairs
        
    def printLattice(self):
        '''
        print out the lattice to stdout in textual form
        '''
        self.lattice.printLattice()
        
    def printLatticeToFile(self, fileDir):
        self.lattice.printLatticeToFile(fileDir)

    def getClearances(self): return self.clearances
    def getCategories(self): return self.categories
    def getAssignments(self): return self.assignments
    def getUsers(self): return self.users
    
    
    def powerset(self,lst):
        '''
        Compute the set of all subsets of a list - taken from StackOverflow.com
        :param lst: a list with no duplicates
        '''
        return reduce(lambda result, x: result + [subset + [x] for subset in result], lst, [[]])

    

    def buildDirectoryTree(self) :
        '''
        Build the file system directory tree from the assign statements, then assign the clearance, categoryset pairs to the tree nodes
        This allows an incomplete specification
        '''

        ''' build directory tree '''
        
        for assign in self.assignments :

                self.pathTree.addPath(assign.getPath())
       
        ''' make type assignments '''
        
        for assign in self.assignments :
            
            if assign.isRecursive() :
                flags = AssignOption.RECURSIVE
            else :
                flags = 0
           
            self.pathTree.assignLevelToSubtree(assign.getPath(),assign.getSecurityLevelString(), flags)
            
    def buildUserMap(self,userDecls):
        '''
        Build a mapping from user names to the user declarations in the MLS specification
        :param userDecls: a list of user declarations from an MLS specification
        '''
        
        for user in userDecls :
            self.userMap[user.getUserId()] = user
            
