function gendecomposition(manager::ExperimentManager, path::AbstractString,
                          options_src::AbstractDict, options_dst::AbstractDict,
                          nb_added_edges::Int;
                          seed=nothing, verbose=false,
                          dec_type=:cholesky, merge_type=:molzahn,
                          kwargs...)
    name = basename(path)[1:end - 2]
    graph = construct_network_graph(path)
    nb_added_edges = gen.add_edges!(graph, options_src, options_dst, nb_added_edges)
    options_src_features = nb_added_edges != 0 ? format_options(options_src) : Dict()
    options_dst_features = nb_added_edges != 0 ? format_options(options_dst) : Dict()
    cliques, cliquetree, chordal_graph, nb_lc, dec_data = gen.decompose(graph, dec_type; kwargs...)
    features = get_features_decomposition(chordal_graph, length(dec_data["added_edges"]), cliques, cliquetree)
    features["nb_lc"] = nb_lc
    data = Mongoc.BSON("cliques" => cliques,
                       "cliquetree" => cliquetree,
                       "options_src" => options_src_features,
                       "options_dst" => options_dst_features,
                       "nb_added_edges" => nb_added_edges,
                       "dec_type" => string(dec_type))
    if haskey(kwargs, "ordering") 
        if typeof(kwargs["ordering"]) <: AbstractVector
            data["ordering"] = kwargs["ordering"]
        else
            data["ordering"] = string(kwargs["ordering"])
        end
    end
    for (key, val) in dec_data
        if typeof(val) <: Union{Number,AbstractString,Bool}
            features[key] = val
        elseif typeof(val) <: AbstractVector{T} where T <: Union{Number,AbstractString,Bool}
            data[key] = val
        end
    end
    instance_name, oid = db.push_decomposition!(manager.decompositions,
                                                name,
                                                data,
                                                features)
    db.add_decomposition_in_instance!(manager.instances, instance_name, oid)
    verbose && @info "($name, $oid, $nb_added_edges) inserted"
    return instance_name, oid
end

function gendecomposition_all(manager::ExperimentManager,
                              options_src::Dict, options_dst::Dict,
                              nb_added_edges::Int;
                              seed=nothing, verbose=false)
    instances_names = []
    oids = []
    paths_matpower = collect(db.getmatpowerpath_all(manager.instances))
    for path in paths_matpower
        instance_name, oid = gendecomposition(manager, path, options_src, options_dst, nb_added_edges; seed=seed, verbose=verbose)
        push!(instances_names, instance_name)
        push!(oids, oid)
    end
    return instances_names, oids
end

function gendecomposition_json(manager::ExperimentManager,
                               path::String, json_file::String;
                               verbose=false, dec_type=:cholesky,
                               kwargs...)
    config = JSON.parsefile(json_file)
    options_src = convertkeytosymbol(config["src"])
    options_dst = convertkeytosymbol(config["dst"])
    nb_added_edges = config["nb_added_edges"]
    seed = haskey(config, "seed") ? config["seed"] : 12345
    return gendecomposition(manager, path, options_src, options_dst, nb_added_edges; seed=seed, verbose=verbose, dec_type=dec_type)
end

function gendecomposition_all_json(manager::ExperimentManager,
                                   json_file::String; verbose=false,
                                   kwargs...)
    config = JSON.parsefile(json_file)
    options_src = convertkeytosymbol(config["src"])
    options_dst = convertkeytosymbol(config["dst"])
    nb_added_edges = config["nb_added_edges"]
    seed = haskey(config, "seed") ? config["seed"] : 12345
    return gendecomposition_all(manager, options_src, options_dst, nb_added_edges; seed=seed, verbose=verbose)
end

function gendecomposition_all_jsons(manager::ExperimentManager,
                                    json_file::String; verbose=false,
                                    kwargs...)
    ids = Dict()
    config = JSON.parsefile(json_file)
    for (key, val) in config
        options_src = convertkeytosymbol(val["src"])
        options_dst = convertkeytosymbol(val["dst"])
        nb_added_edges = val["nb_added_edges"]
        seed = haskey(val, "seed") ? val["seed"] : 12345
        ids[key] = gendecomposition_all(manager, options_src, options_dst, nb_added_edges; seed=seed, verbose=verbose)
    end
    return ids
end

function gendecomposition_mult_json(manager::ExperimentManager,
                                    json_file::String, paths_matpower::AbstractVector;
                                    verbose=false, kwargs...)
    config = JSON.parsefile(json_file)
    options_src = convertkeytosymbol(config["src"])
    options_dst = convertkeytosymbol(config["dst"])
    nb_added_edges = config["nb_added_edges"]
    seed = haskey(config, "seed") ? config["seed"] : 12345
    for path in paths_matpower
        gendecomposition(manager, path, options_src, options_dst, nb_added_edges; seed=seed, verbose=verbose)
    end
end

function genoriginal(manager::ExperimentManager, path; dec_type=:cholesky, verbose=false, kwargs...)
    return gendecomposition(manager, path, Dict(), Dict(), 0; dec_type=dec_type, verbose=verbose, kwargs...)
end

function genoriginal_mult(manager::ExperimentManager, path_matpower; dec_type=:cholesky, verbose=false, kwargs...)
    for path in paths_matpower
        genoriginal(manager, path; dec_type=dec_type, verbose=verbose, kwargs...)
    end
