class ModelSelection(object):
    """
    Applicable models for MRStandpoint objects
    Only models that are not exhausted and have not been tried are returned
    """

    def is_exhausted(self, standpoint, component):

        if component.has_count():
            components = [
                m.component() for m in standpoint.solution().ensembles()
                ]
            return component.count() <= components.count( component )
        
        else:
            return False
        
        
    def has_been_tried(self, standpoint, ensemble):
        
        return (
            ensemble in [ mrn.lead() for mrn in standpoint.successors() ]
            )
    
    
    def active_ensembles(self, standpoint, ensembles):
        
        components = set( [ m.component() for m in ensembles ] )
        exhausteds = set(
            [ c for c in components if self.is_exhausted( standpoint, c ) ]
            )
        
        return [ m for m in ensembles if (
            not self.has_been_tried( standpoint, m )
            and ( m.component() not in exhausteds )
            ) ]
        
        
    def select(self, standpoint, ensembles):
        
        return [ e for e in self.active_ensembles( standpoint, ensembles )
            if self.applicable( standpoint, e ) ]


class ContinueWithCurrent(ModelSelection):
    """
    Continue extension with current model
    """
    
    def applicable(self, standpoint, ensemble):
        
        if ensemble == standpoint.lead():
            return True
        
        else:
            return False
        
        
class SwitchModel(ModelSelection):
    """
    Switches back to models that were used before
    """
    
    def applicable(self, standpoint, model):
        
        if model in standpoint.solution().ensembles():
            return True
        
        else:
            return False
         

class StartNewComponent(ModelSelection):
    """
    Starts searching with new component
    """
    
    def applicable(self, standpoint, model):
        
        used_components = set(
            [ m.component() for m in standpoint.solution().ensembles() ]
            )
        
        if model.component() not in used_components:
            return True
        
        else:
            return False
