Calculates the label state of a given peptide for the label setup
    described in labelDescriptor

    :param peptide: peptide which label state should be calcualted
    :param labelDescriptor: :class:`LabelDescriptor`, describes the label setup
        of an experiment.
    :param labelSymbols: modifications that show a label, as returned by
        :func:`modSymbolsFromLabelInfo`.
    :param labelAminoacids: amino acids that can bear a label, as returned by
        :func:`modAminoacidsFromLabelInfo`.

    :returns: integer that shows the label state:
        >=0: predicted label state of the peptide
         -1: peptide sequence can't bear any labelState modifications
         -2: peptide modifications don't fit to any predicted labelState
         -3: peptide modifications fit to a predicted labelState, but not all
             predicted labelStates are distinguishable

def returnLabelState(peptide, labelDescriptor, labelSymbols=None,
                     labelAminoacids=None):
    """Calculates the label state of a given peptide for the label setup
    described in labelDescriptor

    :param peptide: peptide which label state should be calcualted
    :param labelDescriptor: :class:`LabelDescriptor`, describes the label setup
        of an experiment.
    :param labelSymbols: modifications that show a label, as returned by
        :func:`modSymbolsFromLabelInfo`.
    :param labelAminoacids: amino acids that can bear a label, as returned by
        :func:`modAminoacidsFromLabelInfo`.

    :returns: integer that shows the label state:
        >=0: predicted label state of the peptide
         -1: peptide sequence can't bear any labelState modifications
         -2: peptide modifications don't fit to any predicted labelState
         -3: peptide modifications fit to a predicted labelState, but not all
             predicted labelStates are distinguishable
    """
    if labelSymbols is None:
        labelSymbols = modSymbolsFromLabelInfo(labelDescriptor)
    if labelAminoacids is None:
        labelAminoacids = modAminoacidsFromLabelInfo(labelDescriptor)

    sequence = maspy.peptidemethods.removeModifications(peptide)
    modPositions = maspy.peptidemethods.returnModPositions(peptide,
                                                           indexStart=0,
                                                           removeModString=False)

    labelState = None
    #No amino acids in sequence which can bear a label modification
    #Note: at the moment presence of excluding modifications are ignored
    _validator = lambda seq, aa: (True if seq.find(aa) == -1 else False)
    if all([_validator(sequence, aa) for aa in labelAminoacids]):
        #No terminal label modifications specified by labelDescriptor
        if 'nTerm' not in labelAminoacids and 'cTerm' not in labelAminoacids:
            labelState = -1

    # Check if the peptide mofidifcations fit to any predicted label state
    if labelState is None:
        peptideLabelPositions = dict()
        for labelSymbol in labelSymbols:
            if labelSymbol in viewkeys(modPositions):
                for sequencePosition in modPositions[labelSymbol]:
                    peptideLabelPositions.setdefault(sequencePosition, list())
                    peptideLabelPositions[sequencePosition].append(labelSymbol)
        for sequencePosition in list(viewkeys(peptideLabelPositions)):
            peptideLabelPositions[sequencePosition] = \
                sorted(peptideLabelPositions[sequencePosition])

        predictedLabelStates = dict()
        for predictedLabelState, labelStateInfo in viewitems(labelDescriptor.labels):
            expectedLabelMods = expectedLabelPosition(peptide, labelStateInfo,
                                                      sequence=sequence,
                                                      modPositions=modPositions)
            predictedLabelStates[predictedLabelState] = expectedLabelMods
            if peptideLabelPositions == expectedLabelMods:
                #If another expectedLabel state has already been matched, then
                #there is an ambiguity between label states ...
                labelState = predictedLabelState

    if labelState is None:
        # Peptide mofidifcations don't fit to any predicted label state
        labelState = -2
    elif labelState != -1:
        # Check if all predicted label states are distinguishable
        _comb = set(itertools.combinations(range(len(predictedLabelStates)), 2))
        for state1, state2 in _comb:
            if predictedLabelStates[state1] == predictedLabelStates[state2]:
                labelState = -3
                break

    return labelState