/********************************************************************************
 * Copyright (c) 2023 CEA-List
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 ********************************************************************************/

#include <memory>

#include "aidge/graph/Node.hpp"
#include "aidge/graph/GraphView.hpp"
#include "aidge/graph/Matching.hpp"
#include "aidge/operator/MetaOperator.hpp"
#include "aidge/recipes/Recipes.hpp"

size_t Aidge::fuseToMetaOps(std::shared_ptr<GraphView> graphView, const std::string& query, const std::string& type) {
    const auto metaType = (!type.empty()) ? type : query;
    const auto matches = SinglePassGraphMatching(graphView).match(query);

    size_t nbReplaced = 0;
    for (const auto& match : matches) {
        auto metaOp = MetaOperator(metaType.c_str(), match.graph->clone());
        // Clone does not clone implementation, which is therefore empty.
        // Use the root node backend for the meta op backend, even though some
        // matching nodes might be on a different backend, as nodes in the meta
        // op are required to share the same backend!
        const auto backend = match.graph->rootNode()->getOperator()->backend();
        if (!backend.empty()) {
            metaOp->getOperator()->setBackend(backend);
        }

        auto metaOpGraph = std::make_shared<GraphView>();
        metaOpGraph->add(metaOp, false);
        const auto success = GraphView::replace(match.graph, metaOpGraph);

        if (!success) {
            Log::notice("Could not replace sub-graph with meta operator");
        }
        else {
            ++nbReplaced;
        }
    }

    Log::info("Replaced {} (out of {}) matching sub-graph with meta operators", nbReplaced, matches.size());
    return nbReplaced;
}