//--------------------------------------------------------------------------------------------------------------
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);
    }
}