# Source: objects/node/Node.js

    import {NodeSocket} from "./NodeSocket";
    import {RoundedBox} from "../RoundedBox";
    import {Object2D} from "../../Object2D";

    /**
     * Node objects can be connected between them to create graphs.
     *
     * Each node contains inputs, outputs and a set of attributes containing their state. Inputs can be connected to outputs of other nodes, and vice-versa.
     *
     * This class implements node basic functionality, the logic to connect node and define inputs/outputs of the nodes.
     *
     * @class
     * @extends {RoundedBox}
     */
    function Node()
    {
    	RoundedBox.call(this);

    	this.draggable = true;

    	/**
    	 * List of inputs of the node.
    	 *
    	 * @type {NodeSocket[]}
    	 */
    	this.inputs = [];

    	/**
    	 * List of outputs of the node.
    	 *
    	 * @type {NodeSocket[]}
    	 */
    	this.outputs = [];
    }

    Node.prototype = Object.create(RoundedBox.prototype);
    Node.prototype.constructor = Node;
    Node.prototype.type = "Node";
    Object2D.register(Node, "Node");

    /**
     * This method should be used for the node to register their socket inputs/outputs.
     *
     * It is called automatically after the node is added to the node graph to create sockets.
     */
    Node.prototype.registerSockets = null;

    /**
     * Add input to this node, can be connected to other nodes to receive data.
     *
     * @param {string} type Data type of the node socket.
     * @param {string} name Name of the node socket.
     * @return {NodeSocket} Node socket created for this node.
     */
    Node.prototype.addInput = function(type, name)
    {
    	var socket = new NodeSocket(this, NodeSocket.INPUT, type, name);
    	this.inputs.push(socket);
    	this.parent.add(socket);
    	return socket;
    };

    /**
     * Add output socket to this node, can be connected to other nodes to send data.
     *
     * @param {string} type Data type of the node socket.
     * @param {string} name Name of the node socket.
     * @return {NodeSocket} Node socket created for this node.
     */
    Node.prototype.addOutput = function(type, name)
    {
    	var socket = new NodeSocket(this, NodeSocket.OUTPUT, type, name);
    	this.outputs.push(socket);
    	this.parent.add(socket);
    	return socket;
    };

    /**
     * Get a output socket by its name. If there are multiple sockets with the same name only the first one found is returned.
     *
     * @param {string} name Name of the node socket to get.
     * @return {NodeSocket} Node socket if it was found, null otherwise.
     */
    Node.prototype.getOutput = function(name)
    {
    	for(var i = 0; i < this.outputs.length; i++)
    	{
    		if(this.outputs[i].name === name)
    		{
    			return this.outputs[i];
    		}
    	}

    	return null;
    };

    /**
     * Get a input socket by its name. If there are multiple sockets with the same name only the first one found is returned.
     *
     * @param {string} name Name of the node socket to get.
     * @return {NodeSocket} Node socket if it was found, null otherwise.
     */
    Node.prototype.getInput = function(name)
    {
    	for(var i = 0; i < this.inputs.length; i++)
    	{
    		if(this.inputs[i].name === name)
    		{
    			return this.inputs[i];
    		}
    	}

    	return null;
    };

    Node.prototype.destroy = function()
    {
    	RoundedBox.prototype.destroy.call(this);

    	for(var i = 0; i < this.inputs.length; i++)
    	{
    		this.inputs[i].destroy();
    	}

    	for(var i = 0; i < this.outputs.length; i++)
    	{
    		this.outputs[i].destroy();
    	}
    };

    Node.prototype.onUpdate = function()
    {
    	var height = this.box.max.y - this.box.min.y;

    	// Input hooks position
    	var step = height / (this.inputs.length + 1);
    	var start = this.box.min.y + step;

    	for(var i = 0; i < this.inputs.length; i++)
    	{
    		this.inputs[i].position.set(this.position.x + this.box.min.x, this.position.y + (start + step * i));
    	}

    	// Output hooks position
    	step = height / (this.outputs.length + 1);
    	start = this.box.min.y + step;

    	for(var i = 0; i < this.outputs.length; i++)
    	{
    		this.outputs[i].position.set(this.position.x + this.box.max.x, this.position.y + (start + step * i));
    	}
    };

    Node.prototype.serialize = function(recursive)
    {
    	var data = RoundedBox.prototype.serialize.call(this, recursive);

    	data.inputs = [];
    	for(var i = 0; i < this.inputs.length; i++)
    	{
    		data.inputs.push(this.inputs[i].uuid);
    	}

    	data.outputs = [];
    	for(var i = 0; i < this.outputs.length; i++)
    	{
    		data.outputs.push(this.outputs[i].uuid);
    	}

    	return data;
    };

    Node.prototype.parse = function(data, root)
    {
    	RoundedBox.prototype.parse.call(this, data, root);

    	for(var i = 0; i < data.inputs.length; i++)
    	{
    		this.inputs.push(root.getChildByUUID(data.inputs[i]));
    	}

    	for(var i = 0; i < data.outputs.length; i++)
    	{
    		this.outputs.push(root.getChildByUUID(data.outputs[i]));
    	}
    };

    export {Node};