/* 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.tagging.disambiguation.rules;

import org.jetbrains.annotations.Nullable;
import org.languagetool.AnalyzedSentence;
import org.languagetool.AnalyzedToken;
import org.languagetool.Language;
import org.languagetool.rules.patterns.AbstractTokenBasedRule;
import org.languagetool.rules.patterns.Match;
import org.languagetool.rules.patterns.PatternToken;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * A Rule that describes a pattern of words or part-of-speech tags used for
 * disambiguation.
 * 
 * @author Marcin Miłkowski
 */
public class DisambiguationPatternRule extends AbstractTokenBasedRule {

  /** Possible disambiguator actions. **/
  public enum DisambiguatorAction {
    ADD, FILTER, REMOVE, REPLACE, UNIFY, IMMUNIZE, IGNORE_SPELLING, FILTERALL, ADDCHUNK
  }

  private final String disambiguatedPOS;
  private final Match matchElement;
  private final DisambiguatorAction disAction;

  private AnalyzedToken[] newTokenReadings;
  private List<DisambiguatedExample> examples = Collections.emptyList();
  private List<String> untouchedExamples = Collections.emptyList();

  /**
   * @param id Id of the Rule
   * @param language Language of the Rule
   * @param description Description to be shown (name)
   * @param disambAction the action to be executed on found token(s)
   * @since public since 2.5
   */
  public DisambiguationPatternRule(String id, String description,
                                   Language language, List<PatternToken> patternTokens,
                                   String disambiguatedPOS, Match posSelect,
                                   DisambiguatorAction disambAction) {
    super(id, description, language, patternTokens, true);
    if (disambiguatedPOS == null && posSelect == null
        && disambAction != DisambiguatorAction.UNIFY
        && disambAction != DisambiguatorAction.ADD
        && disambAction != DisambiguatorAction.REMOVE
        && disambAction != DisambiguatorAction.IMMUNIZE
        && disambAction != DisambiguatorAction.REPLACE
        && disambAction != DisambiguatorAction.FILTERALL
        && disambAction != DisambiguatorAction.IGNORE_SPELLING
        && disambAction != DisambiguatorAction.ADDCHUNK) {
      throw new NullPointerException("disambiguated POS cannot be null with posSelect == null and " + disambAction);
    }
    this.disambiguatedPOS = disambiguatedPOS;
    this.matchElement = posSelect;
    this.disAction = Objects.requireNonNull(disambAction);
    setMessage("");
    suggestionsOutMsg = "";
  }

  /**
   * Used to add new interpretations.
   * @param newReadings
   *          An array of AnalyzedTokens. The length of the array should be the
   *          same as the number of the tokens matched and selected by
   *          {@code <marker>...</marker>} elements.
   */
  public final void setNewInterpretations(AnalyzedToken[] newReadings) {
    newTokenReadings = newReadings.clone();
  }

  /**
   * Performs disambiguation on the source sentence.
   * @param sentence {@link AnalyzedSentence} Sentence to be disambiguated.
   * @return {@link AnalyzedSentence} Disambiguated sentence (might be unchanged).
   */
  public final AnalyzedSentence replace(AnalyzedSentence sentence) throws IOException {
    return canBeIgnoredFor(sentence) ? sentence : new DisambiguationPatternRuleReplacer(this).replace(sentence);
  }

  public void setExamples(List<DisambiguatedExample> examples) {
    this.examples = Objects.requireNonNull(examples);
  }

  public List<DisambiguatedExample> getExamples() {
    return Collections.unmodifiableList(examples);
  }

  public void setUntouchedExamples(List<String> untouchedExamples) {
    this.untouchedExamples = Objects.requireNonNull(untouchedExamples);
  }

  public List<String> getUntouchedExamples() {
    return Collections.unmodifiableList(untouchedExamples);
  }

  /**
   * @since 2.3
   */
  public DisambiguatorAction getAction() {
    return disAction;
  }

  /**
   * @since 2.3
   */
  public AnalyzedToken[] getNewTokenReadings() {
    return newTokenReadings;
  }

  /**
   * @since 2.3
   */
  @Nullable
  public Match getMatchElement() {
    return matchElement;
  }

  /**
   * @since 2.3
   */
  @Nullable
  public String getDisambiguatedPOS() {
    return disambiguatedPOS;
  }

}
