<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
    <link rel="stylesheet" href="../vendors/jointjs/css/joint.min.css" />
    <script src="../vendors/jointjs/dependencies/jquery.min.js"></script>
    <script src="../vendors/jointjs/dependencies//lodash.min.js"></script>
    <script src="../vendors/jointjs/dependencies/backbone-min.js"></script>
	<script src="../vendors/jointjs/js/joint.min.js"></script>
	<script src="../vendors/jointjs/lib/dagre.min.js"></script>
	<script src="../vendors/jointjs/lib/graphlib.min.js"></script>
	<script src="../vendors/jointjs/plugins/joint.layout.DirectedGraph.min.js"></script>
	<link rel="stylesheet" type="text/css" href="../css/graph.css" />
</head>
<body>
  <div id="graphHolder"></div>
  
  <script type="text/javascript">
  
	//adjacencyList, hard-encoded now but will be the result of a request to the server, format may change
	var vmList = {
		'vms': [
			'VM 1',
			'VM 2',
			'VM 3',
			'VM 4',
			'VM 5',
			'VM 6',
			'VM 7',
			'VM 8',
			'VM 9',
			'VM 10'
		],
		'links': [
			['VM 1', 'VM 2', 'I1', 'I2'],
			['VM 2', 'VM 3', 'I3', 'I4'],
			['VM 1', 'VM 3', 'I5', 'I6'],
			['VM 2', 'VM 4', 'I5', 'I6'],
			['VM 4', 'VM 5', 'I5', 'I6'],
			['VM 4', 'VM 6', 'I5', 'I6'],
			['VM 4', 'VM 1', 'I5', 'I6'],
			['VM 7', 'VM 4', 'I5', 'I6'],
			['VM 7', 'VM 3', 'I5', 'I6'],
			['VM 6', 'VM 8', 'I5', 'I6'],
			['VM 3', 'VM 9', 'I5', 'I6'],
			['VM 3', 'VM 10', 'I5', 'I6']
		]
	};
	
	
	//Custom element for inserting html
	joint.shapes.html = {};
	joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
		defaults: joint.util.deepSupplement({
			type: 'html.Element',
			attrs: {
				rect: { stroke: 'none', 'fill-opacity': 0 }
			}
		}, joint.shapes.basic.Rect.prototype.defaults)
	});
		
	//Custom view for this element
	joint.shapes.html.ElementView = joint.dia.ElementView.extend({

		initialize: function() {
			_.bindAll(this, 'updateBox');
			joint.dia.ElementView.prototype.initialize.apply(this, arguments);

			this.$box = $(_.template(this.model.get('html'))());
			// Prevent paper from handling pointerdown.
			this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); });
			// This is an example of reacting on the input change and storing the input data in the cell model.
			this.$box.find('input').on('change', _.bind(function(evt) {
				this.model.set('input', $(evt.target).val());
			}, this));
			this.$box.find('select').on('change', _.bind(function(evt) {
				this.model.set('select', $(evt.target).val());
			}, this));
			this.$box.find('select').val(this.model.get('select'));
			//this.$box.find('.config').on('click', CALL OVERLAY HERE);
			// Update the box position whenever the underlying model changes.
			this.model.on('change', this.updateBox, this);
			// Remove the box when the model gets removed from the graph.
			this.model.on('remove', this.removeBox, this);

			this.updateBox();
		},
		render: function() {
			joint.dia.ElementView.prototype.render.apply(this, arguments);
			this.paper.$el.prepend(this.$box);
			this.updateBox();
			return this;
		},
		updateBox: function() {
			// Set the position and dimension of the box so that it covers the JointJS element.
			var bbox = this.model.getBBox();
			// Example of updating the HTML with a data stored in the cell model.
			this.$box.find('label').text(this.model.get('name'));
			this.$box.find('span').text(this.model.get('select'));
			this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
		},
		removeBox: function(evt) {
			this.$box.remove();
		}
	});
	
  
	//Read the adjacencyList and build the elements and the links according to it
	function buildGraphFromAdjacencyList(adjacencyList) {

		var elements = [];
		var links = [];
		
		_.each(adjacencyList['vms'], function(vm) {
			elements.push(makeElement(vm));
		});
		
		_.each(adjacencyList['links'], function(link) {
			links.push(makeLink(link[0], link[1] , link[2], link[3]));
		});

		// Links must be added after all the elements. This is because when the links
		// are added to the graph, link source/target
		// elements must be in the graph already.
		return elements.concat(links);
	}
	
	//Return a new link linking the parent and child elements with the interfaces names given in parameters 
	function makeLink(parentElementLabel, childElementLabel, Iparent, Ichild) {

		return new joint.dia.Link({
			source: { id: parentElementLabel },
			target: { id: childElementLabel },
			labels: [
				{ position: 20, attrs: { text: { text: Iparent } }},
				{ position: -20, attrs: { text: { text: Ichild } }}
			]
		});
	}

	//Return a new element
	function makeElement(label) {

		var maxLineLength = _.max(label.split('\n'), function(l) { return l.length; }).length;

		// Compute width/height of the rectangle based on the number 
		// of lines in the label and the letter size. 0.6 * letterSize is
		// an approximation of the monospace font letter width.
		var width = 130;
		var height = 80;

		return new joint.shapes.html.Element({
            id: label,
			name: label,
            size: { width: width, height: height },

            html: [
				'<div class="html-element">',
				'<img src="../images/ON.png">',
				'<label></label>',
				'<input type="image" src="../images/gear.png" class="config"></button>',
				'</div>'
			].join(''),

            attrs: {
                rect: {
                    fill: '#FE854F',
                    width: width,
                    height: height,
                    rx: 5,
                    ry: 5,
                    stroke: 'none'
                }
            }
        });
	}
	
	var graph = new joint.dia.Graph;

    var paper = new joint.dia.Paper({
        el: $('#graphHolder'),
        width: 2000,
        height: 2000,
        model: graph,
        gridSize: 1
    });
	
	paper.$el.css('pointer-events', 'none');
	
    var cells = buildGraphFromAdjacencyList(vmList);
    graph.resetCells(cells);
    joint.layout.DirectedGraph.layout(graph, {
		setLinkVertices: false,
		//Top to bottom generation
		rankDir: "TB",
		nodeSep: 150,
		edgeSep: 150,
		rankSep: 150
	});

  </script>
</body>
</html>