void OnlinePlanExpansionExecution::OnGoalNodeSucceeded(_In_ IOlcbpPlan::NodeID nodeId)
{
    GoalEx* pGoal = (GoalEx*)m_pOlcbpPlan->GetNode(nodeId);
    _ASSERTE(pGoal->State() == ESTATE_Succeeded);


    if (GetNodeData(nodeId).BelongingCase != nullptr)
    {
        LogInfo("Goal=%s succeeded, revising its case and retaining it", pGoal->ToString().c_str());

        CaseEx* currentCase = GetLastCaseForGoalNode(nodeId);
        m_pCbReasoner->Reviser()->Revise(currentCase, true);
        //UpdateHistory(currentCase);
    }
    else
    {
        LogInfo("Goal=%s succeeded without expansion, no case to revise", pGoal->ToString().c_str());
    }

    UpdateBelongingSubplanChildrenWithParentReadiness(nodeId);
    OnNodeDone(nodeId);

    if (m_planRootNodeId == nodeId)
    {
        g_MessagePump->Send(new Message(0, MSG_PlanComplete));
    }
}
void OnlinePlanExpansionExecution::OnGoalNodeFailed(_In_ IOlcbpPlan::NodeID nodeId)
{
    GoalEx* pGoal = (GoalEx*)m_pOlcbpPlan->GetNode(nodeId);
    _ASSERTE(pGoal->State() == ESTATE_Failed);

    if (GetNodeData(nodeId).BelongingCase != nullptr)
    {
        LogInfo("Goal=%s failed, revising and retaining it", pGoal->ToString().c_str());

        CaseEx* currentCase = GetLastCaseForGoalNode(nodeId);
        m_pCbReasoner->Reviser()->Revise(currentCase, false);
        //UpdateHistory(currentCase);
    }

    OnNodeDone(nodeId);
}
bool OnlinePlanExpansionExecution::UpdateGoalNode(_In_ IOlcbpPlan::NodeID currentNode, _In_ const WorldClock& clock)
{
    bool expanded = false;
    GoalEx* pCurrentGoalNode = (GoalEx*)m_pOlcbpPlan->GetNode(currentNode);

    // fast return if node state reached a final state (i.e succeeded or failed)
    _ASSERTE(!IsNodeDone(currentNode));

#pragma region Node Open
    if (IsNodeOpen(currentNode))
    {
        _ASSERTE(pCurrentGoalNode->GetState() == ESTATE_NotPrepared);
        _ASSERTE(IsNodeDone(currentNode) == false);

        bool hasPreviousPlan = DestroyGoalSnippetIfExist(currentNode);

        // The goal was previously expanded with a plan, but it somehow failed
        // Thats why it is now open
        // Revise the node belonging case as failed case
        if (hasPreviousPlan)
        {
            LogInfo("Node with plan-step '%s' is open and has children nodes, case is sent for revision and children have been destroyed", pCurrentGoalNode->ToString().c_str());

            CaseEx* currentCase = GetLastCaseForGoalNode(currentNode);
            m_pCbReasoner->Reviser()->Revise(currentCase, false);
            UpdateHistory(currentCase);
        }

        if (pCurrentGoalNode->SuccessConditionsSatisfied(*g_Game))
        {
            LogInfo("Goal %s already satisfied, no need to expand it, closing the node", pCurrentGoalNode->ToString().c_str());
            pCurrentGoalNode->SetState(ESTATE_Succeeded, *g_Game, clock);
            CloseNode(currentNode);
            OnGoalNodeSucceeded(currentNode);
        }
        else
        {
            IOlcbpPlan::NodeID satisfyingGoalNode = GetNodeData(currentNode).SatisfyingGoal;
            AbstractRetriever::RetrieveOptions options;
            options.ExcludedCases = GetNodeData(currentNode).TriedCases;

            if (satisfyingGoalNode != IOlcbpPlan::NullNodeID)
            {
                LogInfo("Excluding satisfying goal node %s to avoid recursive plan expansion", m_pOlcbpPlan->GetNode(satisfyingGoalNode)->ToString().c_str());
                // Add belonging case to exclusion to avoid recursive expansion of plans
                _ASSERTE(GetNodeData(satisfyingGoalNode).BelongingCase != nullptr);
                options.ExcludedGoalHashes.insert(GetNodeData(satisfyingGoalNode).BelongingCase->Goal()->Hash());
            }

            //pCurrentGoalNode->AdaptParameters(*g_Game);
            options.GoalTypeId = (GoalType)pCurrentGoalNode->StepTypeId();
            options.pGameState = g_Game;

            options.Parameters = pCurrentGoalNode->Parameters();
            CaseEx* pCandidateCase = m_pCbReasoner->Retriever()->Retrieve(options);

            // We found a matching case and it was not tried for that goal before
            if (pCandidateCase != nullptr)
            {
                // Retriever should always retrieve a non tried case for that specific node
                // _ASSERTE(!IsCaseTried(currentNode, pCandidateCase));

                LogInfo("Retrieved case '%s' has not been tried before, and its goal is being sent for expansion",
                    pCandidateCase->Goal()->ToString().c_str());

                MarkCaseAsTried(currentNode, pCandidateCase);
                ExpandGoal(currentNode, pCandidateCase);
                expanded = true;
            }
            else
            {
                // The current failed goal node is the root goal and the planner exhausted all possible 
                // plans form the case-base for that goal node and nothing succeeded so far
                //
                // WE SURRENDER!!
                //
                if (m_planRootNodeId == currentNode)
                {
                    LogWarning("Planner has exhausted all possible cases, WE SURRENDER!!");
                    m_planRootNodeId = IOlcbpPlan::NullNodeID;
                }
                else
                {
                    LogInfo("Goal=%s exhausted all possible cases, failing it", pCurrentGoalNode->ToString().c_str());
                    pCurrentGoalNode->SetState(ESTATE_Failed, *g_Game, clock);
                    CloseNode(currentNode);
                    OnGoalNodeFailed(currentNode);
                }
            }
        }
    }
#pragma endregion
#pragma region Node Closed
    else
    {
        _ASSERTE(pCurrentGoalNode->GetState() == ESTATE_NotPrepared);

        if (pCurrentGoalNode->SuccessConditionsSatisfied(*g_Game) 
            && !HasActiveAction(currentNode))
        {
            pCurrentGoalNode->SetState(ESTATE_Succeeded, *g_Game, clock);
            OnGoalNodeSucceeded(currentNode);
        }
        else
        {
            // The goal is not done yet, and all of its children are done and
            // finished execution. It does not make sense for the goal to continue
            // this goal should fail, it has no future
            if (GetNodeData(currentNode).WaitOnChildrenCount == 0)
            {
                if (!pCurrentGoalNode->IsSleeping(clock))
                {
                    if (pCurrentGoalNode->SleepsCount() < GoalMaxSleepsCount)
                    {
                        LogInfo("%s is still not done and all of its children are done execution, slept %d time(s) before, will send it to sleep", pCurrentGoalNode->ToString().c_str(), pCurrentGoalNode->SleepsCount());
                        pCurrentGoalNode->Sleep(clock, GoalSleepTime);
                    }
                    else
                    {
                        LogInfo("%s is still not done and all of its children are done execution, already tried to sleep it %d time(s) before, failing it", pCurrentGoalNode->ToString().c_str(), GoalMaxSleepsCount);
                        OpenNode(currentNode);
                    }
                }
            }
        }
    }
#pragma endregion

    return expanded;
}
//--------------------------------------------------------------------------------------------------------------
bool IStrategizer::LearningFromHumanDemonstration::SubplansDetection(vector<CookedPlan*>& p_cookedPlans) const
{
    SubplansMap subplans;

    // Detecting the subplans and the matched nodes
    for (unsigned i = 0; i < p_cookedPlans.size(); ++i)
    {
        for (int j = i - 1; j >= 0; --j)
        {
            LogInfo("Checking if %d is supergraph of %d", i, j);
            OlcbpPlan::NodeSet matchedIds;

            if (IsSuperGraph(p_cookedPlans[i]->pPlan, p_cookedPlans[j]->pPlan, matchedIds))
            {
                subplans[i].push_back(SubsetPlanData(j, matchedIds));
            }
        }
    }

    if (subplans.empty())
    {
        return false;
    }

    for (unsigned i = 0; i < p_cookedPlans.size(); ++i)
    {
        // Remove duplicated nodes between subplans
        for (unsigned j = 0; j < subplans[i].size(); ++j)
        {
            for (unsigned k = j + 1; k < subplans[i].size(); ++k)
            {
                for (OlcbpPlan::NodeID nodeId : subplans[i][j].Nodes)
                {
                    subplans[i][k].Nodes.erase(nodeId);
                }
            }
        }

        for (SubsetPlanData subplanData : subplans[i])
        {
            if (subplanData.Nodes.empty())
            {
                continue;
            }

            unsigned subplanInx = subplanData.Index;
            unsigned subplanId = p_cookedPlans[subplanInx]->Goal->Id();
            unsigned nodeOrder = subplanId;
            OlcbpPlan::NodeSet matchedIds = subplanData.Nodes;
            GoalEx* pGoalClone = (GoalEx*)p_cookedPlans[subplanInx]->Goal->Clone();
            pGoalClone->Id(subplanId);
            
            if (p_cookedPlans[i]->pPlan->Contains(subplanId))
            {
                subplanId = PlanStepEx::GenerateID();
                pGoalClone->Id(subplanId);
            }
            
            // Substitute the detected subplans in the super plan
            _ASSERTE(subplanId == pGoalClone->Id());
            p_cookedPlans[i]->pPlan->SubGraphSubstitution(matchedIds, pGoalClone, subplanId, nodeOrder);

            LogInfo("Subistituting %d/%d", i, subplanInx);
        }
    }

    return true;
}
void OnlinePlanExpansionExecution::CoverFailedGoals()
{
    IOlcbpPlan::NodeQueue Q;
    IOlcbpPlan::NodeID currNodeId;
    IOlcbpPlan::NodeSerializedSet planRoots;
    IOlcbpPlan::NodeSet visitedNodes;
    IOlcbpPlan::NodeSet toCover;

    _ASSERTE(m_planRootNodeId != IOlcbpPlan::NullNodeID);

    Q.push(m_planRootNodeId);
    visitedNodes.insert(m_planRootNodeId);

    while (!Q.empty())
    {
        currNodeId = Q.front();
        Q.pop();

        if (!m_pOlcbpPlan->Contains(currNodeId))
        {
            LogWarning("A non existing node was there in the update queue, skipping it");
            continue;
        }

        for (auto childNodeId : m_pOlcbpPlan->GetAdjacentNodes(currNodeId))
        {
            if (visitedNodes.count(childNodeId) == 0)
            {
                if (IsGoalNode(childNodeId) && IsNodeDone(childNodeId))
                {
                    auto goalNode = m_pOlcbpPlan->GetNode(childNodeId);
                    if (m_coverGoals.count(childNodeId) == 0 && 
                        !goalNode->SuccessConditionsSatisfied(*g_Game) &&
                        m_backupNodes.count(childNodeId) == 0)
                    {
                        m_coverGoals.insert(childNodeId);
                        toCover.insert(childNodeId);
                    }
                }

                visitedNodes.insert(childNodeId);
                Q.push(childNodeId);
            }
        }
    }

    for (auto nodeId : toCover)
    {
        auto goalNode = m_pOlcbpPlan->GetNode(nodeId);
        GoalEx* backupNode = (GoalEx*)goalNode->Clone();
        m_backupNodes.insert(MakePair(backupNode->Id(), nodeId));
        backupNode->SetState(ESTATE_NotPrepared);
        m_pOlcbpPlan->AddNode(backupNode, backupNode->Id());
        m_nodeData[backupNode->Id()] = OlcbpPlanNodeData();
        m_nodeData[backupNode->Id()].ID = backupNode->Id();
        SetNodeSatisfyingGoal(backupNode->Id(), m_planRootNodeId);
        LinkNodes(m_planRootNodeId, backupNode->Id());
        auto& rootNodeData = GetNodeData(m_planRootNodeId);
        rootNodeData.SetWaitOnChildrenCount(rootNodeData.WaitOnChildrenCount + 1);
    }
}
void LfhdCbNodeSelector::Select(_Out_ IOlcbpPlan::NodeSet& goalsToUpdate,
    _Out_ IOlcbpPlan::NodeDQueue& actionsToUpdate,
    _Out_ IOlcbpPlan::NodeSet& snippetsToDestroy)
{
    IOlcbpPlan* pPlan = m_pPlanner->Plan();
    IOlcbpPlan::NodeQueue actionQ;
    IOlcbpPlan::NodeQueue goalQ;
    typedef unsigned GoalKey;
    map<GoalKey, stack<IOlcbpPlan::NodeID>> goalTable;

    // 1st pass: get ready nodes only
    m_pPlanner->GetReachableReadyNodes(actionQ, goalQ);

    while (!goalQ.empty())
    {
        IOlcbpPlan::NodeID currentGoalId = goalQ.front();
        goalQ.pop();

        if (!pPlan->Contains(currentGoalId))
            continue;

        GoalEx* pCurrGoal = (GoalEx*)pPlan->GetNode(currentGoalId);
        GoalKey typeKey = pCurrGoal->Key();

        if (!m_pPlanner->IsNodeDone(currentGoalId))
        {
            IOlcbpPlan::NodeID newActiveGoalId = currentGoalId;

            if (goalTable.count(typeKey) == 0)
                goalTable[typeKey].push(newActiveGoalId);
            else
            {
                auto& currentOverrideStack = goalTable[typeKey];
                IOlcbpPlan::NodeID currentActiveGoalId = currentOverrideStack.top();

                IOlcbpPlan::NodeSet ancestors;
                stack<IOlcbpPlan::NodeID> newOverrideStack;

                m_pPlanner->GetAncestorSatisfyingGoals(newActiveGoalId, ancestors);
                newOverrideStack.push(newActiveGoalId);

                while (!currentOverrideStack.empty())
                {
                    currentActiveGoalId = currentOverrideStack.top();

                    // Nodes belonging to my ancestors set should not be destroyed
                    // and should be kept in order
                    if (ancestors.count(currentActiveGoalId) != 0)
                    {
                        newOverrideStack.push(currentActiveGoalId);
                    }
                    else if (pPlan->Contains(currentActiveGoalId) &&
                        !m_pPlanner->IsNodeOpen(currentActiveGoalId) &&
                        !m_pPlanner->HasActiveAction(currentActiveGoalId))
                    {
                        snippetsToDestroy.insert(currentActiveGoalId);
                    }

                    currentOverrideStack.pop();
                }

                // Push back new stack into the current one in a LIFO order to reverse the original one
                while (!newOverrideStack.empty())
                {
                    currentOverrideStack.push(newOverrideStack.top());
                    newOverrideStack.pop();
                }
            }
        }
    }

    for (auto& r : goalTable)
    {
        goalsToUpdate.insert(r.second.top());
    }

    while (!actionQ.empty())
    {
        auto actionNodeId = actionQ.front();

        bool satisfyingGoalActive = goalsToUpdate.count(m_pPlanner->GetNodeData(actionNodeId).SatisfyingGoal) > 0;
        bool satisfyingGoalDone = m_pPlanner->IsNodeDone(m_pPlanner->GetNodeData(actionNodeId).SatisfyingGoal);

        if (satisfyingGoalActive || satisfyingGoalDone)
        {
            actionsToUpdate.push_back(actionNodeId);
        }

        actionQ.pop();
    }
}