package org.studiorailgun.ai.conversation.web;

import java.util.List;
import java.util.stream.Collectors;

import org.studiorailgun.Globals;
import org.studiorailgun.ai.conversation.parser.PennTreebankTagSet;
import org.studiorailgun.ai.conversation.parser.depend.Argument;
import org.studiorailgun.ai.conversation.tracking.Conversation;
import org.studiorailgun.ai.conversation.tracking.Quote;
import org.studiorailgun.ai.knowledge.Node;
import org.studiorailgun.ai.knowledge.Relation;
import org.studiorailgun.ai.knowledge.query.InstanceQuery;
import org.studiorailgun.ai.knowledge.query.PossessionQuery;
import org.studiorailgun.ai.knowledge.types.RelationTypes;
import org.studiorailgun.ai.linguistics.PronounQuery;
import org.studiorailgun.ai.linguistics.ProperNounQuery;
import org.studiorailgun.ai.philosophy.ConceptQuery;

/**
 * Queries related to linguistic arguments
 */
public class ArgumentQuery {
    
    /**
     * Gets the node representing a linguistic argument
     * @param conversation The conversation the quote is in context of
     * @param quote The quote the argument is originating from -- used for some lookups (ie possession)
     * @param argument The argument
     * @return The node
     */
    public static Node getArgument(Conversation conversation, Quote quote, Argument argument){
        String argumentRoot = argument.getRoot().originalText();
        String argumentTag = argument.getRoot().tag();

        //the root node which then had modifiers applied to it
        Node rootNode = null;

        if(PennTreebankTagSet.isCommonNoun(argumentTag)){
            Node conceptNode = ConceptQuery.getConcept(argumentRoot);
            rootNode = conceptNode;
            //apply possessive modifier
            if(argument.getPossessiveModifier() != null){
                rootNode = ArgumentQuery.getPossessionModified(quote, rootNode, argument);
            }
        } else if(PennTreebankTagSet.isProperNoun(argumentTag)){
            rootNode = ProperNounQuery.getProperNoun(argumentRoot);
        } else if(PennTreebankTagSet.isPronoun(argumentTag)){
            rootNode = PronounQuery.getPronoun(conversation, quote, argumentRoot);
        } else {
            throw new Error("Undefined case! " + argumentTag);
        }

        return rootNode;
    }

    /**
     * Gets the root node with the possession modifier applied
     * @param rootNode The root node
     * @param argument The argument
     * @return The node that represents the possession modifier applied to the root node
     */
    private static Node getPossessionModified(Quote quote, Node rootNode, Argument argument){
        Node speaker = QuoteQuery.getSpeaker(quote.getNode());
        String possessionModifier = argument.getPossessiveModifier().originalText().toLowerCase();
        switch(possessionModifier){
            case "my": {
                List<Node> instances = InstanceQuery.getInstances(rootNode);
                List<Node> possessedInstances = instances.stream().filter(node -> {
                    List<Relation> relations = Globals.web.getRelationsOfChildNode(node);
                    List<Relation> possessionRelationsToRoot = relations.stream().filter(relation -> relation.getName().equals(RelationTypes.POSSESSION_OF) && relation.getParent().equals(rootNode)).collect(Collectors.toList());
                    return possessionRelationsToRoot.size() > 0;
                }).collect(Collectors.toList());
                if(possessedInstances.size() == 1){
                    //already exists, return it
                    return possessedInstances.get(0);
                } else if(possessedInstances.size() > 1) {
                    //already exists, return it
                    throw new Error("Can't currently handle plural instances!");
                } else {
                    //does not already exist, see if we can generate a node to encapsulate it
                    Node newInstance = Globals.web.createNode(rootNode.getName() + "(inst)");
                    InstanceQuery.setInstance(rootNode, newInstance);       // ie (inst) <--instanceOf-- "name"
                    MetaQuery.flagAsLearnable(newInstance);             // ie (inst) <--qualityOf-- "learnable"
                    PossessionQuery.setPossessor(speaker, newInstance); // ie (inst) <--possessionOf-- (person instance)
                    return newInstance;
                }
            }
            default: {
                throw new Error("Unsupported possession modifier! " + possessionModifier);
            }
        }
    }

}
