class UnnecessaryPhraseRule extends AbstractStatisticStyleRule {
  
  private static final int DEFAULT_MIN_PER_MILL = 8;

  private static final String[][] unnecessaryPhrases = { new String[] { "dann", "und", "wann" },
                                                       new String[] { "des", "Ungeachtet" },
                                                       new String[] { "ganz", "und", "gar" },
                                                       new String[] { "hie", "und","da" },
                                                       new String[] { "im", "Allgemeinen"},
                                                       new String[] { "in", "der", "Tat" },
                                                       new String[] { "in", "diesem", "Zusammenhang" },
                                                       new String[] { "mehr", "oder", "weniger" },
                                                       new String[] { "meines", "Erachtens" },
                                                       new String[] { "ohne", "weiteres" },
                                                       new String[] { "ohne", "Zweifel" },
                                                       new String[] { "samt", "und", "sonders"},
                                                       new String[] { "sowohl", "als", "auch" },
                                                       new String[] { "voll", "und", "ganz" },
                                                       new String[] { "von", "Neuem" },
                                                       new String[] { "allem", "Anschein", "nach" },
                                                       new String[] { "aufs", "Neue" },
                                                       new String[] { "ein", "bisschen" },
                                                       new String[] { "ein", "wenig" },
                                                       new String[] { "des", "Öfteren" },
                                                       new String[] { "bei", "weitem" },
                                                       new String[] { "an", "sich" }
  };
  
  public UnnecessaryPhraseRule(ResourceBundle messages, Language lang, UserConfig userConfig) {
    super(messages, lang, userConfig, DEFAULT_MIN_PER_MILL);
    addExamplePair(Example.wrong("Das ist <marker>allem Anschein nach</marker> eine Phrase."),
        Example.fixed("Das ist eine Phrase."));
  }

  /**
   * Minimal value is given in per mil
   */
  @Override
  public double denominator() {
    return 10000.0;
  }
  
  /**
   * changes first char to upper as sentence begin
   */
  private static String firstCharToLower(AnalyzedTokenReadings[] tokens, int nToken) {
    String token = tokens[nToken].getToken();
    return ((nToken != 1 || token.length() < 2) ? token : token.substring(0, 1).toLowerCase() + token.substring(1));
  }
  
  @Override
  protected int conditionFulfilled(AnalyzedTokenReadings[] tokens, int nAnalysedToken) {
    for (int i = 0; i < unnecessaryPhrases.length; i++) {
      int j;
      for (j = 0; j < unnecessaryPhrases[i].length && nAnalysedToken + j < tokens.length && 
          unnecessaryPhrases[i][j].equals(firstCharToLower(tokens, nAnalysedToken + j)); j++);
      if (j == unnecessaryPhrases[i].length) {
        return nAnalysedToken + unnecessaryPhrases[i].length - 1;
      }
    }
    return -1;
  }
  
  @Override
  protected boolean sentenceConditionFulfilled(AnalyzedTokenReadings[] tokens, int nToken) {
    return false;
  }

  @Override
  protected boolean excludeDirectSpeech() {
    return true;
  }

  @Override
  protected String getLimitMessage(int limit, double percent) {<FILL_FUNCTION_BODY>}

  @Override
  protected String getSentenceMessage() {
    return null;
  }

  @Override
  public String getId() {
    return "UNNECESSARY_PHRASES_DE";
  }

  @Override
  public String getDescription() {
    return "Statistische Stilanalyse: Potenzielle Phrasen";
  }

  @Override
  public String getConfigureText() {
    return "Anzeigen wenn mehr als ...‱ eines Kapitels potenzielle Phrasen sind:";
  }

}

    if (limit == 0) {
      return "Der Ausdruck gilt als Phrase. Es wird empfohlen ihn zu löschen, falls möglich.";
    }
    return "Mehr als " + limit + "‱ potenzielle Phrasen {" + ((int) (percent +0.5d)) +
        "‱} gefunden. Es wird empfohlen den Ausdruck zu löschen, falls möglich.";
  
<methods>public void <init>(java.util.ResourceBundle, org.languagetool.Language, org.languagetool.UserConfig, int, boolean) ,public void <init>(java.util.ResourceBundle, org.languagetool.Language, org.languagetool.UserConfig, int) ,public double denominator() ,public abstract java.lang.String getConfigureText() ,public int getDefaultValue() ,public int getMaxConfigurableValue() ,public int getMinConfigurableValue() ,public int getNumberOfMatches() ,public int getWordCount() ,public boolean hasConfigurableValue() ,public org.languagetool.rules.RuleMatch[] match(List<org.languagetool.AnalyzedSentence>) throws java.io.IOException,public int minToCheckParagraph() ,public void setWithoutDirectSpeech(boolean) <variables>private static final boolean DEFAULT_ACTIVATION,private static final java.util.regex.Pattern ENDING_QUOTES,private static final java.util.regex.Pattern OPENING_QUOTES,private final non-sealed int defaultMinPercent,private final non-sealed int minPercent,private int numMatches,private boolean withoutDirectSpeech,private int wordCount