<commit_before>'use strict';

angular.module('subutai.environment.adv-controller', [])
	.controller('AdvancedEnvironmentCtrl', AdvancedEnvironmentCtrl);

AdvancedEnvironmentCtrl.$inject = ['$scope', 'environmentService', 'trackerSrv', 'SweetAlert', 'ngDialog'];

var graph = new joint.dia.Graph;

function AdvancedEnvironmentCtrl($scope, environmentService, trackerSrv, SweetAlert, ngDialog) {

	var vm = this;
	var GRID_CELL_SIZE = 100;
	var GRID_SIZE = 100;

	vm.buildEnvironment = buildEnvironment;

	vm.domainStrategies = [];
	vm.strategies = [];
	vm.activeCloudTab = 'peers';

	vm.peerIds = [];
	vm.resourceHosts = [];
	vm.currentResourceHosts = [];
	vm.advancedEnv = {};
	vm.nodeStatus = 'Add to';
	vm.nodeList = [];
	vm.colors = quotaColors;
	vm.templates = [];

	vm.cubeGrowth = 1;
	vm.environment2BuildName = 'Environment name';
	vm.currentPeer = false;
	vm.currentPeerIndex = false;

	// functions

	vm.initJointJs = initJointJs;
	vm.buildEnvironmentByJoint = buildEnvironmentByJoint;
	vm.clearWorkspace = clearWorkspace;
	vm.addSettingsToTemplate = addSettingsToTemplate;

	vm.showResources = showResources;
	vm.addResource2Build = addResource2Build;

	/*environmentService.getTemplates()
		.success(function (data) {
			vm.templates = data;
		})
		.error(function (data) {
			VARS_MODAL_ERROR( SweetAlert, 'Error on getting templates ' + data );
		});*/

	vm.templates = ['mongo', 'cassandra', 'master', 'hadoop'];

	environmentService.getStrategies().success(function (data) {
		vm.strategies = data;
	});

	environmentService.getDomainStrategies().success(function (data) {
		vm.domainStrategies = data;
	});

	environmentService.getPeers().success(function (data) {
		vm.peerIds = data;
	});

	/*peerRegistrationService.getResourceHosts().success(function (data) {
		vm.resourceHosts = data;
	});*/

	function getLogsFromTracker(environmentId) {
		trackerSrv.getOperations('ENVIRONMENT MANAGER', moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD'), 100)
			.success(function (data) {
				for(var i = 0; i < data.length; i++) {
					if(data[i].description.includes(environmentId)) {
						getLogById(data[i].id, true);
						break;
					}
				}
				return false;
			}).error(function(error) {
				console.log(error);
			});		
	}

	function checkLastLog(status) {
		var lastLog = vm.logMessages[vm.logMessages.length - 1];
		lastLog.time = moment().format('HH:mm:ss');
		if(status === true) {
			lastLog.status = 'success';
			lastLog.classes = ['fa-check', 'g-text-green'];
		} else {
			lastLog.status = 'success';
			lastLog.classes = ['fa-times', 'g-text-red'];
		}
	}

	function getLogById(id, checkLast, prevLogs) {
		if(checkLast === undefined || checkLast === null) checkLast = false;
		if(prevLogs === undefined || prevLogs === null) prevLogs = false;
		trackerSrv.getOperation('ENVIRONMENT MANAGER', id)
			.success(function (data) {
				if(data.state == 'RUNNING') {

					if(checkLast) {
						checkLastLog(true);
					}

					var logs = data.log.split(/(?:\r\n|\r|\n)/g);
					var result = [];
					var i = 0;
					if(prevLogs) {
						i = prevLogs.length;
						if(logs.length > prevLogs.length) {
							checkLastLog(true);
						}
					}
					for(i; i < logs.length; i++) {

						var logTime = moment().format('HH:mm:ss');
						var logStatus = 'success';
						var logClasses = ['fa-check', 'g-text-green'];
						if(i+1 == logs.length) {
							logTime = '';
							logStatus = 'in-progress';
							logClasses = ['fa-spinner', 'fa-pulse'];
						}

						var  currentLog = {
							"time": logTime,
							"status": logStatus,
							"classes": logClasses,
							"text": logs[i]
						};
						result.push(currentLog);
					}

					vm.logMessages = vm.logMessages.concat(result);

					setTimeout(function() {
						getLogById(id, false, logs);
					}, 2000);					

					return result;
				} else {
					if(data.state == 'FAILED') {
						checkLastLog(false);
					} else {
						SweetAlert.swal("Success!", "Your environment has been built successfully.", "success");
						checkLastLog(true);
					}
				}
			}).error(function(error) {
				console.log(error);
			});
	}

	vm.logMessages = [];
	function buildEnvironment() {
		vm.buildStep = 'showLogs';

		vm.logMessages = [];
		var currentLog = {
			"time": '',
			"status": 'in-progress',
			"classes": ['fa-spinner', 'fa-pulse'],
			"text": 'Registering environment'
		};
		vm.logMessages.push(currentLog);

		environmentService.startEnvironmentAutoBuild(vm.environment2BuildName, JSON.stringify(vm.containers2Build))
			.success(function(data){
				vm.newEnvID = data;
				currentLog.status = 'success';
				currentLog.classes = ['fa-check', 'g-text-green'];
				currentLog.time = moment().format('HH:mm:ss');

				currentLog = {
					"time": '',
					"status": 'in-progress',
					"classes": ['fa-spinner', 'fa-pulse'],
					"text": 'Environment creation has been started'
				};
				vm.logMessages.push(currentLog);

				//var logId = getLogsFromTracker(vm.newEnvID);
				var logId = getLogsFromTracker(vm.environment2BuildName);

			}).error(function(error){
				if(error && error.ERROR === undefined) {
					VARS_MODAL_ERROR( SweetAlert, 'Error: ' + error );
				} else {
					VARS_MODAL_ERROR( SweetAlert, 'Error: ' + error.ERROR );
				}
				currentLog.status = 'fail';
				currentLog.classes = ['fa-times', 'g-text-red'];
				currentLog.time = moment().format('HH:mm:ss');				
			});
	}

	function showResources(peerId, resourcesId, index) {
		vm.currentResourceHosts = resourcesId;
		vm.currentPeer = peerId;
		vm.currentPeerIndex = index;
		$('.b-cloud-add-tools').animate({'left': '-200px'}, 300);
	}

	//add resource host
	function addResource2Build(currentResource, index) {
		//var pos = calculatePeerPos();
		var posX = calculatePeerPos();
		var posY = calculateResourceHostPos(vm.currentPeer);

		if( PEER_MAP[vm.currentPeer] !== undefined ) {
			if( PEER_MAP[vm.currentPeer].rh[currentResource] !== undefined ) {
				return PEER_MAP[vm.currentPeer].rh[currentResource];
			}
		} else {
			PEER_MAP[vm.currentPeer] = { rh: [], position : posX };
		}

		var resourceHost = new joint.shapes.resourceHostHtml.Element({
			//position: { x: 40, y: 40 },
			position: { x: PEER_MAP[vm.currentPeer].position * ( PEER_WIDTH + PEER_SPACE ), y: posY },
			size: { width: 155, height: 173 },
			peerId: vm.currentPeer,
			hostId: currentResource,
			children: 0,
			grid: [],
			gridSize: { size: 2 },
			'resourceHostName': 'RH' + (index + 1),
			'peerName': 'Peer ' + (vm.currentPeerIndex + 1),
			'addClass': 'b-resource-host_last'
		});

		if(Object.keys(PEER_MAP[vm.currentPeer].rh).length > 0) {
			var lastResourceInPeer = graph.getCell(PEER_MAP[vm.currentPeer].rh[
				Object.keys(PEER_MAP[vm.currentPeer].rh)[
					Object.keys(PEER_MAP[vm.currentPeer].rh).length - 1
				]
			]);
			lastResourceInPeer.set('addClass', '');
			lastResourceInPeer.set('removeClass', 'b-resource-host_last');
		}

		graph.addCell(resourceHost);
		PEER_MAP[vm.currentPeer].rh[currentResource] = resourceHost.id;

		return false;
	}

	function calculateResourceHostPos(peerId) {
		if(PEER_MAP[peerId]) {
			var posY = 30;
			for(var key in PEER_MAP[peerId].rh) {
				var currentResource = graph.getCell(PEER_MAP[peerId].rh[key]);
				var currentResourceSize = currentResource.get('size');
				var currentResourcePos = currentResource.get('position');
				posY = posY + (currentResourcePos.x + currentResourceSize.height);
			}
			return posY - 8;
		} else {
			return 30;
		}
	}

	function calculatePeerPos() {
		var pos = [];

		for (var key in PEER_MAP) {
			if (PEER_MAP.hasOwnProperty(key)) {
				pos.push( PEER_MAP[key].position );
			}
		}

		if( pos.length == 0 )
			return 0;
		if( pos.length == 1 )
			return 1;

		pos.sort();

		for( var i = 1; i < pos.length; i++ )
		{
			if( pos[i - 1] + 1 !== pos[i] )
			{
				return pos[i - 1] + 1;
			}
		}

		return pos[pos.length - 1];
	}

	//custom shapes
	joint.shapes.tm = {};

	//simple creatiom templates
	joint.shapes.tm.toolElement = joint.shapes.basic.Generic.extend({

		toolMarkup: [
			'<g class="element-tools">',
				'<g class="element-tool-remove">',
					'<circle fill="#F8FBFD" r="8" stroke="#dcdcdc"/>',
					'<polygon transform="scale(1.2) translate(-5, -5)" fill="#292F6C" points="8.4,2.4 7.6,1.6 5,4.3 2.4,1.6 1.6,2.4 4.3,5 1.6,7.6 2.4,8.4 5,5.7 7.6,8.4 8.4,7.6 5.7,5 "/>',
					'<title>Remove</title>',
				'</g>',
				/*'<g class="element-call-menu">',
					'<circle fill="#F8FBFD" r="8" stroke="#dcdcdc"/>',
					'<polygon transform="scale(1.2) translate(-5, -5)" fill="#292F6C" points="8.4,2.4 7.6,1.6 5,4.3 2.4,1.6 1.6,2.4 4.3,5 1.6,7.6 2.4,8.4 5,5.7 7.6,8.4 8.4,7.6 5.7,5 "/>',
					'<title>Menu</title>',
				'</g>',*/
			'</g>'
		].join(''),

		defaults: joint.util.deepSupplement({
			attrs: {
				text: { 'font-weight': 400, 'font-size': 'small', fill: 'black', 'text-anchor': 'middle', 'ref-x': .5, 'ref-y': .5, 'y-alignment': 'middle' },
				'g.element-call-menu': {'ref-x': 18, 'ref-y': 25}
			},
		}, joint.shapes.basic.Generic.prototype.defaults)

	});

	joint.shapes.tm.devElement = joint.shapes.tm.toolElement.extend({

		markup: [
			'<g class="rotatable">',
				'<g class="scalable">',
					'<rect class="b-border"/>',
				'</g>',
				'<title/>',
				'<image/>',
				'<rect class="b-magnet"/>',
				'<g class="b-container-plus-icon">',
					'<line fill="none" stroke="#FFFFFF" stroke-miterlimit="10" x1="0" y1="4.5" x2="9" y2="4.5"/>',
					'<line fill="none" stroke="#FFFFFF" stroke-miterlimit="10" x1="4.5" y1="0" x2="4.5" y2="9"/>',
				'</g>',
			'</g>'
		].join(''),

		defaults: joint.util.deepSupplement({
			type: 'tm.devElement',
			size: { width: 40, height: 40 },
			attrs: {
				title: {text: 'Static Tooltip'},
				'rect.b-border': {fill: '#fff', stroke: '#dcdcdc', 'stroke-width': 1, width: 40, height: 40, rx: 50, ry: 50},
				//'rect.b-magnet': {fill: '#04346E', width: 10, height: 10, rx: 50, ry: 50, magnet: true, transform: 'translate(16,28)'},
				'rect.b-magnet': {fill: '#04346E', width: 10, height: 10, rx: 50, ry: 50, transform: 'translate(16,28)'},
				'g.b-container-plus-icon': {'ref-x': 17.5, 'ref-y': 30, ref: 'rect', transform: 'scale(0.8)'},
				image: {'ref-x': 9, 'ref-y': 9, ref: 'rect', width: 25, height: 25},
			}
		}, joint.shapes.tm.toolElement.prototype.defaults)
	});

	//custom view
	joint.shapes.tm.ToolElementView = joint.dia.ElementView.extend({
		initialize: function() {
			joint.dia.ElementView.prototype.initialize.apply(this, arguments);
		},
		render: function () {
			joint.dia.ElementView.prototype.render.apply(this, arguments);
			this.renderTools();
			this.update();
			return this;
		},
		renderTools: function () {
			var toolMarkup = this.model.toolMarkup || this.model.get('toolMarkup');
			if (toolMarkup) {
				var nodes = V(toolMarkup);
				V(this.el).append(nodes);
			}
			return this;
		},
		mouseover: function(evt, x, y) {
		},
		pointerclick: function (evt, x, y) {
			this._dx = x;
			this._dy = y;
			this._action = '';
			var className = evt.target.parentNode.getAttribute('class');
			switch (className) {
				case 'element-tool-remove':
					var rh = this.model.attributes.rh;
					delete graph.getCell(rh.model).attributes.grid[rh.x][rh.y];
					this.model.remove();
					return;
					break;
				case 'element-call-menu':
					console.log(this.model);
					var elementPos = this.model.get('position');
					$('.js-dropen-menu').css({
						'left': (elementPos.x + 70) + 'px',
						'top': (elementPos.y + 83) + 'px',
						'display': 'block'
					});
					return;
					break;
				case 'rotatable':
					console.log(this.model);
					vm.currentTemplate = this.model;
					ngDialog.open({
						template: 'subutai-app/environment/partials/popups/templateSettingsAdvanced.html',
						scope: $scope
					});
					return;
					break;
				default:
			}
			joint.dia.CellView.prototype.pointerclick.apply(this, arguments);
		}
	});
	joint.shapes.tm.devElementView = joint.shapes.tm.ToolElementView;

	//resource host object
	joint.shapes.resourceHostHtml = {};
	joint.shapes.resourceHostHtml.Element = joint.shapes.basic.Rect.extend({
		defaults: joint.util.deepSupplement({
			type: 'resourceHostHtml.Element',
			attrs: {
				rect: { stroke: 'none', 'fill-opacity': 0, 'pointer-events':'none' }
			}
		}, joint.shapes.basic.Rect.prototype.defaults)
	});

	// Resource host html.
	// -------------------------------------------------------------------------

	joint.shapes.resourceHostHtml.ElementView = joint.dia.ElementView.extend({

		template: [
			'<div class="b-resource-host">',
				'<div class="b-peer-title"></div>',
				'<button class="b-peer-delete js-delete-peer"></button>',
				'<div class="b-resource-host__inner">',
					'<div class="b-recouce-host-title"></div>',
					'<div class="b-resource-host__containers">',
						'<div class="b-resource-host-containers">',
						'</div>',
					'</div>',
				'</div>',
			'</div>'
		].join(''),

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

			this.$box = $(_.template(this.template)());
			this.$box.find('.js-delete-peer').on('click', _.bind(this.model.remove, this.model));
			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();

			if(this.model.get('addClass')) {
				//this.$box.find('.b-resource-host').addClass(this.model.get('className'));
				this.$box.addClass(this.model.get('addClass'));
			}

			if(this.model.get('removeClass')) {
				this.$box.removeClass(this.model.get('removeClass'));
			}

			this.$box.find('.b-peer-title').text(this.model.get('peerName'));
			this.$box.find('.b-recouce-host-title').text(this.model.get('resourceHostName'));
			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) {
			delete PEER_MAP[this.model.get('peerId')].rh[this.model.get('hostId')];
			if(Object.keys(PEER_MAP[this.model.get('peerId')].rh).length == 0) {
				delete PEER_MAP[this.model.get('peerId')];
			} else {
				var lastResourceInPeer = graph.getCell(PEER_MAP[vm.currentPeer].rh[
					Object.keys(PEER_MAP[vm.currentPeer].rh)[
						Object.keys(PEER_MAP[vm.currentPeer].rh).length - 1
					]
				]);
				lastResourceInPeer.set('addClass', 'b-resource-host_last');
				lastResourceInPeer.set('removeClass', '');
			}

			this.$box.remove();
		}
	});	

	function initJointJs() {

		var paper = new joint.dia.Paper({
			el: $('#js-environment-creation'),
			width: '100%',
			height: '100%',
			model: graph,
			gridSize: 1
		});

	paper.on('cell:pointerdown', function(cellView) {
		cellView.prevPos = cellView.model.get('position');
	});

	paper.on('cell:pointerup', function(cellView) {

		if( cellView.model.get( 'containerName' ) === undefined )
			return;<commit_msg>advanced environment creation remove resource fix<commit_after>'use strict';

angular.module('subutai.environment.adv-controller', [])
	.controller('AdvancedEnvironmentCtrl', AdvancedEnvironmentCtrl);

AdvancedEnvironmentCtrl.$inject = ['$scope', 'environmentService', 'trackerSrv', 'SweetAlert', 'ngDialog'];

var graph = new joint.dia.Graph;

function AdvancedEnvironmentCtrl($scope, environmentService, trackerSrv, SweetAlert, ngDialog) {

	var vm = this;
	var GRID_CELL_SIZE = 100;
	var GRID_SIZE = 100;

	vm.buildEnvironment = buildEnvironment;

	vm.domainStrategies = [];
	vm.strategies = [];
	vm.activeCloudTab = 'peers';

	vm.peerIds = [];
	vm.resourceHosts = [];
	vm.currentResourceHosts = [];
	vm.advancedEnv = {};
	vm.nodeStatus = 'Add to';
	vm.nodeList = [];
	vm.colors = quotaColors;
	vm.templates = [];

	vm.cubeGrowth = 1;
	vm.environment2BuildName = 'Environment name';
	vm.currentPeer = false;
	vm.currentPeerIndex = false;

	// functions

	vm.initJointJs = initJointJs;
	vm.buildEnvironmentByJoint = buildEnvironmentByJoint;
	vm.clearWorkspace = clearWorkspace;
	vm.addSettingsToTemplate = addSettingsToTemplate;

	vm.showResources = showResources;
	vm.addResource2Build = addResource2Build;

	/*environmentService.getTemplates()
		.success(function (data) {
			vm.templates = data;
		})
		.error(function (data) {
			VARS_MODAL_ERROR( SweetAlert, 'Error on getting templates ' + data );
		});*/

	vm.templates = ['mongo', 'cassandra', 'master', 'hadoop'];

	environmentService.getStrategies().success(function (data) {
		vm.strategies = data;
	});

	environmentService.getDomainStrategies().success(function (data) {
		vm.domainStrategies = data;
	});

	environmentService.getPeers().success(function (data) {
		vm.peerIds = data;
	});

	/*peerRegistrationService.getResourceHosts().success(function (data) {
		vm.resourceHosts = data;
	});*/

	function getLogsFromTracker(environmentId) {
		trackerSrv.getOperations('ENVIRONMENT MANAGER', moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD'), 100)
			.success(function (data) {
				for(var i = 0; i < data.length; i++) {
					if(data[i].description.includes(environmentId)) {
						getLogById(data[i].id, true);
						break;
					}
				}
				return false;
			}).error(function(error) {
				console.log(error);
			});		
	}

	function checkLastLog(status) {
		var lastLog = vm.logMessages[vm.logMessages.length - 1];
		lastLog.time = moment().format('HH:mm:ss');
		if(status === true) {
			lastLog.status = 'success';
			lastLog.classes = ['fa-check', 'g-text-green'];
		} else {
			lastLog.status = 'success';
			lastLog.classes = ['fa-times', 'g-text-red'];
		}
	}

	function getLogById(id, checkLast, prevLogs) {
		if(checkLast === undefined || checkLast === null) checkLast = false;
		if(prevLogs === undefined || prevLogs === null) prevLogs = false;
		trackerSrv.getOperation('ENVIRONMENT MANAGER', id)
			.success(function (data) {
				if(data.state == 'RUNNING') {

					if(checkLast) {
						checkLastLog(true);
					}

					var logs = data.log.split(/(?:\r\n|\r|\n)/g);
					var result = [];
					var i = 0;
					if(prevLogs) {
						i = prevLogs.length;
						if(logs.length > prevLogs.length) {
							checkLastLog(true);
						}
					}
					for(i; i < logs.length; i++) {

						var logTime = moment().format('HH:mm:ss');
						var logStatus = 'success';
						var logClasses = ['fa-check', 'g-text-green'];
						if(i+1 == logs.length) {
							logTime = '';
							logStatus = 'in-progress';
							logClasses = ['fa-spinner', 'fa-pulse'];
						}

						var  currentLog = {
							"time": logTime,
							"status": logStatus,
							"classes": logClasses,
							"text": logs[i]
						};
						result.push(currentLog);
					}

					vm.logMessages = vm.logMessages.concat(result);

					setTimeout(function() {
						getLogById(id, false, logs);
					}, 2000);					

					return result;
				} else {
					if(data.state == 'FAILED') {
						checkLastLog(false);
					} else {
						SweetAlert.swal("Success!", "Your environment has been built successfully.", "success");
						checkLastLog(true);
					}
				}
			}).error(function(error) {
				console.log(error);
			});
	}

	vm.logMessages = [];
	function buildEnvironment() {
		vm.buildStep = 'showLogs';

		vm.logMessages = [];
		var currentLog = {
			"time": '',
			"status": 'in-progress',
			"classes": ['fa-spinner', 'fa-pulse'],
			"text": 'Registering environment'
		};
		vm.logMessages.push(currentLog);

		environmentService.startEnvironmentAutoBuild(vm.environment2BuildName, JSON.stringify(vm.containers2Build))
			.success(function(data){
				vm.newEnvID = data;
				currentLog.status = 'success';
				currentLog.classes = ['fa-check', 'g-text-green'];
				currentLog.time = moment().format('HH:mm:ss');

				currentLog = {
					"time": '',
					"status": 'in-progress',
					"classes": ['fa-spinner', 'fa-pulse'],
					"text": 'Environment creation has been started'
				};
				vm.logMessages.push(currentLog);

				//var logId = getLogsFromTracker(vm.newEnvID);
				var logId = getLogsFromTracker(vm.environment2BuildName);

			}).error(function(error){
				if(error && error.ERROR === undefined) {
					VARS_MODAL_ERROR( SweetAlert, 'Error: ' + error );
				} else {
					VARS_MODAL_ERROR( SweetAlert, 'Error: ' + error.ERROR );
				}
				currentLog.status = 'fail';
				currentLog.classes = ['fa-times', 'g-text-red'];
				currentLog.time = moment().format('HH:mm:ss');				
			});
	}

	function showResources(peerId, resourcesId, index) {
		vm.currentResourceHosts = resourcesId;
		vm.currentPeer = peerId;
		vm.currentPeerIndex = index;
		$('.b-cloud-add-tools').animate({'left': '-200px'}, 300);
	}

	//add resource host
	function addResource2Build(currentResource, index) {
		//var pos = calculatePeerPos();
		var posX = calculatePeerPos();
		var posY = calculateResourceHostPos(vm.currentPeer);

		if( PEER_MAP[vm.currentPeer] !== undefined ) {
			if( PEER_MAP[vm.currentPeer].rh[currentResource] !== undefined ) {
				return PEER_MAP[vm.currentPeer].rh[currentResource];
			}
		} else {
			PEER_MAP[vm.currentPeer] = { rh: [], position : posX };
		}

		var resourceHost = new joint.shapes.resourceHostHtml.Element({
			//position: { x: 40, y: 40 },
			position: { x: PEER_MAP[vm.currentPeer].position * ( PEER_WIDTH + PEER_SPACE ), y: posY },
			size: { width: 155, height: 173 },
			peerId: vm.currentPeer,
			hostId: currentResource,
			children: 0,
			grid: [],
			gridSize: { size: 2 },
			'resourceHostName': 'RH' + (index + 1),
			'peerName': 'Peer ' + (vm.currentPeerIndex + 1),
			'addClass': 'b-resource-host_last'
		});

		if(Object.keys(PEER_MAP[vm.currentPeer].rh).length > 0) {
			var lastResourceInPeer = graph.getCell(PEER_MAP[vm.currentPeer].rh[
				Object.keys(PEER_MAP[vm.currentPeer].rh)[
					Object.keys(PEER_MAP[vm.currentPeer].rh).length - 1
				]
			]);
			lastResourceInPeer.set('addClass', '');
			lastResourceInPeer.set('removeClass', 'b-resource-host_last');
		}

		graph.addCell(resourceHost);
		PEER_MAP[vm.currentPeer].rh[currentResource] = resourceHost.id;

		return false;
	}

	function calculateResourceHostPos(peerId) {
		if(PEER_MAP[peerId]) {
			var posY = 30;
			for(var key in PEER_MAP[peerId].rh) {
				var currentResource = graph.getCell(PEER_MAP[peerId].rh[key]);
				var currentResourceSize = currentResource.get('size');
				var currentResourcePos = currentResource.get('position');
				posY = posY + (currentResourcePos.x + currentResourceSize.height);
			}
			return posY - 8;
		} else {
			return 30;
		}
	}

	function calculatePeerPos() {
		var pos = [];

		for (var key in PEER_MAP) {
			if (PEER_MAP.hasOwnProperty(key)) {
				pos.push( PEER_MAP[key].position );
			}
		}

		if( pos.length == 0 )
			return 0;
		if( pos.length == 1 )
			return 1;

		pos.sort();

		for( var i = 1; i < pos.length; i++ )
		{
			if( pos[i - 1] + 1 !== pos[i] )
			{
				return pos[i - 1] + 1;
			}
		}

		return pos[pos.length - 1];
	}

	//custom shapes
	joint.shapes.tm = {};

	//simple creatiom templates
	joint.shapes.tm.toolElement = joint.shapes.basic.Generic.extend({

		toolMarkup: [
			'<g class="element-tools">',
				'<g class="element-tool-remove">',
					'<circle fill="#F8FBFD" r="8" stroke="#dcdcdc"/>',
					'<polygon transform="scale(1.2) translate(-5, -5)" fill="#292F6C" points="8.4,2.4 7.6,1.6 5,4.3 2.4,1.6 1.6,2.4 4.3,5 1.6,7.6 2.4,8.4 5,5.7 7.6,8.4 8.4,7.6 5.7,5 "/>',
					'<title>Remove</title>',
				'</g>',
				/*'<g class="element-call-menu">',
					'<circle fill="#F8FBFD" r="8" stroke="#dcdcdc"/>',
					'<polygon transform="scale(1.2) translate(-5, -5)" fill="#292F6C" points="8.4,2.4 7.6,1.6 5,4.3 2.4,1.6 1.6,2.4 4.3,5 1.6,7.6 2.4,8.4 5,5.7 7.6,8.4 8.4,7.6 5.7,5 "/>',
					'<title>Menu</title>',
				'</g>',*/
			'</g>'
		].join(''),

		defaults: joint.util.deepSupplement({
			attrs: {
				text: { 'font-weight': 400, 'font-size': 'small', fill: 'black', 'text-anchor': 'middle', 'ref-x': .5, 'ref-y': .5, 'y-alignment': 'middle' },
				'g.element-call-menu': {'ref-x': 18, 'ref-y': 25}
			},
		}, joint.shapes.basic.Generic.prototype.defaults)

	});

	joint.shapes.tm.devElement = joint.shapes.tm.toolElement.extend({

		markup: [
			'<g class="rotatable">',
				'<g class="scalable">',
					'<rect class="b-border"/>',
				'</g>',
				'<title/>',
				'<image/>',
				'<rect class="b-magnet"/>',
				'<g class="b-container-plus-icon">',
					'<line fill="none" stroke="#FFFFFF" stroke-miterlimit="10" x1="0" y1="4.5" x2="9" y2="4.5"/>',
					'<line fill="none" stroke="#FFFFFF" stroke-miterlimit="10" x1="4.5" y1="0" x2="4.5" y2="9"/>',
				'</g>',
			'</g>'
		].join(''),

		defaults: joint.util.deepSupplement({
			type: 'tm.devElement',
			size: { width: 40, height: 40 },
			attrs: {
				title: {text: 'Static Tooltip'},
				'rect.b-border': {fill: '#fff', stroke: '#dcdcdc', 'stroke-width': 1, width: 40, height: 40, rx: 50, ry: 50},
				//'rect.b-magnet': {fill: '#04346E', width: 10, height: 10, rx: 50, ry: 50, magnet: true, transform: 'translate(16,28)'},
				'rect.b-magnet': {fill: '#04346E', width: 10, height: 10, rx: 50, ry: 50, transform: 'translate(16,28)'},
				'g.b-container-plus-icon': {'ref-x': 17.5, 'ref-y': 30, ref: 'rect', transform: 'scale(0.8)'},
				image: {'ref-x': 9, 'ref-y': 9, ref: 'rect', width: 25, height: 25},
			}
		}, joint.shapes.tm.toolElement.prototype.defaults)
	});

	//custom view
	joint.shapes.tm.ToolElementView = joint.dia.ElementView.extend({
		initialize: function() {
			joint.dia.ElementView.prototype.initialize.apply(this, arguments);
		},
		render: function () {
			joint.dia.ElementView.prototype.render.apply(this, arguments);
			this.renderTools();
			this.update();
			return this;
		},
		renderTools: function () {
			var toolMarkup = this.model.toolMarkup || this.model.get('toolMarkup');
			if (toolMarkup) {
				var nodes = V(toolMarkup);
				V(this.el).append(nodes);
			}
			return this;
		},
		mouseover: function(evt, x, y) {
		},
		pointerclick: function (evt, x, y) {
			this._dx = x;
			this._dy = y;
			this._action = '';
			var className = evt.target.parentNode.getAttribute('class');
			switch (className) {
				case 'element-tool-remove':
					var rh = this.model.attributes.rh;
					delete graph.getCell(rh.model).attributes.grid[rh.x][rh.y];
					this.model.remove();
					return;
					break;
				case 'element-call-menu':
					console.log(this.model);
					var elementPos = this.model.get('position');
					$('.js-dropen-menu').css({
						'left': (elementPos.x + 70) + 'px',
						'top': (elementPos.y + 83) + 'px',
						'display': 'block'
					});
					return;
					break;
				case 'rotatable':
					console.log(this.model);
					vm.currentTemplate = this.model;
					ngDialog.open({
						template: 'subutai-app/environment/partials/popups/templateSettingsAdvanced.html',
						scope: $scope
					});
					return;
					break;
				default:
			}
			joint.dia.CellView.prototype.pointerclick.apply(this, arguments);
		}
	});
	joint.shapes.tm.devElementView = joint.shapes.tm.ToolElementView;

	//resource host object
	joint.shapes.resourceHostHtml = {};
	joint.shapes.resourceHostHtml.Element = joint.shapes.basic.Rect.extend({
		defaults: joint.util.deepSupplement({
			type: 'resourceHostHtml.Element',
			attrs: {
				rect: { stroke: 'none', 'fill-opacity': 0, 'pointer-events':'none' }
			}
		}, joint.shapes.basic.Rect.prototype.defaults)
	});

	// Resource host html.
	// -------------------------------------------------------------------------

	joint.shapes.resourceHostHtml.ElementView = joint.dia.ElementView.extend({

		template: [
			'<div class="b-resource-host">',
				'<div class="b-peer-title"></div>',
				'<button class="b-peer-delete js-delete-peer"></button>',
				'<div class="b-resource-host__inner">',
					'<div class="b-recouce-host-title"></div>',
					'<div class="b-resource-host__containers">',
						'<div class="b-resource-host-containers">',
						'</div>',
					'</div>',
				'</div>',
			'</div>'
		].join(''),

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

			this.$box = $(_.template(this.template)());
			this.$box.find('.js-delete-peer').on('click', _.bind(this.model.remove, this.model));
			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();

			if(this.model.get('addClass')) {
				this.$box.addClass(this.model.get('addClass'));
			}

			if(this.model.get('removeClass')) {
				this.$box.removeClass(this.model.get('removeClass'));
			}

			this.$box.find('.b-peer-title').text(this.model.get('peerName'));
			this.$box.find('.b-recouce-host-title').text(this.model.get('resourceHostName'));
			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) {
			var keys = Object.keys(PEER_MAP[vm.currentPeer].rh);
			keys.splice(keys.indexOf(this.model.get('hostId')), 1);
			var emptyPlace = this.model.get('size').height - 8;
			delete PEER_MAP[this.model.get('peerId')].rh[this.model.get('hostId')];

			if(Object.keys(PEER_MAP[this.model.get('peerId')].rh).length == 0) {
				delete PEER_MAP[this.model.get('peerId')];
			} else {

				for(var i = 0; i < keys.length; i++) {
					var resourceHost = graph.getCell(PEER_MAP[vm.currentPeer].rh[keys[i]]);
					var resourceHostPosition = resourceHost.get('position');
					console.log(resourceHostPosition);
					resourceHost.set('position', {x: resourceHostPosition.x, y: (resourceHostPosition.y - emptyPlace)});
					console.log(resourceHost);
				}

				var lastResourceInPeer = graph.getCell(PEER_MAP[vm.currentPeer].rh[
					Object.keys(PEER_MAP[vm.currentPeer].rh)[
						Object.keys(PEER_MAP[vm.currentPeer].rh).length - 1
					]
				]);
				lastResourceInPeer.set('addClass', 'b-resource-host_last');
				lastResourceInPeer.set('removeClass', '');
			}

			this.$box.remove();
		}
	});	

	function initJointJs() {

		var paper = new joint.dia.Paper({
			el: $('#js-environment-creation'),
			width: '100%',
			height: '100%',
			model: graph,
			gridSize: 1
		});

	paper.on('cell:pointerdown', function(cellView) {
		cellView.prevPos = cellView.model.get('position');
	});

	paper.on('cell:pointerup', function(cellView) {

		if( cellView.model.get( 'containerName' ) === undefined )
			return;
{'fraction_non_alphanumeric': 0.19144136886540133, 'fraction_numerical': 0.018013082847291594, 'mean_word_length': 3.377768373536465, 'pattern_counts': {'":': 24, '<': 90, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6038686', 'n_tokens_mistral': 13290, 'n_tokens_neox': 10952, 'n_words': 1928}