end

function genoriginal_all(manager::ExperimentManager; dec_type=:cholesky, verbose=false)
    paths_matpower = collect(db.getmatpowerpath_all(manager.instances))
    for path in paths_matpower
        genoriginal(manager, path; dec_type=dec_type, verbose=verbose, kwargs...)
    end
end

function genmerge_all(manager::ExperimentManager)
    for decomposition in manager.decompositions
        instance_name = decomposition["_id"]["instance_name"]
        oid = decomposition["_id"]["oid"]
        genmerge(manager, instance_name, oid; verbose=true)
    end
end

function genmerge_mult(manager::ExperimentManager, decompositions::AbstractVector; verbose=false)
    for decomposition in decompositions
        genmerge(manager, decomposition["instance_name"], decomposition["oid"])
    end
end

function genmerge(manager::ExperimentManager, instance_name::String,
                  oid::Union{String,UUID};
                  verbose=false,
                  merge_type=:molzahn,
                  dec_type=:cholesky,
                  merge_treshold_type=:nv,
                  merge_treshold::Float64=0.10,
                  kwargs...)
    decomposition = db.getdecomposition(manager.decompositions, instance_name, oid)
    cliques = copy(decomposition["cliques"])
    cliquetree = copy(decomposition["cliquetree"])
    paths = db.getpath_one(manager.instances, instance_name)
    alpha, beta, c = get_param_merge(paths["params"])
    array = merge_treshold_type == :nv ? Base.OneTo(decomposition["features"]["chordal_graph"]["nv"]) : cliques
    cliques, cliquetree, new_edges = gen.merge(cliques, cliquetree, merge_type;
                                               treshold=gen.treshold_percent(array, merge_treshold),
                                               alpha=alpha,
                                               beta=beta,
                                               m=get_nb_constraint(paths["OPF_ctr"]),
                                               nb_lc=decomposition["features"]["nb_lc"],
                                               kwargs...)
    chordal_graph = construct_graph_from_cliques(cliques)
    nb_added_edges = nv(chordal_graph) - db.getnv(manager.instances, instance_name)
    features = get_features_decomposition(chordal_graph, nb_added_edges, cliques, cliquetree)
    features["nb_lc"] = get_nb_lc(cliques, cliquetree)
    data = Mongoc.BSON("cliques" => cliques,
                       "cliquetree" => cliquetree,
                       "nb_added_edges" => -1,
                       "origin_oid" => oid,
                       "origin_nb_added_edges" => decomposition["nb_added_edges"],
                       "merge_treshold" => merge_treshold)
    instance_name, oid = db.push_decomposition!(manager.decompositions,
                                                instance_name,
                                                data,
                                                features)
    db.add_decomposition_in_instance!(manager.instances, instance_name, oid)
    db.add_merge_in_decomposition!(manager.decompositions,
                                   instance_name,
                                   decomposition["_id"]["oid"],
                                   string(oid),
                                   string(merge_type),
                                   string(merge_treshold_type),
                                   merge_treshold)
    verbose && @info "Merging of ($instance_name, $oid, $(decomposition["nb_added_edges"]) inserted"
    return instance_name, oid
end

function gencombine(manager::ExperimentManager, instance_name::String,
                    oid::Union{String,UUID}, k=3;
                    combine_type::Symbol=:intersect,
                    verbose=false,
                    neighbors_g=nothing)
    neighbors_indexes = db.getkneighbors_indexes(manager.decompositions, instance_name, oid, k, neighbors_g)
    neighbor = collect(manager.decompositions)[neighbors_indexes[rand(1:k)]]
    return gencombine(manager,
                      instance_name,
                      oid,
                      neighbor["_id"]["oid"];
                      combine_type=combine_type,
                      verbose=verbose)
end

function gencombine(manager::ExperimentManager, instance_name::String,
                    oid1::Union{String,UUID}, oid2::Union{String,UUID};
                    combine_type::Symbol=:intersect,
                    verbose=false)
    decomposition1 = db.getdecomposition(manager.decompositions, instance_name, oid1)
    decomposition2 = db.getdecomposition(manager.decompositions, instance_name, oid2)
    instance = db.getinstance(manager.instances, instance_name)
    g1 = construct_graph_from_cliques(decomposition1["cliques"])
    g2 = construct_graph_from_cliques(decomposition2["cliques"])
    combined_results = gen.combine_decomposition(g1, g2; combine_type=combine_type, instance_path=instance["paths"]["matpower"])
    isnothing(combined_results) && return nothing
    cliques, cliquetree, cg, nb_lc, data = combined_results
    merge!(data, Mongoc.BSON("cliques" => cliques,
                             "cliquetree" => cliquetree,
                             "nb_added_edges" => -2,
                             "oid1" => oid1,
                             "oid2" => oid2))
    nb_added_edges = nv(cg) - db.getnv(manager.instances, instance_name)
    features = get_features_decomposition(cg, nb_added_edges, cliques, cliquetree)
    instance_name, oid = db.push_decomposition!(manager.decompositions,
                                                instance_name,
                                                data,
                                                features)
    db.add_decomposition_in_instance!(manager.instances, instance_name, oid)
    verbose && @info "Combination of $(instance_name): $(oid1) and $(oid2) inserted"
    return instance_name, oid
end

