/*
 * GRAKN.AI - THE KNOWLEDGE GRAPH
 * Copyright (C) 2018 Grakn Labs Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package grakn.core.graql.internal.reasoner.state;

import grakn.core.graql.answer.ConceptMap;
import grakn.core.graql.admin.Unifier;
import grakn.core.graql.internal.reasoner.atom.predicate.NeqPredicate;
import grakn.core.graql.internal.reasoner.cache.SimpleQueryCache;
import grakn.core.graql.internal.reasoner.query.ReasonerAtomicQuery;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Set;
import java.util.stream.Collectors;

/**
 *
 * <p>
 * Query state corresponding to an atomic query ({@link ReasonerAtomicQuery}) with neq predicates ({@link NeqPredicate}).
 * Defining the answer to the entry query Q as a set B:
 *
 * B = Ans{R(x1, x2, ..., xn), xj = ..., xi != xj}
 *
 * We find the answer to the query by finding the complement:
 *
 * B = A\C,
 *
 * where
 *
 * A = Ans{R(x1, x2, ..., xn), xj = ...}
 * C = Ans{R(x1, x2, ..., xn), xj = ..., xi = xj}
 *
 * </p>
 *
 *
 */
@SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
public class NeqComplementState extends AtomicState {

    private final ResolutionState complementState;
    private boolean visited = false;

    private final ConceptMap neqPredicateSub;
    private final Set<NeqPredicate> neqPredicates;

    NeqComplementState(ReasonerAtomicQuery q,
                       ConceptMap sub,
                       Unifier u,
                       QueryStateBase parent,
                       Set<ReasonerAtomicQuery> subGoals,
                       SimpleQueryCache<ReasonerAtomicQuery> cache) {
        super(q, sub, u, parent, subGoals, cache);

        this.neqPredicates = q.getAtoms(NeqPredicate.class).collect(Collectors.toSet());
        this.neqPredicateSub = getQuery().getSubstitution().merge(sub)
                .project(this.neqPredicates.stream().flatMap(p -> p.getVarNames().stream()).collect(Collectors.toSet()));

        complementState = getQuery().positive().subGoal(sub, u, this, subGoals, cache);
    }

    @Override
    public ResolutionState propagateAnswer(AnswerState state) {
        ConceptMap fullAnswer = state.getSubstitution().merge(neqPredicateSub);

        boolean isNeqSatisfied = neqPredicates.stream()
                .allMatch(p -> p.isSatisfied(fullAnswer));
        return isNeqSatisfied?
                new AnswerState(state.getSubstitution(), getUnifier(), getParentState()) :
                null;
    }

    @Override
    public ResolutionState generateSubGoal() {
        if (!visited){
            visited = true;
            return complementState;
        }
        return null;
    }
}

@@ -1141,16 +1141,81 @@
 rnings;%0A
+import grakn.core.graql.internal.reasoner.query.ReasonerQueries;%0A
 import j
@@ -1821,18 +1821,21 @@
 nds 
-AtomicStat
+QueryStateBas
 e %7B%0A
@@ -1853,26 +1853,22 @@
 e final 
-Resolution
+Atomic
 State co
@@ -2329,11 +2329,8 @@
 per(
-q, 
 sub,
@@ -2359,16 +2359,83 @@
 cache);%0A
+        ReasonerAtomicQuery query = ReasonerQueries.atomic(q, sub);
 %0A       
@@ -2547,26 +2547,21 @@
 teSub = 
-getQ
+q
 uery
-()
 .getSubs
@@ -2713,16 +2713,21 @@
         
+this.
 compleme
@@ -2740,18 +2740,29 @@
 e = 
-getQ
+new AtomicState(q
 uery
-()
 .pos
@@ -2772,17 +2772,10 @@
 ve()
-.subGoal(
+, 
 sub,
@@ -3226,32 +3226,156 @@
    null;%0A    %7D%0A%0A
+    @Override%0A    ConceptMap consumeAnswer(AnswerState state) %7B%0A        return complementState.consumeAnswer(state);%0A    %7D%0A%0A
     @Override%0A  

refactor complement state (#4632)