def detectVerbChainsFromSent( self, sentence, **kwargs):
        ''' Detect verb chains from given sentence.

        Parameters
        ----------
        sentence:  list of dict
            A list of sentence words, each word in form of a dictionary containing 
            morphological analysis and clause boundary annotations (must have CLAUSE_IDX);
        
        Keyword parameters
        ------------------
        expand2ndTime: boolean
            If True, regular verb chains (chains not ending with 'olema') are expanded twice.
            (default: False)
        breakOnPunctuation: boolean
            If True, expansion of regular verb chains will be broken in case of intervening punctuation.
            (default: False)
        removeSingleAraEi: boolean
            if True, verb chains consisting of a single word, 'ära' or 'ei', will be removed.
            (default: True)
        removeOverlapping: boolean
            If True, overlapping verb chains will be removed.
            (default: True)

        Returns
        -------
        list of dict
            List of detected verb chains, each verb chain has following attributes (keys):
             PHRASE      -- list of int : indexes pointing to elements in sentence that belong 
                                            to the chain;
             PATTERN     -- list of str : for each word in phrase, marks whether it is 'ega', 'ei', 
                                            'ära', 'pole', 'ole', '&' (conjunction: ja/ning/ega/või) 
                                            'verb' (verb different than 'ole') or 'nom/adv';
             ANALYSIS_IDS -- list of (list of int) : for each word in phrase, points to index(es) of 
                                                      morphological analyses that correspond to words
                                                      in the verb chains;
             ROOTS       -- list of str : for each word in phrase, lists its corresponding ROOT 
                                            value from the morphological analysis; e.g. for the verb
                                            chain 'püüab kodeerida', the ROOT will be ['püüd', 
                                            'kodeeri'];
             MORPH       -- list of str : for each word in phrase, lists its part-of-speech value 
                                            and morphological form (in one string, separated by '_',
                                            and multiple variants of the pos/form separated by '/'); 
                                            e.g. for the verb chain 'on tulnud', the MORPH value 
                                            will be ['V_vad/b', 'V_nud'];
             OTHER_VERBS  -- bool : whether there are other verbs in the context, potentially being 
                                     part of the verb chain; if this is True, it is uncertain whether 
                                     the chain is complete or not;
             
             POLARITY     -- 'POS', 'NEG' or '??' : grammatical polarity of the verb chain; Negative
                                                    polarity indicates that the verb phrase begins 
                                                    with 'ei', 'ega', 'ära' or 'pole'; 
             TENSE        -- tense of the main verb:  'present', 'imperfect', 'perfect', 
                                                              'pluperfect', 'past', '??';
             MOOD         -- mood of the main verb:   'indic', 'imper', 'condit', 'quotat', '??';
             VOICE        -- voice of the main verb:  'personal', 'impersonal', '??';

        '''
        # 0) Parse given arguments
        expand2ndTime = False
        removeOverlapping  = True
        removeSingleAraEi  = True
        breakOnPunctuation = False
        for argName, argVal in kwargs.items():
            if argName == 'expand2ndTime':
                expand2ndTime = bool(argVal)
            elif argName == 'removeOverlapping':
                removeOverlapping = bool(argVal)
            elif argName == 'removeSingleAraEi':
                removeSingleAraEi = bool(argVal)
            elif argName == 'breakOnPunctuation':
                breakOnPunctuation = bool(argVal)
            else:
                raise Exception(' Unsupported argument given: '+argName)

        # 1) Preprocessing
        sentence = addWordIDs( sentence )
        clauses  = getClausesByClauseIDs( sentence )

        # 2) Extract predicate-centric verb chains within each clause
        allDetectedVerbChains = []
        for clauseID in clauses:
            clause   = clauses[clauseID]

            # 2.1) Extract predicate-centric verb chains within each clause
            detectedBasicChains = _extractBasicPredicateFromClause(clause, clauseID)
            allDetectedVerbChains.extend( detectedBasicChains )
            
            # 2.2) Extract 'saama' + 'tud' verb phrases (typically rare)
            _expandSaamaWithTud( clause, clauseID, allDetectedVerbChains )

            # 2.3) Extend 'olema' chains with 'nud/tud/mas/mata' verbs (if possible)
            _expandOlemaVerbChains( clause, clauseID, allDetectedVerbChains )
            
            # 2.4) Expand non-olema verb chains inside the clause where possible (verb+verb chains)
            _expandVerbChainsBySubcat( clause, clauseID, allDetectedVerbChains, self.verbInfSubcatLexicon, False, breakOnPunctuation)

            # 2.5) Determine for which verb chains the context should be clear
            #    (no additional verbs can be added to the phrase)
            _determineVerbChainContextualAmbiguity( clause, clauseID, allDetectedVerbChains)
            
            # 2.6) Expand non-olema verb chains inside the clause 2nd time (verb+verb+verb chains)
            #      (Note that while verb+verb+verb+verb+...  chains are also possible, three verbs 
            #       seems to be a critical length: longer chains are rare and thus making longer 
            #       chains will likely lead to errors);
            if expand2ndTime:
                _expandVerbChainsBySubcat( clause, clauseID, allDetectedVerbChains, self.verbInfSubcatLexicon, False, breakOnPunctuation)
            
        # 3) Extract 'ega' negations (considering the whole sentence context)
        expandableEgaFound = _extractEgaNegFromSent( sentence, clauses, allDetectedVerbChains )

        if expandableEgaFound:
            for clauseID in clauses:
                clause = clauses[clauseID]
                # 3.1) Expand non-olema 'ega' verb chains inside the clause, if possible;
                _expandVerbChainsBySubcat( clause, clauseID, allDetectedVerbChains, self.verbInfSubcatLexicon, False, breakOnPunctuation)
            
            #_debugPrint(' | '+getJsonAsTextString(sentence, markTokens = [ verbObj[PHRASE] for verbObj in allDetectedVerbChains ]))

        # 4) Extend chains with nom/adv + Vinf relations
        if self.verbNomAdvVinfExtender:
            addGrammaticalFeatsAndRoots( sentence, allDetectedVerbChains )
            for clauseID in clauses:
                clause = clauses[clauseID]
                expansionPerformed = \
                    self.verbNomAdvVinfExtender.extendChainsInClause( clause, clauseID, allDetectedVerbChains )
                if expansionPerformed:
                    _determineVerbChainContextualAmbiguity( clause, clauseID, allDetectedVerbChains)
        
        # ) Remove redundant and overlapping verb phrases
        removeRedundantVerbChains( allDetectedVerbChains, removeOverlapping = removeOverlapping, removeSingleAraAndEi = removeSingleAraEi )

        # ) Add grammatical features (in the end)
        addGrammaticalFeatsAndRoots( sentence, allDetectedVerbChains )

        return allDetectedVerbChains