<!DOCTYPE html>
<html lang="en">
<head>
	<link rel="icon" href="logo.png">
	<title>InterMap</title>
	<meta name="description" content="InterMap">
	<meta name="author" content="AD">
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
	<script src="snap/dist/snap.svg-min.js"></script>
	<script src="jszip/dist/jszip.min.js"></script>
	<script src="FileSaver/FileSaver.js"></script>
	<script src="jscolor/jscolor.js"></script>
	<script src="jquery/jquery-3.2.1.min.js"></script>
	<script src="image-picker/image-picker.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
	<style>
		body, html {
			height:100%;
		}
		
		hr {
			border-color: #000;
		}
		
		textarea {
			width: 100%;
		}
		
		input {
			width: 100%;
		}
		
		.fullHeight {
			height: 100%;
		}
		
		.existingTemplates {
			text-align: center;
		}
		
		.existingTemplates td {
			padding: 10px;
		}
		
		.btn:focus {
		  outline: none;
		}

		
		#leftPanel {
			background-color: #DDD;
			overflow: auto;
		}
		
		#dNoElementSelected {
			padding: 20px;
		}
		
		#dElementSelected {
			padding-bottom: 20px;
		}
		
		#pNoModifiers {
			margin: 20px;
		}
		
		.panel-body {
			padding: 5px;
			padding-top: 15px;
			padding-bottom: 15px;
		}
		
		.list-group {
			margin: 0;
		}
		
		#centerPanel {
			padding: 0;
		}
		
		#paper {
			
			display: block;
			width: 100%;
			height: 100%;
		}
		
		#svg {
			background: #F0F0F0;
			display: block;
			width: 100%;
			height: 100%;
		}
		
		#rightPanel {
			background-color: #DDD;
			padding-top: 20px;
		}
		
		#rightPanel button{
			padding-left: 0;
			padding-right: 0;
			background-color: #f97352;
			border-color: #f63809;
		}
		
		#rightPanel button:hover{
			background-color: #fb9c84;
		}

	</style>
</head>
<body>
  
<div class="container-fluid text-center fullHeight">    
	<div class="row content fullHeight">
		<div id="leftPanel" class="col-lg-2 col-md-2 col-sm-2 sidenav fullHeight">
			<div id="dNoElementSelected">
				<p>Click on an element to modify its properties</p>
			</div>
			<div id="dElementSelected" style="display:none">
				<div id="dModifiersContainer" class="panel-group">
					<p id="pNoModifiers">No modifiers are present on this element yet</p>
					
					<div class="panel panel-default modifier">
						<div class="panel-heading">
							<table style="width : 100%">
								<tr>
									<td class="text-left modifierTitle"> Modifier1 </td>
									<td class="text-right"> <a href="#" class="btn btn-danger btn-sm removeModifierButton" data-toggle="tooltip" data-placement="left" title="Remove modifier"><span class="glyphicon glyphicon-remove"></span></a> </td>
								</tr>
							</table>
						</div>
						<div class="panel-body">
						
							<!--Conditions-->
							<div class="panel panel-default">
								<div class="panel-heading">
									<table style="width : 100%">
										<tr>
											<td class="text-left"> Conditions </td>
											<td class="text-right"> <a href="#" class="btn btn-success btn-sm addConditionButton" data-toggle="tooltip" data-placement="left" title="Add condition"><span class="glyphicon glyphicon-plus"></span></a> </td>
										</tr>
									</table>
								</div>
								<div class="panel-body">
									<ul class="list-group conditions">
										<p class="templateNoConditions">No conditions are set for this modifier. All effects will be applied.</p>
										<li class="list-group-item"><div class="condition templateConditionDefault">Default State</div></li>
										<div class="condition templateConditionSelection">When Selected</div>
										<div class="condition templateConditionHover">When Hovered</div>
										<div class="condition templateConditionLayerSelection">
											<p class="noMargin modifierQuarterTitle">On Layer Selection</p>
											<p> Layer : <select>
											</select></p>
										</div>
										<div class="condition templateConditionVariable">
											<p class="noMargin modifierQuarterTitle">When variable is set</p>
											<p>Variable : <input type="text" value="" placeholder="Enter the variable's name"></p>
										</div>
									</ul>
								</div>
							</div>
							
							<!--Effect-->
							<div class="panel panel-default">
								<div class="panel-heading">
									<table style="width : 100%">
										<tr>
											<td class="text-left"> Effects </td>
											<td class="text-right"> <a href="#" class="btn btn-success btn-sm addEffectButton" data-toggle="tooltip" data-placement="left" title="Add effect"><span class="glyphicon glyphicon-plus"></span></a> </td>
										</tr>
									</table>
								</div>
								<div class="panel-body">
									
									<ul class="list-group effects">
										<p class="templateNoEffects">No effects are set for this modifier. It won't do anything.</p>
										<div class="condition templateEffectFill">
											<p class="noMargin modifierQuarterTitle">Change fill color</p>
											<p><input class="colorPicker jscolor{hash:true,onFineChange:'updateEffectColor(this)'}" value="#ffffff"></p>
										</div>
										<div class="condition templateEffectStroke">
											<p class="noMargin modifierQuarterTitle">Change stroke color</p>
											<p><input class="colorPicker jscolor{hash:true,onFineChange:'updateEffectColor(this)'}" value="#ffffff"></p>
										</div>
										<div class="condition templateEffectInfoPanel">
											<p class="noMargin modifierQuarterTitle">Display an info panel</p>
											<textarea rows="10" cols="50" placeholder="Type your text here" input="updateInfoPanelText()"></textarea>
											<p> Position : <select>
												<option value="right">Right</option>
												<option value="top">Top</option>
												<option value="left">Left</option>
												<option value="bottom">Bottom</option>
											</select></p>
											<p> Horizontal Offset : <input type="number" class="fifthWidth"> px</p>
											<p> Vertical Offset : <input type="number" class="fifthWidth"> px</p>
											<p> Horizontal Scale : <input type="number" step="0.02" min="0.01" class="fifthWidth"></p>
											<p> Vertical Scale : <input type="number" step="0.02" min="0.01" class="fifthWidth"></p>
											<p> Style : <select class="image-picker show-html">
											</select></p>
										</div>
										<div class="condition templateEffectLegend">
											<p class="noMargin modifierQuarterTitle">Set as legend</p>
											<p> Position : <select>
												<option value="bottom-right">Bottom-Right</option>
												<option value="bottom-left">Bottom-Left</option>
												<option value="top-right">Top-Right</option>
												<option value="top-left">Top-Left</option>
											</select></p>
											<p> Scale : <input type="number" step="0.02" min="0.01" class="fifthWidth"></p>
										</div>
										<div class="condition templateEffectPathAnimation">
											<p class="noMargin modifierQuarterTitle">Path animation</p>
											<p> Time : <input type="number" class="fifthWidth"> ms</p>
											<p> Start : <input type="number" step="0.5" min="0" max="100" class="fifthWidth"> %</p>
											<p> End : <input type="number" step="0.5" min="0" max="100" class="fifthWidth"> %</p>
										</div>
										<div class="condition templateEffectCenterCamera">
											<p class="noMargin modifierQuarterTitle">Center Camera on element</p>
										</div>
										<div class="condition templateEffectSetVariable">
											<p class="noMargin modifierQuarterTitle">Set variable</p>
											<p><input type="text" value=""></p>
										</div>
										<div class="condition templateEffectUnsetVariable">
											<p class="noMargin modifierQuarterTitle">Unset variable</p>
											<p><input type="text" value=""></p>
										</div>
									</ul>
								</div>
							</div>
							</br>
						</div>
					</div>
				</div>
				<button type="button" class="btn btn-success btn-lg" onclick="addEmptyModifier(selectedElement);reconstructModifiersUI(selectedElement)"><span class="glyphicon glyphicon-plus"></span>Add modifier</button>
			</div>
		</div>
		<div id="centerPanel" class="col-lg-8 col-md-8 col-sm-8 text-left fullHeight">
			<div id="paper">
				<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
			</div>
		</div>
		<div id="rightPanel" class="col-lg-2 col-md-2 col-sm-2 sidenav fullHeight">
			<div class="btn-group-vertical btn-block">
				<button type="button" class="btn btn-warning btn-lg" data-toggle="modal" data-target="#modalCustomSVGFile">Change Template</button>
				<button type="button" class="btn btn-warning btn-lg" data-toggle="modal" data-target="#modalImportData">Import Map</button>
				<button type="button" class="btn btn-warning btn-lg" onclick="exportData()">Export Map</button>
			</div>
			<hr />
			<div class="btn-group-vertical btn-block">
				<button type="button" class="btn btn-warning btn-lg" onclick="testMap()">Test Map</button>
				<button type="button" class="btn btn-warning btn-lg">Integration</button>
			</div>
			<hr />
			<div class="btn-group-vertical btn-block">
				<button type="button" class="btn btn-warning btn-lg">Options</button>
				<button type="button" class="btn btn-warning btn-lg">Timeline</button>
				<button type="button" class="btn btn-warning btn-lg">Set Default Timeline</button>
			</div>
			<hr />
			<div class="btn-group-vertical btn-block">
				<button type="button" class="btn btn-warning btn-lg">Import Custom Info Panel</button>
			</div>
		</div>
	</div>
</div>

<div class="modal fade" id="modalAddCondition" role="dialog">
	<div class="modal-dialog  modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">&times;</button>
				<h4 class="text-center">Add a new condition</h4>
			</div>
			<div class="modal-body">
				<table style="width : 100%">
					<tr>
						<td class="text-left">
							<div class="dropdown">
								<button class="btn btn-primary btn-lg dropdown-toggle" type="button" data-toggle="dropdown">
									<span id="sConditionName">Select the condition</span>
									<span class="caret"></span>
								</button>
								<ul class="dropdown-menu">
									<li><a href="#" onclick="changeSelectedCondition('default')">Default</a></li>
									<li><a href="#" onclick="changeSelectedCondition('selection')">Selection</a></li>
									<li><a href="#" onclick="changeSelectedCondition('hover')">Hover</a></li>
								</ul>
							</div>
						</td>
						<td class="text-right"><button type="button" id="bAddCondition" class="btn btn-success btn-lg" onclick="addCondition()"><span class="glyphicon glyphicon-plus"></span>Add Condition</button></td>
					</tr>
				</table>
				<h4 id="dConditionDescription" class="text-center"> DESCRIPTION </h4>
			</div>
		</div>
	</div>
