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 svgX = paper.getBoundingClientRect().left;
var svgY = paper.getBoundingClientRect().top;

var group = s.g();
group.attr({
	id : "kapoueMap"
});
group.drag();

var selectedElement;

var f = Snap.parse(savedData.map);

group.append(f);

var box = group.getBBox();
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);
group.transform(m);

var id = 0;

function initializeChild(element) {
	if (isElementFinal(element)) {
		if (savedData.elements[element.attr("id")]) {
			
			element.data("id", element.attr("id"));
			
			var elementData = savedData.elements[element.attr("id")];
			
			element.data("fill", elementData.fill);
			element.data("stroke", elementData.stroke);
			element.data("fillHover", elementData.fillHover);
			element.data("strokeHover", elementData.strokeHover);
			element.data("fillSelected", elementData.fillSelected);
			element.data("strokeSelected", elementData.strokeSelected);
			
			element.data("isLegend", elementData.isLegend);
			element.data("positionLegend", elementData.positionLegend);
			
			if (elementData.infoText) {
				element.data("infoText", elementData.infoText);
				element.data("offsetInfoText", elementData.offsetInfoText);
				element.data("positionInfoText", elementData.positionInfoText);
				element.data("styleInfoText", elementData.styleInfoText);
				
				var f = Snap.parse(savedData.styles[element.data("styleInfoText")]);
				
				f.node.getElementById("foreignInfoText").innerHTML = "<p xmlns='http://www.w3.org/1999/xhtml' class='infoText'>" + element.data("infoText") + "</p>";
					
				var groupInfoText = s.g();
				groupInfoText.append(f);
				
				group.append(groupInfoText);
				
				var m = new Snap.Matrix();
				m.add(element.transform().globalMatrix);
				var bbox = getRealBBox(element);
				var infoBbox = groupInfoText.getBBox();
				switch (element.data("positionInfoText")) {
					default : //right
						m.translate((bbox.x2 - infoBbox.x + element.data("offsetInfoText")), 
									 bbox.cy - infoBbox.cy);
					break;
					case 1 : //top
						m.translate((bbox.cx - infoBbox.cx), 
									 bbox.y - infoBbox.y2 - element.data("offsetInfoText"));
					break;
					case 2 : //left
						m.translate((bbox.x - infoBbox.x2 - element.data("offsetInfoText")), 
									 bbox.cy - infoBbox.cy);
					break;
					case 3 : //bottom
						m.translate((bbox.cx - infoBbox.cx), 
									 bbox.y2 - infoBbox.y + element.data("offsetInfoText"));
					break;
				}
				groupInfoText.transform(m);
				
				groupInfoText.attr({ display : "none" });
				
				element.data("eInfoText", groupInfoText);
				element.data("eInfoTextBBox", groupInfoText.getBBox()); //UNUSED; IF BUGGY; MAY COME FROM THIS
			}
			
			if (element.data("isLegend")) {
					
				var bbox = getRealBBox(element);
				var legendGroup = s.g();
				legendGroup.attr({
					id : "kapoueLegend" + element.attr("id")
				});
				element.remove();
				legendGroup.append(element);
				
				var m = new Snap.Matrix();
				m.add(element.transform().localMatrix.invert());
				switch (element.data("positionLegend")) {
					default : //bottom right
						m.translate(-bbox.x2 + paper.getBoundingClientRect().width, 
									-bbox.y2 + paper.getBoundingClientRect().height);
					break;
					case 1 : //bottom left
						m.translate(-bbox.x, 
									-bbox.y2 + paper.getBoundingClientRect().height);
					break;
					case 2 : //top right
						m.translate(-bbox.x2 + paper.getBoundingClientRect().width, 
									-bbox.y);
					break;
					case 3 : //top left
						m.translate(-bbox.x, 
									-bbox.y);
					break;
				}
				legendGroup.transform(m);
			}
			
			element.click(clickCallback);
			element.mouseover(hoverCallback);
			element.mouseout(outCallback);
		}
	}
	else {
		element.children().forEach(function(child) {
			initializeChild(child);
		});
	}
}

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

function isElementFinal(element) {
	return element.children().length == 0 || (element.type == "g" && !(element.attr("id") && (element.attr("id").startsWith("layer") || element.attr("id").startsWith("kapoue"))));
}

function getRealBBox(element) {
	if (element.children().length == 0) {
		return element.getBBox();
	}
	else {
		var bbox = element.getBBox();
		
		bbox.x = Number.MAX_VALUE;
		bbox.y = Number.MAX_VALUE;
		
		bbox.x2 = Number.MIN_VALUE;
		bbox.y2 = Number.MIN_VALUE;
		for (var i = 0; i < element.children().length; i++) {
			var cbox = getRealBBox(element.children()[i]);
			
			if (cbox.w == 0 && cbox.h == 0) {
				continue;
			}
			
			bbox.x = Math.min(bbox.x, cbox.x);
			bbox.y = Math.min(bbox.y, cbox.y);
			
			bbox.x2 = Math.max(bbox.x2, cbox.x2);
			bbox.y2 = Math.max(bbox.y2, cbox.y2);
		}
		
		bbox.cx = (bbox.x + bbox.x2) / 2;
		bbox.cy = (bbox.y + bbox.y2) / 2;
		
		return bbox;
	}
}

//------------------------------------------------------------------------
//UI
//------------------------------------------------------------------------

