/*
 * LanguageTool, a natural language style checker
 * Copyright (C) 2021 Sohaib Afifi, Taha Zerrouki
 *
 * 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.ar;

import org.languagetool.AnalyzedSentence;
import org.languagetool.AnalyzedToken;
import org.languagetool.AnalyzedTokenReadings;
import org.languagetool.language.Arabic;
import org.languagetool.rules.*;
import org.languagetool.synthesis.ar.ArabicSynthesizer;
import org.languagetool.tagging.ar.ArabicTagManager;
import org.languagetool.tagging.ar.ArabicTagger;

import java.util.*;

public class ArabicTransVerbRule extends AbstractSimpleReplaceRule2 {

  public static final String AR_VERB_TRANS_INDIRECT_REPLACE = "AR_VERB_TRANSITIVE_IINDIRECT";

  private static final String FILE_NAME = "/ar/verb_trans_to_untrans2.txt";
  private static final Locale AR_LOCALE = new Locale("ar");

  private final ArabicTagger tagger;
  private final ArabicTagManager tagmanager;
  private final List<Map<String, SuggestionWithMessage>> wrongWords;

  public ArabicTransVerbRule(ResourceBundle messages) {
    super(messages, new Arabic());
    tagger = new ArabicTagger();
    tagger.enableNewStylePronounTag();
    tagmanager = new ArabicTagManager();

    super.setCategory(Categories.MISC.getCategory(messages));
    setLocQualityIssueType(ITSIssueType.Misspelling);
    addExamplePair(Example.wrong("The train arrived <marker>a hour</marker> ago."),
      Example.fixed("The train arrived <marker>an hour</marker> ago."));

    // get wrong words from resource file
    wrongWords = getWrongWords(false);
  }

  @Override
  public String getId() {
    return AR_VERB_TRANS_INDIRECT_REPLACE;
  }

  @Override
  public String getDescription() {
    return "َTransitive verbs corrected to indirect transitive";
  }

  @Override
  public final List<String> getFileNames() {
    return Collections.singletonList(FILE_NAME);
  }

  @Override
  public String getShort() {
    return "أفعال متعدية بحرف، يخطئ في تعديتها";
  }

  @Override
  public String getMessage() {
    return "'$match' الفعل خاطئ في التعدية بحرف: $suggestions";
  }

  @Override
  public String getSuggestionsSeparator() {
    return " أو ";
  }

  @Override
  public Locale getLocale() {
    return AR_LOCALE;
  }

  @Override
  public RuleMatch[] match(AnalyzedSentence sentence) {
    List<RuleMatch> ruleMatches = new ArrayList<>();
    if (wrongWords.size() == 0) {
      return toRuleMatchArray(ruleMatches);
    }
    AnalyzedTokenReadings[] tokens = sentence.getTokensWithoutWhitespace();
    int prevTokenIndex = 0;
    for (int i = 1; i < tokens.length; i++) {  // ignoring token 0, i.e., SENT_START
      AnalyzedTokenReadings token = tokens[i];
      AnalyzedTokenReadings prevToken = prevTokenIndex > 0 ? tokens[prevTokenIndex] : null;
      String prevTokenStr = prevTokenIndex > 0 ? tokens[prevTokenIndex].getToken() : null;

      if (prevTokenStr != null) {
        // test if the first token is a verb
        boolean is_attached_verb_transitive = isAttachedTransitiveVerb(prevToken);

        // test if the preposition token is suitable for verb token (previous)
        List<String> prepositions = getProperPrepositionForTransitiveVerb(prevToken);

        boolean is_right_preposition = isRightPreposition(token, prepositions);

        // the verb is attached and the next token is not the suitable preposition
        // we give the correct new form
        if (is_attached_verb_transitive && !is_right_preposition) {
          String verb = getCorrectVerbForm(tokens[prevTokenIndex]);
          // generate suggestion according to suggested prepositions
          // FIXME: test all suggestions
          String newPreposition = prepositions.get(0);
          String preposition = getCorrectPrepositionForm(newPreposition, prevToken);

          String replacement = verb + " " + preposition;
          String msg = "قل <suggestion>" + replacement + "</suggestion> بدلا من '" + prevTokenStr + "' لأنّ الفعل " +
            " متعد بحرف  .";
          RuleMatch match = new RuleMatch(
            this, sentence, tokens[prevTokenIndex].getStartPos(), tokens[prevTokenIndex].getEndPos(),
            tokens[prevTokenIndex].getStartPos(), token.getEndPos(), msg, "خطأ في الفعل المتعدي بحرف");
          ruleMatches.add(match);
        }
      }

      if (isAttachedTransitiveVerb(token)) {
        prevTokenIndex = i;
      } else {
        prevTokenIndex = 0;
      }
    }
    return toRuleMatchArray(ruleMatches);
  }

  private boolean isAttachedTransitiveVerb(AnalyzedTokenReadings mytoken) {
    List<AnalyzedToken> verbTokenList = mytoken.getReadings();

    for (AnalyzedToken verbTok : verbTokenList) {
      String verbLemma = verbTok.getLemma();
      String verbPostag = verbTok.getPOSTag();

      // if postag is attached
      // test if verb is in the verb list
      if (verbPostag != null)// && verbPostag.endsWith("H"))
      {
        // lookup in WrongWords
        SuggestionWithMessage verbLemmaMatch = wrongWords.get(wrongWords.size() - 1).get(verbLemma);
        // The lemma is found in the dictionary file
        if (verbLemmaMatch != null)
          return true;
      }

    }
    return false;
  }

  /* if the word is a transitive verb, we got proper preposition inorder to test it*/
  private List<String> getProperPrepositionForTransitiveVerb(AnalyzedTokenReadings mytoken) {
    List<AnalyzedToken> verbTokenList = mytoken.getReadings();

    // keep the suitable postags
    List<String> replacements = new ArrayList<>();

    for (AnalyzedToken verbTok : verbTokenList) {
      String verbLemma = verbTok.getLemma();
      String verbPostag = verbTok.getPOSTag();

      // if postag is attached
      // test if verb is in the verb list
      if (verbPostag != null)
      {
        // lookup in WrongWords
        SuggestionWithMessage verbLemmaMatch = wrongWords.get(wrongWords.size() - 1).get(verbLemma);
        // The lemma is found in the dictionary file
        if (verbLemmaMatch != null) {
          replacements = Arrays.asList(verbLemmaMatch.getSuggestion().split("\\|"));
          return replacements;
        }
      }
    }
    return replacements;
  }

  private static boolean isRightPreposition(AnalyzedTokenReadings nextToken, List<String> prepositionList) {
    //FIXME: test if the next token  is the suitable preposition for the previous token as verbtoken
    String nextTokenStr = nextToken.getReadings().get(0).getLemma();
    return prepositionList.contains(nextTokenStr);
  }

  private String getCorrectVerbForm(AnalyzedTokenReadings token) {
    return generateUnattachedNewForm(token);
  }

  private String getCorrectPrepositionForm(String prepositionLemma, AnalyzedTokenReadings prevtoken) {
    return generateAttachedNewForm(prepositionLemma, prevtoken);
  }

  /* generate a new form according to a specific postag*/
  private String generateNewForm(String word, String posTag, char flag) {
    // generate new from word form
    String newposTag = tagmanager.setFlag(posTag, "PRONOUN", flag);
    // FIXME: remove the specific flag for option D
    if (flag != '-')
      newposTag = tagmanager.setFlag(newposTag, "OPTION", 'D');
    // generate the new preposition according to modified postag
    AnalyzedToken prepAToken = new AnalyzedToken(word, newposTag, word);
    String[] newwordList = ArabicSynthesizer.INSTANCE.synthesize(prepAToken, newposTag);
    String newWord = "";
    if (newwordList.length != 0) {
      newWord = newwordList[0];
    }
    return newWord;
  }

  /* generate a new form according to a specific postag, this form is Un-Attached*/
  private String generateUnattachedNewForm(AnalyzedTokenReadings token) {
    String lemma = token.getReadings().get(0).getLemma();
    String postag = token.getReadings().get(0).getPOSTag();
    return generateNewForm(lemma, postag, '-');
  }

  /* generate a new form according to a specific postag, this form is Attached*/
  private String generateAttachedNewForm(String prepositionLemma, AnalyzedTokenReadings prevtoken) {
    // FIXME ; generate multiple cases
    String postag = "PR-;---;---";
    String prevPosTag = prevtoken.getReadings().get(0).getPOSTag();
    char flag = tagmanager.getFlag(prevPosTag, "PRONOUN");
    return generateNewForm(prepositionLemma, postag, flag);
  }
}
