/* LanguageTool, a natural language style checker
 * Copyright (C) 2010 Daniel Naber (http://www.languagetool.org)
 *
 * 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.ru;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.languagetool.AnalyzedSentence;
import org.languagetool.AnalyzedToken;
import org.languagetool.AnalyzedTokenReadings;
import org.languagetool.rules.Rule;
import org.languagetool.rules.RuleMatch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RussianVerbConjugationRule extends Rule {

    private static final Pattern PRONOUN = Pattern.compile("PNN:(.*):Nom:(.*)");
    private static final Pattern FUT_REAL_VERB = Pattern.compile("VB:(Fut|Real):(.*):(.*):(.*):(.*)");
    private static final Pattern PAST_VERB = Pattern.compile("VB:Past:(.*):(.*):(.*)");

    public RussianVerbConjugationRule(ResourceBundle messages) {
        super(messages);
    }

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

    @Override
    public String getDescription() {
        return "Согласование личных местоимений с глаголами";
    }

    @Override
    public RuleMatch[] match(AnalyzedSentence sentence) throws IOException {
        List<RuleMatch> ruleMatches = new ArrayList<>();
        AnalyzedTokenReadings[] tokenReadings = sentence.getTokensWithoutWhitespace();
        for (int i = 1; i < tokenReadings.length - 1; i++) {
	    AnalyzedTokenReadings previousReading = tokenReadings[i-1];	
            AnalyzedTokenReadings currentReading = tokenReadings[i];
            AnalyzedTokenReadings nextReading = tokenReadings[i + 1];
	    AnalyzedToken previousLemmaTok = previousReading.getReadings().get(0);
            AnalyzedToken currentLemmaTok = currentReading.getReadings().get(0);
            String previousToken = previousLemmaTok.getToken();
	    String currentToken = currentLemmaTok.getToken();
            String currentPosTag = currentLemmaTok.getPOSTag();
            if (currentToken != null && currentPosTag != null && !currentToken.isEmpty() && !currentPosTag.isEmpty()) {
                Matcher pronounMatcher = PRONOUN.matcher(currentPosTag);
                if ((pronounMatcher.find()) && !(previousToken.equals("и")))  {
                    Pair<String, String> pronounPair = new ImmutablePair<>(pronounMatcher.group(1), pronounMatcher.group(2));
                    AnalyzedToken nextLemmaTok = nextReading.getReadings().get(0);
                    String nextPosTag = nextLemmaTok.getPOSTag();
                    if(nextPosTag != null && !(nextPosTag.isEmpty()) && !(nextLemmaTok.getToken().equals("может")) ) {  // replace check nextLemmaTok+1 && "быть"
                        Matcher verbMatcher = FUT_REAL_VERB.matcher(nextPosTag);
                        if (verbMatcher.find()) {
                            Pair<String, String> verbPair = new ImmutablePair<>(verbMatcher.group(4), verbMatcher.group(5));
                            if (isConjugationInPresentOrFutureWrong(pronounPair, verbPair)) {
                                addRuleMatch(ruleMatches, currentReading, nextReading, sentence);
                            }
                        } else {
                            verbMatcher = PAST_VERB.matcher(nextPosTag);
                            if (verbMatcher.find()) {
                                if (isConjugationInPastWrong(pronounMatcher.group(1), verbMatcher.group(3))) {
                                    addRuleMatch(ruleMatches, currentReading, nextReading, sentence);
                                }
                            }
                        }
                    }
                }
            }
        }
        return toRuleMatchArray(ruleMatches);
    }

    private boolean isConjugationInPresentOrFutureWrong(Pair<String, String> pronoun, Pair<String, String> verb) {
        if (!pronoun.getRight().equals(verb.getRight())) {
            return true;
        }
        if (Arrays.asList("Masc", "Fem", "Neut").contains(pronoun.getLeft())) {
            return "PL".equals(verb.getLeft());
        }
        return !pronoun.getLeft().equals(verb.getLeft());
    }

    private boolean isConjugationInPastWrong(String pronoun, String verb) {
        if ("Sin".equals(pronoun)) {
            return "PL".equals(verb) || "Neut".equals(verb);
        }
        return !pronoun.equals(verb);
    }

    private void addRuleMatch(List<RuleMatch> ruleMatches, AnalyzedTokenReadings currentReading, AnalyzedTokenReadings nextReading, AnalyzedSentence sentence) {
        RuleMatch ruleMatch = new RuleMatch(this, sentence, currentReading.getStartPos(), nextReading.getEndPos(), "Неверное спряжение глагола или неверное местоимение", getShort());
        ruleMatches.add(ruleMatch);
    }

    protected String getShort() {
        return "Неверное спряжение глагола";
    }
}


@@ -3343,32 +3343,481 @@
 dings().get(0);%0A
+                    String next2Token = %22%22;%0A                    if (i %3C tokenReadings.length - 2) %7B%0A                    AnalyzedTokenReadings next2Reading = tokenReadings%5Bi + 2%5D;%0A                    AnalyzedToken next2LemmaTok = next2Reading.getReadings().get(0);%0A                    next2Token = next2LemmaTok.getToken();%0A                    %7D else  %7B%0A                            next2Token = %22%22;%0A                            %7D%0A                    %0A
                 
@@ -3944,35 +3944,22 @@
 & !(next
-LemmaTok.get
+2
 Token
-()
 .equals(
@@ -3963,13 +3963,12 @@
 ls(%22
-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82
+%D0%B1%D1%8B%D1%82%D1%8C
 %22)) 
@@ -3979,41 +3979,16 @@
  // 
-replace check nextLemmaTok+1 && %22
+ %22%D0%BC%D0%BE%D0%B6%D0%B5%D1%82 
 %D0%B1%D1%8B%D1%82%D1%8C

improve rule, add exception