import { abstractJSONSerializer } from "../../../json/abstractJSONSerializer.js";

/**
 *
 * @param {NodeInstance} node
 * @param {Map<string, function(v:Object):Object>} serializers
 * @param {Map<*,string>} classNames
 */
function nodeParametersToJSON(node, serializers, classNames) {
    const result = {};

    const parameters = node.parameters;

    for (const key in parameters) {

        const source = parameters[key];


        result[key] = abstractJSONSerializer(source, serializers, classNames);

    }

    return result;
}


/**
 *
 * @param {NodeGraph} graph
 * @param {Map<string, function(v:Object):Object>} [serializers]
 * @param {Map<*,string>} [classNames]
 */
export function serializeNodeGraphToJSON({ graph, serializers = new Map(), classNames = new Map() }) {
    /**
     *
     * @type {NodeDescription[]}
     */
    const description_objects = [];
    /**
     *
     * @type {Map<NodeDescription, number>}
     */
    const description_to_index_map = new Map();

    /**
     * JSON versions of descriptions
     * @type {Object[]}
     */
    const descriptions = [];

    // extract node descriptions
    const node_instances = graph.getNodes();
    for (let i = 0; i < node_instances.length; i++) {
        const node = node_instances[i];

        const description = node.description;

        let index = description_objects.indexOf(description);

        if (index !== -1) {
            // already recorded
            continue;
        }

        index = description_objects.length;
        description_objects.push(description);

        description_to_index_map.set(description, index);

        descriptions[index] = abstractJSONSerializer(description, serializers, classNames);
    }

    const nodes = [];

    for (let i = 0; i < node_instances.length; i++) {
        const node = node_instances[i];

        const parameters = nodeParametersToJSON(node, serializers, classNames);

        nodes.push({
            id: node.id,
            description: description_to_index_map.get(node.description),
            parameters: parameters
        });

    }

    const connections = [];

    graph.traverseConnections(connection => {

        connections.push({
            source: {
                instance: connection.source.instance.id,
                port: connection.source.port.id
            },
            target: {
                instance: connection.target.instance.id,
                port: connection.target.port.id
            }
        });

    });

    return {
        nodes,
        connections,
        descriptions
    };
}