</div>

<div class="modal fade" id="modalAddEffect" role="dialog">
	<div class="modal-dialog  modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">&times;</button>
				<h4 class="text-center">Add a new effect</h4>
			</div>
			<div class="modal-body">
				<table style="width : 100%">
					<tr>
						<td class="text-left">
							<div class="dropdown">
								<button class="btn btn-primary btn-lg dropdown-toggle" type="button" data-toggle="dropdown">
									<span id="sEffectName">Select the effect</span>
									<span class="caret"></span>
								</button>
								<ul class="dropdown-menu">
									<li><a href="#" onclick="changeSelectedEffect('fill')">Fill Color</a></li>
									<li><a href="#" onclick="changeSelectedEffect('stroke')">Stroke Color</a></li>
									<li><a href="#" onclick="changeSelectedEffect('infoPanel')">Info Panel</a></li>
								</ul>
							</div>
						</td>
						<td class="text-right"><button type="button" id="bAddEffect" class="btn btn-success btn-lg" onclick="addEffect()"><span class="glyphicon glyphicon-plus"></span>Add Effect</button></td>
					</tr>
				</table>
				<h4 id="dEffectDescription" class="text-center"> DESCRIPTION </h4>
			</div>
		</div>
	</div>
</div>

<div class="modal fade" id="modalCustomSVGFile" role="dialog">
	<div class="modal-dialog  modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">&times;</button>
				<h4 class="text-center">Change the template of your interactive map</h4>
			</div>
			<div class="modal-body text-center">
				<table class="existingTemplates">
					<tr>
						<td><img src="thumbnails/test.png" alt="Earth" style="width:256px;height:128px;"></td>
						<td><h4>Map of the entire Earth, showing borders and lakes</h4></td>
						<td><button class="btn btn-primary" onClick="loadLocalSvgFile('test.svg')">SELECT</button></td>
					</tr>
					<tr>
						<td><img src="thumbnails/test2.png" alt="Test" style="width:256px;height:128px;"></td>
						<td><h4>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam a tincidunt nunc</h4></td>
						<td><button class="btn btn-primary" onClick="loadLocalSvgFile('test2.svg')">SELECT</button></td>
					</tr>
				</table>
				</br>
				</br>
				<label class="btn btn-primary">
					Upload your own .SVG file<input id="fileCustomSvgFile" type="file" style="display:none;">
				</label>
				<button class="btn btn-success" onClick="loadCustomSvgFile()">Select file</button>
			</div>
		</div>
	</div>
</div>

<div class="modal fade" id="modalImportData" role="dialog">
	<div class="modal-dialog  modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">&times;</button>
				<h4 class="text-center">Import a previously exported Inter Map</h4>
			</div>
			<div class="modal-body text-center">
				<label class="btn btn-primary">
					Select the .ZIP file exported earlier <input id="fileImportData" type="file" style="display:none;">
				</label>
				<button class="btn btn-success" onClick="importData()">Load map</button>
			</div>
		</div>
	</div>
</div>

<div class="modal fade" id="modalLoading" role="dialog">
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h4 class="text-center">Loading</h4>
			</div>
		</div>
	</div>
</div>

<script>
var zoomSpeed = 1.1;
var currentZoom = 1;

var s = Snap("#svg");

var paper = document.getElementById("svg");
if (paper.addEventListener) {
	paper.addEventListener("mousewheel", mouseWheelHandler, false);
	paper.addEventListener("DOMMouseScroll", mouseWheelHandler, false);
}
else {
	paper.attachEvent("onmousewheel", mouseWheelHandler);
}

var superGroup, mapGroup, legendGroup, timelineGroup, interfaceGroup, tempGroup;
var layerNullMap, layerNullLegend;
var svgFileContent = null;
var timelineContent = null;
var id = 0;
var customId = 0;

var allModifiers = [];
var allElements = [];
var elementsData = {};

var layerNames = [];
var layers = {};
var timelineLayers = [];
var isTimelineActive = true;
var elementsInNullLayer = false;
var layerCountInTimeline = 0;
var selectedLayer = null;
var selectedLayerIndex = null;
var timelineType = "chevron";

var variables = {};

var infoPanelNames = [];
var infoPanels = {};

var selectedElement = null;
var currentModifier = null;

var areGroupsFinal = true;

var config = {
	cameraMovementEnabled : true,
	cameraMovementStyle : "standard"
};

//#

var fullScreenIcon = Snap.parse('<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>');
var exitFullScreenIcon = Snap.parse('<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/></svg>')