var clickCallback = function(event) {
	//Changes in selected elements
	if (selectedElement != null) {
		if (selectedElement.data("eInfoText")) {
			selectedElement.data("eInfoText").attr({ display : "none" });
		}
		
		animateColor(selectedElement.data("fill"), selectedElement.data("stroke"), selectedElement);
	}
	
	if (selectedElement == this) {
		if (selectedElement.data("eInfoText")) {
			selectedElement.data("eInfoText").attr({ display : "none" });
		}
		
		selectedElement = null;
		return;
	}
	
	selectedElement = this;
	
	animateColor(this.data("fillSelected"), this.data("strokeSelected"), this);
	
	//Center camera on objects
	if (selectedElement.data("eInfoText")) {
		selectedElement.data("eInfoText").attr({ display : "" });
		
		var selBox = getRealBBox(selectedElement);
		var infoBox = selectedElement.data("eInfoText").getBBox();
		
		var mat = selectedElement.transform().globalMatrix;
		var m = new Snap.Matrix();
			
		var tX, tY;
		var scaleX = 0.9 * paper.getBoundingClientRect().width;
		var scaleY = 0.9 * paper.getBoundingClientRect().height;
		switch (selectedElement.data("positionInfoText")) {
			default : //right
				tX = (mat.a * selBox.x + mat.e  +  infoBox.x2) / 2;
				tY = mat.d * selBox.cy + mat.f;
				scaleX /= (infoBox.x2 - (mat.a * selBox.x + mat.e));
				scaleY /= Math.max(mat.d * selBox.h, infoBox.h);
			break;
			case 1 : //top
				tX = mat.a * selBox.cx + mat.e;
				tY = (mat.d * selBox.y2 + mat.f  +  infoBox.y) / 2;
				scaleX /= Math.max(mat.a * selBox.w, infoBox.w);
				scaleY /= (- infoBox.y + (mat.d * selBox.y2 + mat.f));
			break;
			case 2 : //left
				tX = (mat.a * selBox.x2 + mat.e  +  infoBox.x) / 2;
				tY = mat.d * selBox.cy + mat.f;
				scaleX /= (- infoBox.x + (mat.a * selBox.x2 + mat.e));
				scaleY /= Math.max(mat.d * selBox.h, infoBox.h);
			break;
			case 3 : //bottom
				tX = mat.a * selBox.cx + mat.e;
				tY = (mat.d * selBox.y + mat.f  +  infoBox.y2) / 2;
				scaleX /= Math.max(mat.a * selBox.w, infoBox.w);
				scaleY /= (infoBox.y2 - (mat.d * selBox.y + mat.f));
			break;
		}
		
		m.translate(-tX, -tY);
		m.translate(paper.getBoundingClientRect().width / 2,
					paper.getBoundingClientRect().height / 2);
		
		var scale = Math.min(scaleX, scaleY);
		m.scale(scale, scale, tX, tY);
		
		group.animate({ transform: m}, 1000);
	}
};

var hoverCallback = function(event) {
	if (this.data("fillHover")) {
		animateColor(this.data("fillHover"), this.data("strokeHover"), this)
	}
}

var outCallback = function(event) {
	if (selectedElement != this) {
		if (this.data("fill")) {
			animateColor(this.data("fill"), this.data("stroke"), this)
		}
	}
	else {
		if (this.data("fillSelected")) {
			animateColor(this.data("fillSelected"), this.data("strokeSelected"), this)
		}
	}
}

initializeChild(group);

//------------------------------------------------------------------------
//Updates
//------------------------------------------------------------------------

function animateColor(colorFill, colorStroke, element) {
	var fromFill = Snap.color(Snap.color(element.attr("fill")).hex)
	var toFill = Snap.color(colorFill)
	
	var fromStroke = Snap.color(Snap.color(element.attr("stroke")).hex)
	var toStroke = Snap.color(colorStroke)
	
	Snap.animate([fromFill.r, fromFill.g, fromFill.b, fromStroke.r, fromStroke.g, fromStroke.b], [toFill.r, toFill.g, toFill.b, toStroke.r, toStroke.g, toStroke.b], function (val) {
		var fillColor = "rgb(" + Math.round(val[0]) + "," + Math.round(val[1]) + "," + Math.round(val[2]) + ")";
		var strokeColor = "rgb(" + Math.round(val[3]) + "," + Math.round(val[4]) + "," + Math.round(val[5]) + ")";
		
		element.attr({ //removes the old values
			fill : fillColor,
			stroke : strokeColor
		});
		
		element.attr({
			style :  element.attr("style") + ";fill: " + fillColor + ";stroke: " + strokeColor
		});
	}, 200);
	
	element.children().forEach(function(child) {
		if (child.type != "#text") {
			animateColor(colorFill, colorStroke, child);
		}
	});
}

//------------------------------------------------------------------------
//Wheel
//------------------------------------------------------------------------

function mouseWheelHandler(event) {
	var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
	
	if ((event.wheelDelta || -event.detail) > 0) {
        var t = new Snap.Matrix();
        t.scale(zoomSpeed, zoomSpeed, event.pageX-svgX, event.pageY-svgY);
        t.add(group.transform().localMatrix);
        group.transform(t);
		
		currentZoom *= zoomSpeed;
	}
	else {
		var t = new Snap.Matrix();
        t.scale(1/zoomSpeed, 1/zoomSpeed, event.pageX-svgX, event.pageY-svgY);
        t.add(group.transform().localMatrix);
        group.transform(t);
		
		currentZoom /= zoomSpeed;
	}
}