code: /* LanguageTool, a natural language style checker 
   * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de)
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
   * USA
   */
  package org.languagetool.rules;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.ResourceBundle;
  import java.util.regex.Pattern;
  
  import org.languagetool.AnalyzedSentence;
  import org.languagetool.AnalyzedTokenReadings;
  import org.languagetool.Language;
  import org.languagetool.tools.Tools;
  
  /**
   * Check if to paragraphs begin with the same word.
   * If the first word is an article it checks if the first two words are identical
   * 
   * @author Fred Kruse
   * @since 4.1
   */
  public class ParagraphRepeatBeginningRule extends TextLevelRule {
  
    private static final Pattern QUOTES_REGEX = Pattern.compile("[’'\"„“”»«‚‘›‹()\\[\\]]");
  
    private final Language lang;
  
    public ParagraphRepeatBeginningRule(ResourceBundle messages, Language lang) {
      super(messages);
      super.setCategory(Categories.STYLE.getCategory(messages));
      this.lang = lang;
      setLocQualityIssueType(ITSIssueType.Style);
      setDefaultOff();
    }
  
    @Override
    public String getId() {
      return "PARAGRAPH_REPEAT_BEGINNING_RULE";
    }
  
    @Override
    public String getDescription() {
      return messages.getString("repetition_paragraph_beginning_desc");
    }
    
    public boolean isArticle(AnalyzedTokenReadings token) {
      return token.hasPosTagStartingWith("DT");
    }
    
    private int numCharEqualBeginning(AnalyzedTokenReadings[] lastTokens, AnalyzedTokenReadings[] nextTokens) {
      if(lastTokens.length < 2 || nextTokens.length < 2 
          || lastTokens[1].isWhitespace() || nextTokens[1].isWhitespace()) {
        return 0;
      }
      int nToken = 1;
      String lastToken = lastTokens[nToken].getToken();
      String nextToken = nextTokens[nToken].getToken();
      if (QUOTES_REGEX.matcher(lastToken).matches() && lastToken.equals(nextToken)) {
        if(lastTokens.length <= nToken + 1 || nextTokens.length <= nToken + 1) {
          return 0;
        }
        nToken++;
        lastToken = lastTokens[nToken].getToken();
        nextToken = nextTokens[nToken].getToken();
      }
      if(!Character.isLetter(lastToken.charAt(0))) {
        return 0;
      }
      if (lastTokens.length > nToken + 1 && isArticle(lastTokens[nToken]) && lastToken.equals(nextToken)) {
        if (nextTokens.length <= nToken + 1) {
          return 0;
        }
        nToken++;
        lastToken = lastTokens[nToken].getToken();
        nextToken = nextTokens[nToken].getToken();
      }
      if (!Character.isLetter(lastToken.charAt(0))) {
        return 0;
      }
      if (lastToken.equals(nextToken)) {
        return lastTokens[nToken].getEndPos();
      }
      return 0;
    }
  
    @Override
    public RuleMatch[] match(List<AnalyzedSentence> sentences) throws IOException {
  
      List<RuleMatch> ruleMatches = new ArrayList<>();
  
      if (sentences.size() < 1) {
        return toRuleMatchArray(ruleMatches);
      }
  
      int nextPos = 0;
      int lastPos = 0;
      int endPos;
      AnalyzedSentence lastSentence = sentences.get(0);
      AnalyzedTokenReadings[] lastTokens = lastSentence.getTokensWithoutWhitespace();
      AnalyzedSentence nextSentence;
      AnalyzedTokenReadings[] nextTokens;
      
      for (int n = 0; n < sentences.size() - 1; n++) {
        nextPos += sentences.get(n).getText().length();
        if(Tools.isParagraphEnd(sentences, n, lang)) {
          nextSentence = sentences.get(n + 1);
          nextTokens = nextSentence.getTokensWithoutWhitespace();
          endPos = numCharEqualBeginning(lastTokens, nextTokens);
          if (endPos > 0) {
            int startPos = lastPos + lastTokens[1].getStartPos();
            if (startPos < lastPos+endPos) {
              String msg = messages.getString("repetition_paragraph_beginning_last_msg");
              RuleMatch ruleMatch = new RuleMatch(this, lastSentence, startPos, lastPos+endPos, msg);
              ruleMatches.add(ruleMatch);
              
              startPos = nextPos + nextTokens[1].getStartPos();
              msg = messages.getString("repetition_paragraph_beginning_last_msg");
              ruleMatch = new RuleMatch(this, nextSentence, startPos, nextPos+endPos, msg);
              ruleMatches.add(ruleMatch);
            }
          }
          lastSentence = nextSentence;
          lastTokens = nextTokens;
          lastPos = nextPos;
        }
      }
      return toRuleMatchArray(ruleMatches);
    }
  
    @Override
    public int minToCheckParagraph() {
      return 1;
    }
  
  }  
  