// Path: nlu-core/src/main/java/com/conversationkit/model/IConversationIntent.java
// public interface IConversationIntent {
//     /**
//      * @return unique ID for the intent.
//      */
//     public String getIntentId();
//     /**
//      * Slots are parameters collected from the user's input while detecting intent. As an example, a
//      * a slot might be a color. So in the user input, "Press the red button" the intent
//      * might be <code>PRESS_BUTTON</code> with a slot of <code>color</code> set to <code>red</code>.
//      * @return map of slot keys to slot values
//      */
//     public Map<String,Object> getSlots();
//     
//     public boolean getAllRequiredSlotsFilled();
// }
// 
// Path: conversation-kit/src/main/java/com/conversationkit/model/IConversationNode.java
// public interface IConversationNode<E extends IConversationEdge> {
// 
//     /**
//      * Returns a list of outbound edges from the current node. One matching 
//      * edge may be chosen to continue the conversation to the next node.
//      * @return outbound edges
//      */
//     public Iterable<E> getEdges();
// 
//     /**
//      * Adds an edge to the list of possible outbound edges.
//      * @param edge edge to add
//      */
//     public void addEdge(E edge);
// 
//     /**
//      * Returns the unique identifier for this node.
//      * @return the node id
//      */
//     public int getId();
//     
//     /**
//      * Node metadata is any additional information the node may
//      * need to build platform-specific implementations of itself. The values stored
//      * in the metadata will be highly dependent on the final use case and is
//      * designed to be highly flexible. 
//      * @return JSON metadata
//      */
//     public JsonObject getMetadata();
//     
// }
// 
// Path: redux/src/main/java/com/conversationkit/redux/Action.java
// @FunctionalInterface
// public interface Action {
//     public String getType();
// }
// 
// Path: redux/src/main/java/com/conversationkit/redux/Reducer.java
// @FunctionalInterface
// /**
//  * Reducers calculate a new state given the previous state and an action.
//  * @see <a href="https://redux.js.org/glossary#reducer">https://redux.js.org/glossary#reducer</a>
//  */
// public interface Reducer {
// 
//     Map reduce(Action action, Map currentState);
// }


import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.conversationkit.model.IConversationIntent;
import com.conversationkit.model.IConversationNode;
import com.conversationkit.redux.Action;
import com.conversationkit.redux.Reducer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
/*
 * The MIT License
 *
 * Copyright 2019 Synclab Consulting LLC.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.conversationkit.impl;


/**
 * Redux reducer function to handle conversation-scoped actions.
 *
 * @author pdtyreus
 */
public class ConversationReducer implements Reducer {

    private static final Set<String> reservedKeys = new HashSet(Arrays.asList("intentId", "edgeId", "misunderstoodCount", "nodeId"));
    private static Logger logger = Logger.getLogger(ConversationReducer.class.getName());

    @Override
    public Map reduce(Action action, Map currentState) {
        Map<String, Object> nextState = new HashMap(currentState);
        if (action instanceof ConversationAction) {
            ConversationAction conversationAction = (ConversationAction) action;
            switch (conversationAction.getActionType()) {
                case MESSAGE_RECEIVED:
                    nextState.remove("intentId");
                    nextState.remove("edgeId");
                    return nextState;
                case SET_NODE_ID:
                    nextState.remove("intentId");
                    nextState.remove("edgeId");
                    nextState.remove("misunderstoodCount");
                    nextState.put("nodeId", ((ConversationAction<String>) action).getPayload().get());
                    return nextState;
                case INTENT_UNDERSTANDING_SUCCEEDED:
                    nextState.remove("misunderstoodCount");
// Path: nlu-core/src/main/java/com/conversationkit/model/IConversationIntent.java
// public interface IConversationIntent {
//     /**
//      * @return unique ID for the intent.
//      */
//     public String getIntentId();
//     /**
//      * Slots are parameters collected from the user's input while detecting intent. As an example, a
//      * a slot might be a color. So in the user input, "Press the red button" the intent
//      * might be <code>PRESS_BUTTON</code> with a slot of <code>color</code> set to <code>red</code>.
//      * @return map of slot keys to slot values
//      */
//     public Map<String,Object> getSlots();
//     
//     public boolean getAllRequiredSlotsFilled();
// }
// 
// Path: conversation-kit/src/main/java/com/conversationkit/model/IConversationNode.java
// public interface IConversationNode<E extends IConversationEdge> {
// 
//     /**
//      * Returns a list of outbound edges from the current node. One matching 
//      * edge may be chosen to continue the conversation to the next node.
//      * @return outbound edges
//      */
//     public Iterable<E> getEdges();
// 
//     /**
//      * Adds an edge to the list of possible outbound edges.
//      * @param edge edge to add
//      */
//     public void addEdge(E edge);
// 
//     /**
//      * Returns the unique identifier for this node.
//      * @return the node id
//      */
//     public int getId();
//     
//     /**
//      * Node metadata is any additional information the node may
//      * need to build platform-specific implementations of itself. The values stored
//      * in the metadata will be highly dependent on the final use case and is
//      * designed to be highly flexible. 
//      * @return JSON metadata
//      */
//     public JsonObject getMetadata();
//     
// }
// 
// Path: redux/src/main/java/com/conversationkit/redux/Action.java
// @FunctionalInterface
// public interface Action {
//     public String getType();
// }
// 
// Path: redux/src/main/java/com/conversationkit/redux/Reducer.java
// @FunctionalInterface
// /**
//  * Reducers calculate a new state given the previous state and an action.
//  * @see <a href="https://redux.js.org/glossary#reducer">https://redux.js.org/glossary#reducer</a>
//  */
// public interface Reducer {
// 
//     Map reduce(Action action, Map currentState);
// }


// Path: conversation-kit/src/main/java/com/conversationkit/impl/ConversationReducer.java
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.conversationkit.model.IConversationIntent;
import com.conversationkit.model.IConversationNode;
import com.conversationkit.redux.Action;
import com.conversationkit.redux.Reducer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

/*
 * The MIT License
 *
 * Copyright 2019 Synclab Consulting LLC.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.conversationkit.impl;


/**
 * Redux reducer function to handle conversation-scoped actions.
 *
 * @author pdtyreus
 */
public class ConversationReducer implements Reducer {

    private static final Set<String> reservedKeys = new HashSet(Arrays.asList("intentId", "edgeId", "misunderstoodCount", "nodeId"));
    private static Logger logger = Logger.getLogger(ConversationReducer.class.getName());

    @Override
    public Map reduce(Action action, Map currentState) {
        Map<String, Object> nextState = new HashMap(currentState);
        if (action instanceof ConversationAction) {
            ConversationAction conversationAction = (ConversationAction) action;
            switch (conversationAction.getActionType()) {
                case MESSAGE_RECEIVED:
                    nextState.remove("intentId");
                    nextState.remove("edgeId");
                    return nextState;
                case SET_NODE_ID:
                    nextState.remove("intentId");
                    nextState.remove("edgeId");
                    nextState.remove("misunderstoodCount");
                    nextState.put("nodeId", ((ConversationAction<String>) action).getPayload().get());
                    return nextState;
                case INTENT_UNDERSTANDING_SUCCEEDED:
                    nextState.remove("misunderstoodCount");
                    IConversationIntent successfulIntent = ((ConversationAction<IConversationIntent>) action).getPayload().get();