var leftChevronIcon = Snap.parse('<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
var rightChevronIcon = Snap.parse('<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');

var dNoElementSelected = document.getElementById("dNoElementSelected");
var dElementSelected = document.getElementById("dElementSelected");

var dModifiersContainer = document.getElementById("dModifiersContainer");
var pNoModifiers = document.getElementById("pNoModifiers");

var dTimelineCheckBoxes = document.getElementById("dTimelineCheckBoxes");

var templateModifier = document.getElementsByClassName("modifier")[0];

var templateConditions = {};
templateConditions['none'] = document.getElementsByClassName("templateNoConditions")[0];
templateConditions['default'] = document.getElementsByClassName("templateConditionDefault")[0];
templateConditions['selection'] = document.getElementsByClassName("templateConditionSelection")[0];
templateConditions['hover'] = document.getElementsByClassName("templateConditionHover")[0];
templateConditions['layerSelection'] = document.getElementsByClassName("templateConditionLayerSelection")[0];
templateConditions['variable'] = document.getElementsByClassName("templateConditionVariable")[0];

var templateEffects = {};
templateEffects['none'] = document.getElementsByClassName("templateNoEffects")[0];
templateEffects['fill'] = document.getElementsByClassName("templateEffectFill")[0];
templateEffects['stroke'] = document.getElementsByClassName("templateEffectStroke")[0];
templateEffects['infoPanel'] = document.getElementsByClassName("templateEffectInfoPanel")[0];
templateEffects['legend'] = document.getElementsByClassName("templateEffectLegend")[0];
templateEffects['pathAnimation'] = document.getElementsByClassName("templateEffectPathAnimation")[0];
templateEffects['centerCamera'] = document.getElementsByClassName("templateEffectCenterCamera")[0];
templateEffects['setVariable'] = document.getElementsByClassName("templateEffectSetVariable")[0];
templateEffects['unsetVariable'] = document.getElementsByClassName("templateEffectUnsetVariable")[0];

var bAddCondition = document.getElementById("bAddCondition");
var sConditionName = document.getElementById("sConditionName");
var dConditionDescription = document.getElementById("dConditionDescription");
var nameConditions = {};
var descriptionConditions = {};
var selectedCondition = "default";
nameConditions['base'] = "Select the condition";
descriptionConditions['base'] = "";

nameConditions['default'] = "Default";
descriptionConditions['default'] = "This modifier will only be applied when the element is not selected nor hovered";
nameConditions['selection'] = "Selection";
descriptionConditions['selection'] = "This modifier will be applied when the element is selected by a mouse click";
nameConditions['hover'] = "Hover";
descriptionConditions['hover'] = "This modifier will be applied when the element is hovered by the mouse";

var bAddEffect = document.getElementById("bAddEffect");
var sEffectName = document.getElementById("sEffectName");
var dEffectDescription = document.getElementById("dEffectDescription");
var nameEffects = {};
var descriptionEffects = {};
var selectedEffect = "fill";
nameEffects['base'] = "Select the effect";
descriptionEffects['base'] = "";

nameConditions['fill'] = "Fill Color";
descriptionEffects['fill'] = "Changes the fill color of the element to the chosen color";
nameConditions['stroke'] = "Stroke Color";
descriptionEffects['stroke'] = "Changes the stroke color of the element to the chosen color";
nameConditions['infoPanel'] = "Info Panel";
descriptionEffects['infoPanel'] = "Displays a customable info panel";

var modals = {};
/*popups["addCondition"] = document.getElementById("popUpAddCondition");
popups["addEffect"] = document.getElementById("popUpAddEffect");
popups["customSvgFile"] = document.getElementById("popUpCustomSvgFile");
popups["customInfoPanel"] = document.getElementById("popUpCustomInfoPanel");
popups["importData"] = document.getElementById("popUpImportData");
popups["globalOptions"] = document.getElementById("popUpGlobalOptions");
popups["timeline"] = document.getElementById("popUpTimeline");
popups["newTimeline"] = document.getElementById("popUpNewTimeline");
popups["integration"] = document.getElementById("popUpIntegration");
popups["loading"] = document.getElementById("popUpLoading");*/
//modals["bla"] = $("#modalBla");
modals["addCondition"] = $("#modalAddCondition");
modals["addEffect"] = $("#modalAddEffect");
modals["customSVGFile"] = $("#modalCustomSVGFile");
modals["importData"] = $("#modalImportData");
modals["loading"] = $("#modalLoading");

hideModals();
changeDescriptionEffect();
setConfigUI();

loadLocalInfoPanel("classic");
loadLocalInfoPanel("modern");
loadLocalInfoPanel("modern2");
loadLocalInfoPanel("modern3");

loadLocalSvgFile("test2modified.svg");

//------------------------------------------------------------------------
//Utils
//------------------------------------------------------------------------

function isElementFinal(element) {
	if (areGroupsFinal) {
		return element.children().length == 0 || (element.type == "g" && !(element.attr("id") && (element.attr("id").startsWith("layer") || element.attr("id") == "tempGroup" || element.attr("id") == "mapGroup" || element.attr("id") == "timelineGroup")));
	}
	else {
		return element.children().length == 0;
	}
	
}

function isElementReal(element) {
	return !(element.type.includes("#") || element.type.includes(":") || element.type == "defs");
}

function isLayer(element) {
	return element.type == "g" && element.attr("id") && element.attr("id").startsWith("layer");
}

function setFillColor(colorFill, element) {
	element.attr({
		fill : colorFill
	});
	
	element.children().forEach(function(child) {
		if (child.type != "#text") {
			setFillColor(colorFill, child);
		}
	});
}

function animateFillColor(colorFill, element) {
	var currentColor = Snap.color(element.attr("fill"))
	
	var fromFill;
	if (currentColor.hex == "none") {
		fromFill = Snap.color("black");
	}
	else {
		fromFill = currentColor;
	}
	
	var toFill = Snap.color(colorFill)
	
	Snap.animate([fromFill.r, fromFill.g, fromFill.b], [toFill.r, toFill.g, toFill.b], function (val) {
		var fillColor = "rgb(" + Math.round(val[0]) + "," + Math.round(val[1]) + "," + Math.round(val[2]) + ")";
		
		element.attr({ //removes the old value
			fill : fillColor
		});
		
		element.attr({
			style :  element.attr("style") + ";fill: " + fillColor
		});
	}, 200);
	
	element.children().forEach(function(child) {
		if (child.type != "#text") {
			animateFillColor(colorFill, child);
		}
	});
}

function setStrokeColor(colorStroke, element) {
	element.attr({
		stroke : colorStroke
	});
	
	element.children().forEach(function(child) {
		if (child.type != "#text") {
			setStrokeColor(colorStroke, child);
		}
	});
}

function animateStrokeColor(colorStroke, element) {
	var currentColor = Snap.color(element.attr("stroke"))
	
	var fromStroke;
	if (currentColor.hex == "none") {
		fromStroke = Snap.color("black");
	}
	else {
		fromStroke = currentColor;
	}
	
	var toStroke = Snap.color(colorStroke)
	
	Snap.animate([fromStroke.r, fromStroke.g, fromStroke.b], [toStroke.r, toStroke.g, toStroke.b], function (val) {
		var strokeColor = "rgb(" + Math.round(val[0]) + "," + Math.round(val[1]) + "," + Math.round(val[2]) + ")";
		
		element.attr({ //removes the old value
			stroke : strokeColor
		});
		
		element.attr({
			style :  element.attr("style") + ";stroke: " + strokeColor
		});
	}, 200);
	
	element.children().forEach(function(child) {
		if (child.type != "#text") {
			animateStrokeColor(colorStroke, child);
		}
	});
}

function centerCamera(element) {
	var ebox = element.getBBox();
	
	var box = ebox;
	if (element.data("infoPanelsGroup")) {
		var ibox = element.data("infoPanelsGroup").getBBox();
		
		if (ibox.w != 0 || ibox.h != 0) {
			box.x = Math.min(box.x, ibox.x);
			box.y = Math.min(box.y, ibox.y);
			
			box.x2 = Math.max(box.x2, ibox.x2);
			box.y2 = Math.max(box.y2, ibox.y2);
			
			box.w = box.x2 - box.x;
			box.h = box.y2 - box.y;
			
			box.cx = box.x + box.w / 2;
			box.cy = box.y + box.h / 2;
		}
	}
	
	switch (config.cameraMovementStyle) {
		default :
			var finalMatrix = new Snap.Matrix();
			finalMatrix.translate(-box.cx + paper.getBoundingClientRect().width / 2,
								  -box.cy + paper.getBoundingClientRect().height / 2);
			
			var scaleX = 0.8 * paper.getBoundingClientRect().width / box.w;
			var scaleY = 0.8 * paper.getBoundingClientRect().height / box.h;
			var scale = Math.min(scaleX, scaleY);
			finalMatrix.scale(scale, scale, box.cx, box.cy);
			
			mapGroup.stop();
			mapGroup.animate({ transform: finalMatrix}, 700, mina.easeinout);
		break;
		case 'dezoom' :
			var finalMatrix = new Snap.Matrix();
			finalMatrix.translate(-box.cx + paper.getBoundingClientRect().width / 2,
								  -box.cy + paper.getBoundingClientRect().height / 2);
			
			var scaleX = 0.8 * paper.getBoundingClientRect().width / box.w;
			var scaleY = 0.8 * paper.getBoundingClientRect().height / box.h;
			var scale = Math.min(scaleX, scaleY);
			finalMatrix.scale(scale, scale, box.cx, box.cy);
			
			
			var current = mapGroup.transform().localMatrix;
			
			var half = new Snap.Matrix();
			half.scale(0.8, 0.8, paper.getBoundingClientRect().width / 2, paper.getBoundingClientRect().height / 2);
			half.add(0.5 * current.a + 0.5 * finalMatrix.a,
					 0.5 * current.b + 0.5 * finalMatrix.b,
					 0.5 * current.c + 0.5 * finalMatrix.c,
					 0.5 * current.d + 0.5 * finalMatrix.d,
					 0.5 * current.e + 0.5 * finalMatrix.e,
					 0.5 * current.f + 0.5 * finalMatrix.f);
			
			mapGroup.stop();
			mapGroup.animate({ transform: half}, 700, ease1, function() {
				mapGroup.animate({ transform: finalMatrix}, 700, ease2);
			});
		break;
		case 'fast' :
			var finalMatrix = new Snap.Matrix();
			finalMatrix.translate(-box.cx + paper.getBoundingClientRect().width / 2,
								  -box.cy + paper.getBoundingClientRect().height / 2);
			
			var scaleX = 0.7 * paper.getBoundingClientRect().width / box.w;
			var scaleY = 0.7 * paper.getBoundingClientRect().height / box.h;
			var scale = Math.min(scaleX, scaleY);
			finalMatrix.scale(scale, scale, box.cx, box.cy);
			
			mapGroup.stop();
			mapGroup.animate({ transform: finalMatrix}, 600, ease1);
		break;
	}
}

function centerMap() {
	var box = mapGroup.getBBox(true);
	var m = new Snap.Matrix();
	m.translate(-box.cx + paper.getBoundingClientRect().width / 2,
				-box.cy + paper.getBoundingClientRect().height / 2);
	
	var scaleX = 0.9 * paper.getBoundingClientRect().width / box.w;
	var scaleY = 0.9 * paper.getBoundingClientRect().height / box.h;
	var scale = Math.min(scaleX, scaleY);
	m.scale(scale, scale, box.cx, box.cy);
	mapGroup.transform(m);
}

function animatePath(element, effect) {
	//Inspired by
	//https://github.com/maxwellito/vivus
	
	if (element.type == "g") {
		element.children().forEach(function(child) {
			animatePath(element, effect);
		});
	}
	else if (element.type == "path") {
		var mask = element.clone();
		
		mask.attr({
			stroke: "#ffffff" //for whatever reason, the mask has to be white
		});

		if (element.attr("mask") != "none") {
			//remove the old mask to improve performance
			Snap.select(element.attr("mask").slice(5, -2)).remove();
		}
		
		element.attr({
			mask: mask
		});
		
		var length = Math.ceil(element.node.getTotalLength());
		var dashGap = 2;
		
		mask.node.style.strokeDasharray  = length + ' ' + (length + dashGap * 2);
		
		var anim = Snap.animate((length + dashGap) * (100 - effect.start) / 100, (length + dashGap) * (100 - effect.end) / 100, function (val) {		
			mask.node.style.strokeDashoffset = val;
		}, effect.time, mina.linear);
	}
}

function showElement(element) {
	element.node.style.display = "";
}


function hideElement(element) {
	element.node.style.display = "none";
}


function ease1(x) {
	return Math.sqrt(1 - (x-1) * (x-1));
}

function ease2(x) {
	return (1 - Math.sqrt(1 - (x * 0.9) * (x * 0.9))) / 0.564110;
}

//From https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
function isMobile() {
  var check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
}

//------------------------------------------------------------------------
// Change svg file
//------------------------------------------------------------------------
//#
function loadLocalSvgFile(fileName) {
	initLoad();
	Snap.load(fileName, function (f) {
		loadSvgFragment(f, false);
	});
	
}


function loadCustomSvgFile() {
	initLoad();
	var file = document.getElementById("fileCustomSvgFile").files[0];
	if (file) {
		var reader = new FileReader();
		reader.readAsText(file, "UTF-8");
		reader.onload = function (evt) {
			loadSvgFragment(Snap.parse(evt.target.result), false);
		}
		reader.onerror = function (evt) {
			console.log("error reading file");
		}
	}
	else {
		hideModals();
	}
}

function loadImportedSvgFile(data) {
	initLoad();
	loadSvgFragment(Snap.parse(data.map), true);
}

function initLoad() {
	//#
	showModal('loading');
	
	if (selectedElement) {
		deselectElement(selectedElement);
	}
	
	if (superGroup) {
		superGroup.remove();
	}
	
	superGroup = s.g();
	superGroup.attr({
		id: "superGroup"
	});

	mapGroup = superGroup.g();
	mapGroup.attr({
		id: "mapGroup"
	});
	
	if (!isMobile()) {
		mapGroup.drag();
	}

	legendGroup = superGroup.g();
	legendGroup.attr({
		id: "legendGroup"
	});

	timelineGroup = superGroup.g();
	timelineGroup.attr({
		id: "timelineGroup"
	});
	
	interfaceGroup = superGroup.g();
	interfaceGroup.attr({
		id: "interfaceGroup"
	});
	
	tempGroup = s.g();
	tempGroup.attr({
		id: "tempGroup"
	});
	
	layerNames = [];
	layers = {};
	timelineLayers = [];
	selectedLayer = null;
	isTimelineActive = true;
	elementsInNullLayer = false;
	
	layerNullMap = s.g();
	layerNullMap.attr({
		id: "layerNullMap"
	});
	mapGroup.append(layerNullMap);
	
	layerNullLegend = s.g();
	layerNullLegend.attr({
		id: "layerNullLegend"
	});
	legendGroup.append(layerNullLegend);
	
	layerNames.push("layerNull");
	layers["layerNull"] = {
		map : layerNullMap,
		legend : layerNullLegend,
		timelineActivated : false
	};
	
	allModifiers = [];
	allElements = [];
	elementsData = {};

	variables = {};
	
	reconstructFullScreenIcon(false);
}

function loadSvgFragment(f, isImported) {
	tempGroup.append(f);
	
	if (!isImported) {
		initializeID(tempGroup);
	}
	
	svgFileContent = tempGroup.innerSVG();
	
	initializeElementsLayer(tempGroup, null);
	initializeLayers(tempGroup);
	tempGroup.remove();
	
	initializeElements(mapGroup);
	
	isTimelineActive = false;
	if (!isImported && ((elementsInNullLayer && layerNames.length > 1) || (!elementsInNullLayer && layerNames.length > 2))) {
		initNewTimelinePopUp();
	}
	else {
		timelineContent = null;
		centerMap();
	
		//#
		hideModals();
	}
}

//#
function initializeID(element) {
	if (isElementFinal(element)) {
		element.data("id", "elem" + (id++));
		element.attr({
			id: "" + element.data("id")
		});
		
	}
	else {
		element.children().forEach(function(child) {
			initializeID(child);
		});
	}
}

function initializeElementsLayer(element, layer) {
	if (isElementFinal(element)) {
		if (layer == null) {
			element.data("layer", "layerNull");
		}
		else {
			element.data("layer", layer);
		}
	}
	else if (isLayer(element)) {
		element.children().forEach(function(child) {
			initializeElementsLayer(child, element.attr("id"));
		});
	}
	else {
		element.children().forEach(function(child) {
			initializeElementsLayer(child, null);
		});
	}
}

function initializeLayers(element) {
	if (isElementFinal(element)) {
		layerNullMap.append(element);
		
		if (isElementReal(element)) {
			isTimelineActive = false;
			elementsInNullLayer = true;
		}
	}
	else if (isLayer(element)) {
		var layerLegend = s.g();
		layerLegend.attr({
			id: element.attr("id") + "Legend"
		});
		legendGroup.append(layerLegend);
		
		layerNames.push(element.attr("id"));
		layers[element.attr("id")] = {
			map : element,
			legend : layerLegend,
			timelineActivated : false
		};
		
		element.attr({
			id: "" + element.attr("id") + "Map"
		});
		mapGroup.append(element);
		
		
	}
	else {
		element.children().forEach(function(child) {
			initializeLayers(child);
		});
	}
}

function initializeElements(element) {
	if (isElementFinal(element)) {
		
		if (element.attr("id")) {
			var elementParent = s.g();
			elementParent.attr({
				id: element.attr("id") + "Parent"
			});
			element.parent().append(elementParent);
			elementParent.append(element);
			
			element.data("parent", elementParent);
			element.data("isSelected", false);
			element.data("isHovered", false);
			element.data("modifiers", []);
			element.data("isLegend", false);
			element.data("firstCheck", true);
			
			elementsData[element.attr("id")] = {
				firstSelection : true
			}
			
			element.click(clickCallback);
			element.mouseover(hoverCallback);
			element.mouseout(outCallback);
			
			allElements.push(element);
		}
	}
	else {
		element.children().forEach(function(child) {
			initializeElements(child);
		});
	}
}

//------------------------------------------------------------------------
//Timeline & Layers
//------------------------------------------------------------------------

function initNewTimelinePopUp() {
	dTimelineCheckBoxes.innerHTML = "";
	
	for (var i = 0; i < layerNames.length; i++) {
		if (i != 0) {
			dTimelineCheckBoxes.innerHTML += "<p>" + layerNames[i] + "<input type='checkbox' id='checkbox" + layerNames[i] + "' checked></p>";
		}
		else if (elementsInNullLayer) {
			dTimelineCheckBoxes.innerHTML += "<p>All elements with no layer<input type='checkbox' id='checkbox" + layerNames[i] + "'></p>";
		}
	}

	showModal('newTimeline');
}

function validateNewTimeline() {
	var results = {};
	layerCountInTimeline = 0;
	 
	results[layerNames[0]] = false;
	 
	for (var i = 0; i < layerNames.length; i++) {
		if (i != 0 || elementsInNullLayer) {
			results[layerNames[i]] = document.getElementById("checkbox" + layerNames[i]).checked;
			
			if (results[layerNames[i]]) {
				layerCountInTimeline ++;
			}
		}
	}
	
	if (layerCountInTimeline >= 2) {
		isTimelineActive = true;
		timelineLayers = [];
		
		for (var i = 0; i < layerNames.length; i++) {
			layers[layerNames[i]].timelineActivated = results[layerNames[i]];
			if (layers[layerNames[i]].timelineActivated) {
				timelineLayers.push(layerNames[i]);
			}
		}
		createDefaultTimeline();
	}
	else {
		//do nothing, everything is set correctly
	}
	
	//#
	hideModals();
}

function selectLayer(layerIndex, isFirstSelection) {
	var layer = timelineLayers[layerIndex];
	if (!isFirstSelection && selectedLayer == layer) {
		return;
	}
	
	if (selectedElement) {
		deselectElement(selectedElement);
	}
	
	var oldSelectedLayer = selectedLayer;
	selectedLayer = layer;
	selectedLayerIndex = layerIndex;
	
	if (!layers[selectedLayer].timelineActivated) {
		console.log("ERROR : selectedLayer is not in timeline");
	}
	
	if (isFirstSelection) {
		for (var i = 0; i < layerNames.length; i++) {
			if (layers[layerNames[i]].timelineActivated) {
				layers[layerNames[i]].map.node.style.display = "none";
				layers[layerNames[i]].legend.node.style.display = "none";
				
				layers[layerNames[i]].map.attr({opacity: 0});
				layers[layerNames[i]].legend.attr({opacity: 0});
				
				layers[layerNames[i]].map.node.style.pointerEvents = "none";
				layers[layerNames[i]].legend.node.style.pointerEvents = "none";
			}
		}		
		layers[selectedLayer].map.attr({opacity: 1});
		layers[selectedLayer].legend.attr({opacity: 1});
	}
	else {
		if (!layers[oldSelectedLayer].timelineActivated) {
			console.log("ERROR : oldSelectedLayer is not in timeline");
		}
	
		layers[oldSelectedLayer].map.node.style.pointerEvents = "none";
		layers[oldSelectedLayer].legend.node.style.pointerEvents = "none";
		
		layers[oldSelectedLayer].map.animate({
			opacity: 0
		}, 1000);
		layers[oldSelectedLayer].legend.animate({
			opacity: 0
		}, 1000);
		
		layers[selectedLayer].map.animate({
			opacity: 1
		}, 1000);
		layers[selectedLayer].legend.animate({
			opacity: 1
		}, 1000);
	}
	layers[selectedLayer].map.node.style.display = "";
	layers[selectedLayer].legend.node.style.display = "";
		
	layers[selectedLayer].map.node.style.pointerEvents = "";
	layers[selectedLayer].legend.node.style.pointerEvents = "";
	
	checkAllModifiers();
}

function initTimeline() {
	timelineGroup.clear();
	timelineGroup.transform(new Snap.Matrix());
}

function finishTimeline() {
	timelineContent = timelineGroup.innerSVG();
	
	if (timelineLayers.length != layerCountInTimeline) {
		console.log("ERROR : timelineLayers.length != layerCountInTimeline");
	}
	
	var possibleTimelineSelectors = collectTimelineSelectors();
	
	if (timelineType == "chevron") {
		if (possibleTimelineSelectors.length != 4) {
			console.log("ERROR : default timeline is wrong");
		}
		else {
			var left = possibleTimelineSelectors[0];
			var right = possibleTimelineSelectors[2];
			var leftDisabled = possibleTimelineSelectors[1];
			var rightDisabled = possibleTimelineSelectors[3];
			
			var animate05 = function() {
				this.animate({
					opacity: 0.5
				}, 200);
			};
			var animate1 = function() {
				this.animate({
					opacity: 1
				}, 200);
			};
			
			left.mouseover(animate05);
			left.mouseout(animate1);
			
			right.mouseover(animate05);
			right.mouseout(animate1);
			
			left.node.style.display = "none";
			rightDisabled.node.style.display = "none";
			
			left.click(function(){
				if (selectedLayerIndex > 0) {
					selectLayer(selectedLayerIndex - 1), false;
					
					if (selectedLayerIndex == 0) {
						left.node.style.display = "none";
						leftDisabled.node.style.display = "";
					}
					
					right.node.style.display = "";
					rightDisabled.node.style.display = "none";
				}
			});
			
			right.click(function(){
				if (selectedLayerIndex < layerCountInTimeline - 1) {
					selectLayer(selectedLayerIndex + 1), false;
					
					if (selectedLayerIndex == layerCountInTimeline - 1) {
						right.node.style.display = "none";
						rightDisabled.node.style.display = "";
					}
					
					left.node.style.display = "";
					leftDisabled.node.style.display = "none";
				}
			});
			
		}
	}
	else if (possibleTimelineSelectors.length < layerCountInTimeline) {
		createDefaultTimeline();
		alert("There isn't enough elements on this timeline to function correctly");
	}
	else {
		var count = 0;
		for (var i = (possibleTimelineSelectors.length - layerCountInTimeline); i < possibleTimelineSelectors.length; i++) {
			var element = possibleTimelineSelectors[i];
			
			var layerName = timelineLayers[count];
			
			layers[layerName].selector = element;
			element.data("timelineLayerIndex", count);
			
			element.attr({
				opacity:0.6
			});
			
			if (count == 0) {
				element.attr({
					opacity:1
				});
			}
			
			element.click(timelineClickCallbackOpacity);
			element.mouseover(timelineHoverCallbackOpacity);
			element.mouseout(timelineOutCallbackOpacity);
			
			count++;
		}
	}
	
	centerTimeline();
	
	selectLayer(0, true);
	centerMap();
	
	//#
	hideModals();
}

function centerTimeline() {
	var w = paper.getBoundingClientRect().width;
	var h = paper.getBoundingClientRect().height;
	
	var bbox = timelineGroup.getBBox(true);
	
	var m = new Snap.Matrix();
	m.translate(-bbox.cx + w / 2,
				-bbox.y2 + h);
				
	if (timelineType != "chevron") {
		m.translate(0, -bbox.h / 2);
	}
	timelineGroup.transform(m);
}

function createDefaultTimeline() {
	initTimeline();
	
	timelineType = "chevron";
	
	var left = timelineGroup.g();
	left.add(leftChevronIcon);
	
	var bbox = left.getBBox();
	var rect = left.rect(bbox.x, bbox.y, bbox.w, bbox.h);
	
	rect.attr({
		opacity: 0
	});
	
	var right = timelineGroup.g();
	right.add(rightChevronIcon);
	
	var bbox = right.getBBox();
	var rect = right.rect(bbox.x, bbox.y, bbox.w, bbox.h);
	
	rect.attr({
		opacity: 0
	});
	
	var m = new Snap.Matrix();
	m.scale(3);
	left.transform(m);
	right.transform(m);
	
	var bbox = right.getBBox(true);
	var m = new Snap.Matrix();
	m.add(right.transform().localMatrix);
	m.translate(bbox.w * 2, 0);
	right.transform(m);
	
	var leftDisabled = left.clone();
	leftDisabled.attr({
		opacity : 0.2
	});
	
	var rightDisabled = right.clone();
	rightDisabled.attr({
		opacity : 0.2
	});
	
	finishTimeline();
}

function loadCustomTimeline() {
	var file = document.getElementById("fileCustomTimeline").files[0];
	if (file) {
		var reader = new FileReader();
		reader.readAsText(file, "UTF-8");
		reader.onload = function (evt) {
			timelineType = "full";
			loadFragmentTimeline(Snap.parse(evt.target.result));
		}
		reader.onerror = function (evt) {
			console.log("error reading file");
		}
	}
	else {
		hideModals();
	}
}

function loadImportedTimeline(data) {
	isTimelineActive = (data.timeline != null);
	if (isTimelineActive) {
		timelineLayers = data.timelineLayers;
		timelineType = data.timelineType;
		layerCountInTimeline = timelineLayers.length;
		
		for (var i = 0; i < layerNames; i++) {
			layers[layerNames[i]].timelineActivated = false;
		}
		for (var i = 0; i < layerCountInTimeline; i++) {
			layers[timelineLayers[i]].timelineActivated = true;
		}
		
		loadFragmentTimeline(Snap.parse(data.timeline));
	}
}

function loadFragmentTimeline(f) {
	initTimeline();
	
	timelineGroup.add(f);
	
	finishTimeline();
}

function collectTimelineSelectors() {
	var queue = [];
	queue.push(timelineGroup);
	
	var possibleTimelineSelectors = [];
	
	while (queue.length > 0) {
		var element = queue.shift();
		
		if (isElementFinal(element) && isElementReal(element)) {
			possibleTimelineSelectors.push(element);
		}
		else {
			for (var i = 0; i < element.children().length; i++) {
				queue.push(element.children()[i]);
			}
		}
	}
	
	return possibleTimelineSelectors;
}

function tryShowPopUpTimeline() {
	if (isTimelineActive) {
		showModal("timeline");
	}
	else {
		alert("The current svg file doesn't fit the requirements to have a timeline");
	}
}

function trySetDefaultTimeline() {
	if (isTimelineActive) {
		createDefaultTimeline();
	}
	else {
		alert("The current svg file doesn't fit the requirements to have a timeline");
	}
}

function timelineClickCallbackOpacity() {
	layers[selectedLayer].selector.animate({
		opacity:0.6
	}, 200);
		
	selectLayer(this.data("timelineLayerIndex"), false);
	
	this.animate({
		opacity:1
	}, 200);
}

function timelineHoverCallbackOpacity() {
	this.animate({
		opacity:0.8
	}, 200);
}

function timelineOutCallbackOpacity() {
	if (selectedLayer == this.data("timelineLayerName")) {
		this.animate({
			opacity:1
		}, 200);
	}
	else {
		this.animate({
			opacity:0.6
		}, 200);
	}
}

//------------------------------------------------------------------------
//Config
//------------------------------------------------------------------------

function setConfigUI() {
	/*document.getElementById("cCameraMovement").checked = config.cameraMovementEnabled;
	document.getElementById("ddCameraMovement").disabled = !config.cameraMovementEnabled;
	document.getElementById("ddCameraMovement").value = config.cameraMovementStyle;*/
}

//------------------------------------------------------------------------
//Info panels
//------------------------------------------------------------------------

function loadLocalInfoPanel(name) {
	infoPanelNames.push(name);
	Snap.load("infoPanels/" + name + ".svg", function (f) {
		var tempGroup = s.g();
		tempGroup.add(f);
		
		tempGroup.select("foreignObject").node.innerHTML = '<div xmlns="http://www.w3.org/1999/xhtml" class="infoPanel"></div>';
		
		infoPanels[name] = {
			svg : tempGroup.innerSVG().toString(),
			thumbnail : "infoPanels/thumbnails/" + name + ".png"
		};
		tempGroup.remove();
	});
}

function loadCustomInfoPanel() {
	var file = document.getElementById("fileCustomInfoPanel").files[0];
	if (file) {
		var reader = new FileReader();
		reader.readAsText(file, "UTF-8");
		reader.onload = function (evt) {
			var name = "custom" + (++customId);
			
			var f = Snap.parse(evt.target.result);
			var groupInfoPanel = s.g();
			groupInfoPanel.add(f);
			
			var allRects = groupInfoPanel.selectAll("rect");
			var toBeReplaced = null;
			
			for (var i = 0; i < allRects.length; i++) {
				if (Snap.color(allRects[i].attr("fill")).hex == "#c0ffee") {
					toBeReplaced = allRects[i];
					break;
				}
			}
			
			if (!toBeReplaced) {
				groupInfoPanel.remove();
				alert("The svg file is not valid for a info panel");
				return;
			}
			
			var allTexts = groupInfoPanel.selectAll("flowRoot");
			var style = "";
			
			if (allTexts.length > 0) {
				style = allTexts[0].attr("style");
				style += ";color:" + allTexts[0].node.style.fill + ";";
			}
			
			var x = toBeReplaced.attr("x");
			var y = toBeReplaced.attr("y");
			var width = toBeReplaced.attr("width");
			var height = toBeReplaced.attr("height");
			var parent = toBeReplaced.parent();
			
			toBeReplaced.remove();
			
			parent.add(Snap.parse('<foreignObject x="' + x + '" y="' + y + '" width="' + width + '" height="' + height + '" class="foreignInfoPanel"><div class="infoPanel" style="' + style + '"></div></foreignObject>'));
			
			infoPanelNames.push(name);
			infoPanels[name] = {
				svg : groupInfoPanel.innerSVG().toString(),
				thumbnail : "infoPanels/thumbnails/custom.png"
			};
			
			groupInfoPanel.remove();
	
			if (selectedElement) {
				reconstructModifiersUI(selectedElement);
			}
			
			hideModals();
		}
		reader.onerror = function (evt) {
			console.log("error reading file");
		}
	}
	else {
		hideModals();
	}
}

function activateInfoPanel(element, effect) {
	var f = Snap.parse(infoPanels[effect.style].svg);
	f.node.getElementsByClassName("infoPanel")[0].innerHTML = effect.text;
	
	var infoPanel = s.g();
	infoPanel.append(f);
	
	infoPanel.attr({
		id : "infoPanel" + (id++)
	});
	
	if (!element.data("infoPanelsGroup")) {
		var infoPanelsGroup = s.g();
		
		infoPanelsGroup.attr({
			id : "infoPanelsGroup" + element.attr("id")
		});
		
		if (element.data("isLegend")) {
			layers[element.data("layer")].legend.append(infoPanelsGroup);
		}
		else {
			layers[element.data("layer")].map.append(infoPanelsGroup);
		}
		element.data("infoPanelsGroup", infoPanelsGroup);
	}
	
	//first scale to get the right bbox
	var m = new Snap.Matrix();
	m.scale(effect.horizontalScale, effect.verticalScale);
	infoPanel.transform(m);
	
	
	var m = new Snap.Matrix();
	
	//as we're putting the info panel in a layer, we need to erase the transform on this layer to avoid applying them twice
	m.add(element.data("infoPanelsGroup").transform().globalMatrix.invert());
	m.add(element.transform().globalMatrix);
	var bbox = element.getBBox(true);
	var infoBbox = infoPanel.getBBox();
	switch (effect.position) {
		default : //right
			m.translate((bbox.x2 - infoBbox.x), 
						 bbox.cy - infoBbox.cy);
		break;
		case 'top' :
			m.translate((bbox.cx - infoBbox.cx), 
						 bbox.y - infoBbox.y2);
		break;
		case 'left' :
			m.translate((bbox.x - infoBbox.x2), 
						 bbox.cy - infoBbox.cy);
		break;
		case 'bottom' :
			m.translate((bbox.cx - infoBbox.cx), 
						 bbox.y2 - infoBbox.y);
		break;
	}
	m.translate(effect.horizontalOffset, effect.verticalOffset);
	m.scale(effect.horizontalScale, effect.verticalScale);
	
	infoPanel.transform(m);
	
	var textElement = infoPanel.select(".foreignInfoPanel");
	m = new Snap.Matrix();
	m.scale(1/effect.horizontalScale, 1/effect.verticalScale);
	textElement.transform(m);
	
	element.data("infoPanelsGroup").append(infoPanel);
	effect.infoPanel = infoPanel.attr("id");
}

//------------------------------------------------------------------------
//Legend
//------------------------------------------------------------------------

function activateLegend(element, effect) {
	if (element.data("isLegend")) {
		return;
	}
	
	element.data("legendUpdate", true);
	element.data("isLegend", true);
	
	if (element.data("infoPanelsGroup")) {
		layers[element.data("layer")].legend.append(element.data("infoPanelsGroup"));
	}
	
	var legendGroup = s.g();
	legendGroup.attr({
		id : "legendGroup" + element.attr("id")
	});
	layers[element.data("layer")].legend.append(legendGroup);
	legendGroup.append(element);
	
	//First, scale the element to get its new bbox
	var m = new Snap.Matrix();
	m.scale(effect.scale);
	legendGroup.transform(m);
	var bbox = element.getBBox();
	
	//the bbox of the group is not used, as it is not well computed with some paths
	
	var localMatrix = legendGroup.transform().localMatrix;
	var x = localMatrix.x(bbox.x, bbox.y);
	var y = localMatrix.y(bbox.x, bbox.y);
	var x2 = localMatrix.x(bbox.x2, bbox.y2);
	var y2 = localMatrix.y(bbox.x2, bbox.y2);
	
	//Then, translate it (independantly of the scale)
	m = new Snap.Matrix();
	switch (effect.position) {
		default : //bottom right
			m.translate(-x2 + paper.getBoundingClientRect().width, 
						-y2 + paper.getBoundingClientRect().height);
		break;
		case 'bottom-left' :
			m.translate(-x, 
						-y2 + paper.getBoundingClientRect().height);
		break;
		case 'top-right' :
			m.translate(-x2 + paper.getBoundingClientRect().width, 
						-y);
		break;
		case 'top-left' :
			m.translate(-x, 
						-y);
		break;
	}
	m.scale(effect.scale); //and scale it again (as the previous scale will be erased)
	legendGroup.transform(m)
	
	element.data("legendGroup", legendGroup);
	
	if (element.data("isSelected")) {
		reconstructSelector(element);
	}
}

function deactivateLegend(element, effect) {
	if (!element.data("isLegend")) {
		return;
	}
	
	element.data("legendUpdate", true);
	element.data("isLegend", false);
	
	if (element.data("infoPanelsGroup")) {
		layers[element.data("layer")].map.append(element.data("infoPanelsGroup"));
	}
	
	element.data("parent").append(element);
	
	if (element.data("legendGroup")) {
		element.data("legendGroup").remove();
	}
	
	if (element.data("isSelected")) {
		reconstructSelector(element);
	}
}

//------------------------------------------------------------------------
//Callbacks & UI
//------------------------------------------------------------------------

function clickCallback(event) {
	var element = this;
	
	if (element.data("isSelected")) {
		deselectElement(element);
	}
	else {
		selectElement(element);
	}
}

function hoverCallback(event) {
	var element = this;
	
	element.data("isHovered", true);
	checkModifiers(element);
}

function outCallback(event) {
	var element = this;
	
	element.data("isHovered", false);
	checkModifiers(element);
}

function updateConditionLayer() {
	var value = this.options[this.selectedIndex].value;

	this.condition.layer = value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateConditionVariable() {
	this.condition.variable = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateEffectColor(colorPicker) {
	colorPicker.valueElement.effect.color = "#" + colorPicker;
	colorPicker.valueElement.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelText() {
	this.effect.text = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelPosition() {
	var value = this.options[this.selectedIndex].value;

	this.effect.position = value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelVerticalOffset() {
	this.effect.verticalOffset = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelHorizontalOffset() {
	this.effect.horizontalOffset = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelVerticalScale() {
	this.effect.verticalScale = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelHorizontalScale() {
	this.effect.horizontalScale = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateInfoPanelStyle(select, pickerOption, event) {
	var value = this[0].options[this[0].selectedIndex].value;
	
	this[0].effect.style = value;
	this[0].modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateLegendPosition() {
	var value = this.options[this.selectedIndex].value;

	this.effect.position = value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateLegendScale() {
	this.effect.scale = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updatePathAnimationTime() {
	this.effect.time = Number(this.value);
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updatePathAnimationStart() {
	this.effect.start = Number(this.value);
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updatePathAnimationEnd() {
	this.effect.end = Number(this.value);
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function updateEffectVariable() {
	this.effect.variable = this.value;
	this.modifier.modified = true;
	checkModifiers(selectedElement);
}

function selectElement(element) {
	if (selectedElement != null) {
		deselectElement(selectedElement);
	}
		
	selectedElement = element;
	element.data("isSelected", true);
	
	//#
	dNoElementSelected.style.display = 'none';
	dElementSelected.style.display = 'block';
	
	if (elementsData[element.attr("id")].firstSelection) {
		elementsData[element.attr("id")].firstSelection = false;
		addDefaultModifiers(element);
	}
	
	reconstructModifiersUI(element);
	checkModifiers(element);
	
	//#
	reconstructSelector(element);
	
	if (!element.data("isLegend") && config.cameraMovementEnabled) {
		centerCamera(element);
	}
}

function reconstructSelector(element) {
	if (element.data("selector")) {
		element.data("selector").remove();
	}
	var bbox = element.getBBox();
	var selector = s.rect(bbox.x, bbox.y, bbox.w, bbox.h);
	
	selector.attr({
		stroke : "black", 
		style : "stroke-width:" + paper.getBoundingClientRect().width / 300 + ";stroke-opacity:0.7;stroke-dasharray:17, 34;fill-opacity:0;pointer-events:none;"
	});
	
	if (element.data("isLegend")) {
		element.data("legendGroup").append(selector);
	}
	else if (isTimelineActive) {
		layers[element.data("layer")].map.append(selector);
	}
	else {
		mapGroup.append(selector);
	}
	
	element.data("selector", selector);
}

function deselectElement(element) {
	selectedElement = null;
	element.data("isSelected", false);
	
	//#
	dNoElementSelected.style.display = 'block';
	dElementSelected.style.display = 'none';
	
	if (element.data("selector")) {
		element.data("selector").remove();
		element.data("selector", null);
	}
	
	checkModifiers(element);
}

//------------------------------------------------------------------------
//Modifiers
//------------------------------------------------------------------------

function addEmptyModifier(element) {
	var modifier = {
		conditions : [],
		effects : [],
		name : "Modifier" + (element.data("modifiers").length + 1),
		activated : false,
		modified : false,
		element : element.attr("id")
	};
	
	allModifiers.push(modifier);
	element.data("modifiers").push(modifier);
	
	return modifier;
}

function removeModifier(element, modifier) {
	element.data("legendUpdate", true); //the modifier may contain a legend effect
	
	deactivateModifier(element, modifier);
	
	var array = element.data("modifiers");
	array.splice(array.indexOf(modifier), 1);
	allModifiers.splice(allModifiers.indexOf(modifier), 1);
	
	checkModifiers(element);
	reconstructModifiersUI(element);
}

function addDefaultModifiers(element) {
	var defaultModifier = addEmptyModifier(element);
	var selectionModifier = addEmptyModifier(element);
	var hoverModifier = addEmptyModifier(element);
	
	defaultModifier.name = "Default Modifier";
	selectionModifier.name = "Select Modifier";
	hoverModifier.name = "Hover Modifier";
	
	defaultModifier.conditions.push({
		type : 'default'
	});
	
	selectionModifier.conditions.push({
		type : 'selection'
	});
	
	hoverModifier.conditions.push({
		type : 'hover'
	});
	
	//console.log(element.attr("fill"))
	
	var fill;
	if (element.node.getAttribute("fill") || (element.node.getAttribute("style") && element.node.getAttribute("style").includes("fill"))) {
		fill = Snap.color(element.attr("fill")).hex;
	}
	else {
		fill = "none";
	}
	
	if (fill != 'none') {
		defaultModifier.effects.push({
			type : 'fill',
			color : fill
		});
		
		selectionModifier.effects.push({
			type : 'fill',
			color : fill
		});
		
		/*selectionModifier.effects.push({
			type : 'infoPanel',
			text : "Kapoue",
			position : "right",
			verticalOffset : 0,
			horizontalOffset : 0,
			verticalScale : 1,
			horizontalScale : 1,
			style : 'classic'
		});*/
		
		hoverModifier.effects.push({
			type : 'fill',
			color : fill
		});
	}
	
	if (element.attr("stroke") && element.attr("stroke") != 'none') {
		defaultModifier.effects.push({
			type : 'stroke',
			color : Snap.color(element.attr("stroke")).hex
		});
		
		selectionModifier.effects.push({
			type : 'stroke',
			color : Snap.color(element.attr("stroke")).hex
		});
		
		hoverModifier.effects.push({
			type : 'stroke',
			color : Snap.color(element.attr("stroke")).hex
		});
	}
}

function addCondition() {
	var value = selectedCondition;
	
	var condition = {
		type : value
	};
	
	var shouldAdd = true;
	
	switch(condition.type) {
		case 'layerSelection':
			if (isTimelineActive) {
				condition.layer = timelineLayers[0];
			}
			else {
				shouldAdd = false;
				alert("The timeline is not active");
			}
		break;
		case 'variable':
			condition.variable = "";
		break;
		default:
			//nothing
		break;
	}
	
	if (shouldAdd) {
		currentModifier.modified = true;
		currentModifier.conditions.push(condition);
		
		checkModifiers(selectedElement);
		reconstructModifiersUI(selectedElement);
	}

	
	hideModals();
}

function addEffect() {
	var value = selectedEffect;
	
	var effect = {
		type : value
	};
	
	switch(effect.type) {
		case 'fill':
			effect.color = "#FFFFFF";
		break;
		case 'stroke':
			effect.color = "#000000";
		break;
		case 'infoPanel':
			effect.text = "";
			effect.position = "right";
			effect.verticalOffset = 0;
			effect.horizontalOffset = 0;
			effect.verticalScale = 1;
			effect.horizontalScale = 1;
			effect.style = 'classic';
		break;
		case 'legend':
			effect.position = "bottom-right";
			effect.scale = 1;
		break;
		case 'pathAnimation':
			effect.time = 1000;
			effect.start = 0;
			effect.end = 100;
		break;
		case 'setVariable':
		case 'unsetVariable':
			effect.variable = "Variable" + (id++);
		break;
		default:
			//nothing
		break;
	}
	
	currentModifier.modified = true;
	currentModifier.effects.push(effect);
	
	checkModifiers(selectedElement);
	reconstructModifiersUI(selectedElement);
	
	hideModals();
}

function checkAllModifiers() {
	for (var i = 0; i < allElements.length; i++) {
		checkModifiers(allElements[i]);
	}
}

function checkModifiers(element) {
	var modifiers = element.data("modifiers");
	for (var i = 0; i < modifiers.length; i++) {
		checkModifier(element, modifiers[i]);
	}
	
	if (element.data("legendUpdate")) {
		element.data("legendUpdate", false);
		
		for (var i = 0; i < modifiers.length; i++) {
			legendCheckModifier(element, modifiers[i]);
		}
	}
	if (element.data("variableUpdate")) {
		element.data("variableUpdate", false);
		checkAllModifiers();
	}
	element.data("firstCheck", false);
}

function checkModifier(element, modifier) {
	if (modifier.activated && modifier.modified) {
		deactivateModifier(element, modifier);
	}
	modifier.modified = false;
	
	var should = shouldBeActive(element, modifier);
	
	if (should) {
		setModifier(element, modifier);
	}
	
	if (should && !modifier.activated) {
		activateModifier(element, modifier);
	}
	else if (!should && modifier.activated) {
		deactivateModifier(element, modifier);
	}
}

function legendCheckModifier(element, modifier) {
	if (!modifier.activated) {
		return;
	}
	
	for (var i = 0; i < modifier.effects.length; i++) {
		var effect = modifier.effects[i];
		
		if (effect.type == "infoPanel") {
			deactivateEffect(element, effect);
			activateEffect(element, effect);
		}
	}
}

function shouldBeActive(element, modifier) {
	for (var i = 0; i < modifier.conditions.length; i++) {
		var condition = modifier.conditions[i]; 
		
		if (!isConditionSatisfied(element, condition)) {
			return false;
		}
	}

	return true;
}

function isConditionSatisfied(element, condition) {
	switch(condition.type) {
		case 'default':
			return !element.data("isSelected") && !element.data("isHovered")
		break;
		case 'selection':
			return element.data("isSelected")
		break;
		case 'hover':
			return element.data("isHovered")
		break;
		case 'layerSelection':
			return selectedLayer == condition.layer;
		break;
		case 'variable':
			return Boolean(variables[condition.variable]);
		break;
		default:
			console.log("UNKNOWN CONDITION TYPE : " + condition.type)
		break;
	}
}

function setModifier(element, modifier) {
	for (var i = 0; i < modifier.effects.length; i++) {
		var effect = modifier.effects[i]; 
		
		setEffect(element, effect);
	}
}

function setEffect(element, effect) {
	switch(effect.type) {
		case 'fill':
			if (element.data("firstCheck")) {
				setFillColor(effect.color, element);
			}
			else {
				animateFillColor(effect.color, element);
			}
		break;
		case 'stroke':
			if (element.data("firstCheck")) {
				setStrokeColor(effect.color, element);
			}
			else {
				animateStrokeColor(effect.color, element);
			}
		break;
		case 'setVariable':
			if (!variables[effect.variable]) {
				variables[effect.variable] = true;
				element.data("variableUpdate", true);
			}
		break;
		case 'unsetVariable':
			if (variables[effect.variable]) {
				variables[effect.variable] = false;
				element.data("variableUpdate", true);
			}
		break;
		default:
			//this effect is only used during transitions
		break;
	}
}

function activateModifier(element, modifier) {
	modifier.activated = true;
	
	for (var i = 0; i < modifier.effects.length; i++) {
		var effect = modifier.effects[i]; 
		
		activateEffect(element, effect);
	}
}

function activateEffect(element, effect) {
	switch(effect.type) {
		case 'infoPanel':
			activateInfoPanel(element, effect);
		break;
		case 'legend':
			activateLegend(element, effect);
		break;
		case 'pathAnimation':
			animatePath(element, effect);
		break;
		case 'centerCamera':
			centerCamera(element);
		break;
		default:
			//this effect has already been set
		break;
	}
}

function deactivateModifier(element, modifier) {
	modifier.activated = false;
	
	for (var i = 0; i < modifier.effects.length; i++) {
		var effect = modifier.effects[i]; 
		
		deactivateEffect(element, effect);
	}
}

function deactivateEffect(element, effect) {
	switch(effect.type) {
		case 'infoPanel':
			var oldInfoPanel = superGroup.select("#" + effect.infoPanel);
			if (oldInfoPanel) {
				oldInfoPanel.remove();
				effect.infoPanel = null;
			}
		break;
		case 'legend':
			deactivateLegend(element, effect);
		break;
		case 'pathAnimation':
			//nothing
		break;
		default:
			//this effect has already been set and does not need deactivation
		break;
	}
}

//------------------------------------------------------------------------
//Modifiers UI
//------------------------------------------------------------------------

function reconstructModifiersUI(element) {
	dModifiersContainer.innerHTML = "";
	
	var modifiers = element.data("modifiers");
	
	if (modifiers.length == 0) {
		dModifiersContainer.appendChild(pNoModifiers);
		return;
	}
	
	for (var i = 0; i < modifiers.length; i++) {
		var modifier = modifiers[i];
		
		var cloneModifier = templateModifier.cloneNode(true);
		cloneModifier.getElementsByClassName("modifierTitle")[0].innerHTML = modifier.name;
		
		//Remove button
		var removeButton = cloneModifier.getElementsByClassName("removeModifierButton")[0];
		removeButton.addEventListener('click', function(e) {
			removeModifier(element, this.modifier);
		}, false);
		removeButton.modifier = modifier;
		
		//Adds the elements for each condition
		var conditions = cloneModifier.getElementsByClassName("conditions")[0];
		conditions.innerHTML = "";
		if (modifier.conditions.length == 0) {
			conditions.appendChild(templateConditions['none'].cloneNode(true));
		}
		else {
			for (var j = 0; j < modifier.conditions.length; j++) {
				conditions.appendChild(getConditionUI(modifier, modifier.conditions[j]));
			}
		}
		
		//Add condition button
		var addConditionButton = cloneModifier.getElementsByClassName("addConditionButton")[0];
		addConditionButton.addEventListener('click', function(e) {
			currentModifier = this.modifier;
			changeSelectedCondition('base');
			showModal('addCondition');
		}, false);
		addConditionButton.modifier = modifier;
		
		//Adds the elements for each effect
		var effects = cloneModifier.getElementsByClassName("effects")[0];
		effects.innerHTML = "";
		if (modifier.effects.length == 0) {
			effects.appendChild(templateEffects['none'].cloneNode(true));
		}
		else {
			var last;
			for (var j = 0; j < modifier.effects.length; j++) {
				last = getEffectUI(modifier, modifier.effects[j]);
				effects.appendChild(last);
			}
			last.className  += " lastCondition";
		}
		
		//Add effect button
		var addEffectButton = cloneModifier.getElementsByClassName("addEffectButton")[0];
		addEffectButton.addEventListener('click', function(e) {
			currentModifier = this.modifier;
			changeSelectedEffect("base");
			showModal('addEffect');
		}, false);
		addEffectButton.modifier = modifier;
	
		dModifiersContainer.appendChild(cloneModifier);
	}
	
	jscolor.installByClassName("jscolor"); //'reboots' jscolor
	
	$('[data-toggle="tooltip"]').tooltip();
}

function getConditionUI(modifier, condition) {
	var li = document.createElement('li');
	li.className = "list-group-item";
	
	li.appendChild(templateConditions[condition.type].cloneNode(true));
	
	var clone = li;
	
	switch(condition.type) {
		case 'layerSelection':
			var select = clone.getElementsByTagName("select")[0];
			
			select.innerHTML = "";
			for (var i = 0; i < timelineLayers.length; i++) {
				select.innerHTML += "<option value='" + timelineLayers[i] + "'>" + timelineLayers[i] + "</option>";
			}
			
			select.value = condition.layer;
			select.modifier = modifier;
			select.condition = condition;
			
			select.addEventListener('change', updateConditionLayer, false);
			
			return clone;
		break;
		case 'variable':
			var input = clone.getElementsByTagName("input")[0];
			
			input.value = condition.variable;
			input.modifier = modifier;
			input.condition = condition;
			
			input.addEventListener('change', updateConditionVariable, false);
			
			return clone;
		break;
		default:
			return clone;
		break;
	}
}

function getEffectUI(modifier, effect) {
	var li = document.createElement('li');
	li.className = "list-group-item";
	
	li.appendChild(templateEffects[effect.type].cloneNode(true));
	
	var clone = li;
	
	switch(effect.type) {
		case 'fill':
			var colorPicker = clone.getElementsByClassName("colorPicker")[0];
			
			colorPicker.value = effect.color;
			colorPicker.modifier = modifier;
			colorPicker.effect = effect;
			
			return clone;
		break;
		case 'stroke':
			var colorPicker = clone.getElementsByClassName("colorPicker")[0];
			
			colorPicker.value = effect.color;
			colorPicker.modifier = modifier;
			colorPicker.effect = effect;
			
			return clone;
		break;
		case 'infoPanel':
			var textArea = clone.getElementsByTagName("textarea")[0];
			var selectPosition = clone.getElementsByTagName("select")[0];
			var verticalOffset = clone.getElementsByTagName("input")[1];
			var horizontalOffset = clone.getElementsByTagName("input")[0];
			var verticalScale = clone.getElementsByTagName("input")[3];
			var horizontalScale= clone.getElementsByTagName("input")[2];
			var selectStyle = clone.getElementsByTagName("select")[1];
			
			for (var i = 0; i < infoPanelNames.length; i++) {
				selectStyle.innerHTML += "<option data-img-src='" + infoPanels[infoPanelNames[i]].thumbnail + "' value='" + infoPanelNames[i] + "'>";
			}
			selectStyle.value = effect.style;
			$(selectStyle).imagepicker({
				selected : updateInfoPanelStyle
			});
			
			textArea.value = effect.text;
			textArea.modifier = modifier;
			textArea.effect = effect;
			
			selectPosition.value = effect.position;
			selectPosition.modifier = modifier;
			selectPosition.effect = effect;
			
			verticalOffset.value = effect.verticalOffset;
			verticalOffset.modifier = modifier;
			verticalOffset.effect = effect;
			
			horizontalOffset.value = effect.horizontalOffset;
			horizontalOffset.modifier = modifier;
			horizontalOffset.effect = effect;
			
			verticalScale.value = effect.verticalScale;
			verticalScale.modifier = modifier;
			verticalScale.effect = effect;
			
			horizontalScale.value = effect.horizontalScale;
			horizontalScale.modifier = modifier;
			horizontalScale.effect = effect;
			
			selectStyle.modifier = modifier;
			selectStyle.effect = effect;
			
			textArea.addEventListener('input', updateInfoPanelText, false);
			selectPosition.addEventListener('change', updateInfoPanelPosition, false);
			verticalOffset.addEventListener('input', updateInfoPanelVerticalOffset, false);
			horizontalOffset.addEventListener('input', updateInfoPanelHorizontalOffset, false);
			verticalScale.addEventListener('input', updateInfoPanelVerticalScale, false);
			horizontalScale.addEventListener('input', updateInfoPanelHorizontalScale, false);
			
			return clone;
		break;
		case 'legend':
			var selectPosition = clone.getElementsByTagName("select")[0];
			var scaleInput = clone.getElementsByTagName("input")[0];
			
			selectPosition.value = effect.position;
			selectPosition.modifier = modifier;
			selectPosition.effect = effect;
			
			scaleInput.value = effect.scale;
			scaleInput.modifier = modifier;
			scaleInput.effect = effect;
			
			selectPosition.addEventListener('change', updateLegendPosition, false);
			scaleInput.addEventListener('input', updateLegendScale, false);			
			return clone;
		break;
		case 'pathAnimation':
			var timeInput = clone.getElementsByTagName("input")[0];
			var startInput = clone.getElementsByTagName("input")[1];
			var endInput = clone.getElementsByTagName("input")[2];
			
			timeInput.value = effect.time;
			timeInput.modifier = modifier;
			timeInput.effect = effect;
			
			startInput.value = effect.start;
			startInput.modifier = modifier;
			startInput.effect = effect;
			
			endInput.value = effect.end;
			endInput.modifier = modifier;
			endInput.effect = effect;
			
			timeInput.addEventListener('input', updatePathAnimationTime, false);	
			startInput.addEventListener('input', updatePathAnimationStart, false);	
			endInput.addEventListener('input', updatePathAnimationEnd, false);	
			return clone;
		break;
		case 'setVariable':
		case 'unsetVariable':
			var input = clone.getElementsByTagName("input")[0];
			
			input.value = effect.variable;
			input.modifier = modifier;
			input.effect = effect;
			
			input.addEventListener('input', updateEffectVariable, false);	
			return clone;
		break;
		default:
			return clone;
		break;
	}
}

function changeSelectedCondition(value) {
	if (value == "base") {
		bAddCondition.style.display = "none";
	}
	else {
		bAddCondition.style.display = "";
		selectedCondition = value;
	}
	
	dConditionDescription.innerHTML = descriptionConditions[value];
	sConditionName.innerHTML = nameConditions[value];
}

function changeSelectedEffect(value) {
	if (value == "base") {
		bAddEffect.style.display = "none";
	}
	else {
		bAddEffect.style.display = "";
		selectedEffect = value;
	}
	
	dEffectDescription.innerHTML = descriptionEffects[value];
	sEffectName.innerHTML = nameEffects[value];
}

function changeDescriptionCondition() {
	/*var value = ddConditionChoice.options[ddConditionChoice.selectedIndex].value;
	
	dConditionDescription.innerHTML = "";
	dConditionDescription.appendChild(descriptionConditions[value]);*/
}

function changeDescriptionEffect() {
	/*var value = ddEffectChoice.options[ddEffectChoice.selectedIndex].value;
	
	dEffectDescription.innerHTML = "";
	dEffectDescription.appendChild(descriptionEffects[value]);*/
}

//------------------------------------------------------------------------
//Export & Import & Test
//------------------------------------------------------------------------

function getSavedData() {
	var savedData = {
		map : svgFileContent,
		infoPanelNames : infoPanelNames,
		infoPanels : infoPanels,
		allModifiers : allModifiers,
		elementsData : elementsData,
		timeline : timelineContent,
		timelineLayers : timelineLayers,
		timelineType : timelineType,
		config : config
	};
	
	return savedData;
}
function exportData() {
	
	var savedData = getSavedData();
	
	var zip = new JSZip();
	zip.file("data.json", "var data = " + JSON.stringify(savedData) + ";");
	
	zip.generateAsync({type:"blob"}).then(function(content) {
		saveAs(content, "inter.zip");
	});
}

function importData() {
	var file = document.getElementById("fileImportData").files[0];
	if (file) {
		JSZip.loadAsync(file).then(function(zip) {
			//showModal('loading');
			
			zip.file("data.json").async("string")
			.then(function success(content) {
				var data = JSON.parse(content.slice(11, -1));
				
				loadImportedSvgFile(data);
				loadImportedTimeline(data);
				infoPanelNames = data.infoPanelNames;
				infoPanels = data.infoPanels;
				allModifiers = data.allModifiers;
				elementsData = data.elementsData;
				config = data.config;
				
				var allElemsWithModifiers = [];
				for (var i = 0; i < allModifiers.length; i++) {
					allModifiers[i].activated = false;
					var element = superGroup.select("#" + allModifiers[i].element);
					element.data("modifiers").push(allModifiers[i]);
					allElemsWithModifiers.push(element);
				}
				
				for (var i = 0; i < allElemsWithModifiers.length; i++) {
					checkModifiers(allElemsWithModifiers[i]);
				}
				
				setConfigUI();
				hideModals();
			}, function error(e) {
				console.log("Cannot load the data");
			});
		});
	}
	else {
		hideModals();
	}
}

function testMap() {
	localStorage.setItem("data", JSON.stringify(getSavedData()));
	window.open('testMap.php','_blank');
}

//------------------------------------------------------------------------
//Popup
//------------------------------------------------------------------------

function hideModals() {
	for (var name in modals) {
		if (modals.hasOwnProperty(name)) {
			modals[name].modal("hide")
		}
	}
}

function showModal(name) {
	hideModals();
	
	modals[name].modal();
}

//------------------------------------------------------------------------
//FullScreen
//------------------------------------------------------------------------

function reconstructFullScreenIcon(isExit) {
	interfaceGroup.clear();
	interfaceGroup.attr({
		opacity: 1
	});
	
	var g = s.g();
	if (isExit) {
		g.add(exitFullScreenIcon);
	}
	else {
		g.add(fullScreenIcon);
	}
	
	interfaceGroup.add(g);
	
	var w = paper.getBoundingClientRect().width;
	var h = paper.getBoundingClientRect().height;
	
	var bbox = g.getBBox();
	
	var m = new Snap.Matrix();
	m.translate(-bbox.x2 + w,
				-bbox.y2 + h);
	m.scale(3, 3, bbox.w, bbox.h);
	g.transform(m);
	
	var bbox = g.getBBox();
	var rect = s.rect(bbox.x, bbox.y, bbox.w, bbox.h);
	
	rect.attr({
		opacity: 0
	});
	
	rect.mouseover(function() {
		interfaceGroup.animate({
			opacity: 0.5
		}, 200);
	});
	rect.mouseout(function() {
		interfaceGroup.animate({
			opacity: 1
		}, 200);
	});
	
	if (isExit) {
		rect.click(function() {
			unsetFullScreen();
		});
	}
	else {
		rect.click(function() {
			setFullScreen();
		});
	}
	
	
	interfaceGroup.add(rect);
}

function setFullScreen() {
	var fullScreenDiv = document.createElement('div');
	fullScreenDiv.id = "fullScreenDiv";
	
	fullScreenDiv.style.position = "fixed";
	fullScreenDiv.style.left = "0px";
	fullScreenDiv.style.top = "0px";
	fullScreenDiv.style.width = "100%";
	fullScreenDiv.style.height = "100%";
	fullScreenDiv.style.background = document.getElementById('paper').style.background;
	fullScreenDiv.style.zIndex = "2147483647";
	
	fullScreenDiv.append(paper);
	
	var body = document.getElementsByTagName("body")[0];
	body.append(fullScreenDiv);
	
	reconstructFullScreenIcon(true);
	centerTimeline();
}

function unsetFullScreen() {
	var fullScreenDiv = document.getElementById('fullScreenDiv');
	
	document.getElementById('paper').append(paper);
	
	document.getElementsByTagName("body")[0].removeChild(fullScreenDiv);
	
	reconstructFullScreenIcon(false);
	centerTimeline();
}

//------------------------------------------------------------------------
//Wheel & Pinch & Drag
//------------------------------------------------------------------------

function zoom(speed, x, y) {
	var svgX = paper.getBoundingClientRect().left;
	var svgY = paper.getBoundingClientRect().top;
	
	var t = new Snap.Matrix();
	t.scale(speed, speed, x-svgX, y-svgY);
	t.add(mapGroup.transform().localMatrix);
	mapGroup.transform(t);
}

function mouseWheelHandler(event) {
	var scrollTo = null;

    if (event.type == 'mousewheel') {
        scrollTo = (event.wheelDelta * -1);
    }
    else if (event.type == 'DOMMouseScroll') {
        scrollTo = 40 * event.detail;
    }

    if (scrollTo) {
        event.preventDefault();
        paper.scrollTop = scrollTo + paper.scrollTop;
    }
	
	var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
	
	
	
	if ((event.wheelDelta || -event.detail) > 0) {
        zoom(zoomSpeed, event.clientX, event.clientY);
	}
	else {
		zoom(1/zoomSpeed, event.clientX, event.clientY);
	}
}

if (isMobile()) {
	paper.onpointerdown = pointerDownHandler;
	paper.onpointermove = pointerMoveHandler;
	paper.onpointerup = pointerUpHandler;
	paper.onpointercancel = pointerUpHandler;
	paper.onpointerout = pointerUpHandler;
	paper.onpointerleave = pointerUpHandler;
}

var pointers = [];
var oldDist = -1;
var isDrag = true;
function pointerDownHandler(event) {
	pointers.push(event);
}

function pointerMoveHandler(event) {
	var oldPointers = [];
	for (var i = 0; i < pointers.length; i++) {
		oldPointers.push(pointers[i]);
		if (event.pointerId == pointers[i].pointerId) {
			pointers[i] = event;
		}
	}

	if (pointers.length == 2) { //pinch
		var dist = Math.abs(pointers[0].clientX - pointers[1].clientX);

		if (oldDist > 0) {
			 if (dist > oldDist) {
				zoom(zoomSpeed, event.clientX, event.clientY);
			 }
			 else if (dist < oldDist) {
				zoom(1/zoomSpeed, event.clientX, event.clientY);1
			}
		}
		oldDist = dist;
	}
	else if (pointers.length == 1) { //drag
		var diffX = pointers[0].clientX - oldPointers[0].clientX;
		var diffY = pointers[0].clientY - oldPointers[0].clientY;
		
		var t = new Snap.Matrix();
		t.translate(diffX, diffY);
		t.add(mapGroup.transform().localMatrix);
		mapGroup.transform(t);
	}
}

function pointerUpHandler(event) {
	
	for (var i = 0; i < pointers.length; i++) {
		if (pointers[i].pointerId == event.pointerId) {
			pointers.splice(i, 1);
			break;
		}
	}
	
	if (pointers.length < 2) {
		oldDist = -1;
	}
}

</script>

</body>
</html>
