var mode,
	player1,
	player2,
	currentPlayer,
	numbers,				// Array zur Speicherung der generierten Zahlen
	columnCount,
	gameStarted,
	clicked = [],			// Array zur Zwischenspeicherung für Informationen bereits angeklickter Karten
	duration = 2000,		// Zeit, um sich die Position der Karten zu merken in Millisekunden
	lock,					// Zum sicherstellen, dass nicht mehr als 2 Karten aufgedeckt werden
	imgMap = [],  			// Array zur Speicherung der Bilder und deren Positionen
	imgsNotOk = [];			// Array zur Speicherung von Imgs, die nicht geladen werden können

// Funktion zum "Mischen" der generierten Zahlen

Array.prototype.shuffle = function() {

	var temp = [];

	for(var i = this.length; i--;) {
		var k = Math.floor(Math.random() * this.length);
		temp.push(this[k]);
		this.splice(k, 1);
	}

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

// Funktion zur Überprüfung, ob ein Wert bereits im Array enthalten ist

Array.prototype.contains = function(obj) {

	for(var i = 0; i < this.length; i++) {
		if(this[i] == obj) {
			return true;
		}
	}

	return false;
}


// Klasse zur Speicherung von Spielerinformationen

function Player() {

	this.playerName;
	this.found = 0;
	this.attempts = 0;
	this.timer = new Timer();
};

// Klasse zur Umsetzung einer Timer-Funktionalität

function Timer() {

	var startTime;
	var tempStorage = 0;

	this.start = function() {
		startTime = new Date();
	}

	this.pause = function() {
		tempStorage += Math.floor((new Date() - startTime) / 1000);
		this.reset();
	}

	this.resume = function() {
		startTime = new Date();
	}

	this.update = function() {
		if(startTime) {
			return tempStorage + Math.floor((new Date() - startTime) / 1000);
		} else {
			return tempStorage + 0;
		}
	}

	this.reset = function() {
		startTime = null;
	}
}

$(document).ready(function() {

	// Zwischenspeichern aller jQuery-Objekte, die im Spiel manipuliert werden

	var CANCEL = $('#cancel');
	var CARD = $('.card');
	var CARDS = $('#cards');
	var CARDS_WRAPPER = $('#cardsWrapper');
	var CURRENT_PLAYER = $('#currentPlayer');
	var FIELD_SIZE = $('#fieldSize');
	var GOOGLE_SEARCH = $('#googleSearch');
	var INFO_LINE = $('#infoLine');
	var INSTRUCTIONS = $('#instructions');
	var LINE_FOR_TIME = $('.lineForTime');
	var LOGO = $('#logo');
	var MEMORY = $('#memory');
	var MODE = $('#mode');
	var NAME_PLAYER_1 = $('#namePlayer1');
	var NAME_PLAYER_2 = $('#namePlayer2');
	var RESTART = $('#restart');
	var RESULT = $('#result');
	var RESULT_OPTIONS = $('#resultOptions');
	var RESULT_TEXT = $('#resultText');
	var START = $('#start');
	var STATS = $('.stats');
	var STATS_PLAYER_1 = $('#statsPlayer1');
	var STATS_PLAYER_2 = $('#statsPlayer2');
	var STATS_PLAYER_1__ATTEMPTS = $('#statsPlayer1 #attempts');
	var STATS_PLAYER_2__ATTEMPTS = $('#statsPlayer2 #attempts');
	var STATS_PLAYER_1__FOUND = $('#statsPlayer1 #found');
	var STATS_PLAYER_2__FOUND = $('#statsPlayer2 #found');
	var STATS_PLAYER_1__STATS_NAME = $('#statsPlayer1 #statsName');
	var STATS_PLAYER_2__STATS_NAME = $('#statsPlayer2 #statsName');
	var STATS_PLAYER_1__TIME = $('#statsPlayer1 #time');
	var STATS_PLAYER_2__TIME = $('#statsPlayer2 #time');

	// Statische Variablen, die in mehreren Funktionen benötigt werden

	var fields;		// Anzahl der Felder (Karten)

	// Default-Einstellungen beim Laden der Seite festlegen

	gameStarted = false;
	mode = "singlePlayer";

	INFO_LINE.hide();
	STATS.hide();
	NAME_PLAYER_2.hide();
	RESULT.hide();

	CANCEL.click(function() {
		RESULT.hide();
		window.location = 'memory.html';
	});

	// Spielmodus auswählen und Felder zur Namensangabe einblenden

	MODE.change(function() {
		if($(this).val() === "singlePlayer") {
			NAME_PLAYER_2.hide();
		} else {
			NAME_PLAYER_2.show();
		}
	});

	// Start-Button zum Start des Spiels

	START.click(function() {
		RESULT.hide();
		startGame();
	});

	// Start des Spiels auch durch Drücken der Enter-Taste möglich

	$("#settings").each(function() {
		$(this).keypress(function(e) {
			if(e.which == 13) {
				gameStarted = false;
				startGame();
			}
		});
	});

	
	// Start des Spiels

	function startGame() {

		gameStarted = false;	// Wird erst auf true gesetzt, wenn die erste Karte aufgedeckt wird

		$('html, body').animate({ scrollTop: 120 }, 1500); 	// Zum Anfangs des Spielfelds nach unten scrollen

		STATS.hide();			// Zu Beginn des Spiels alle Spielstatistiken verbergen
		INSTRUCTIONS.hide();	// Zu Beginn des Spiels die Spielanleitung verbergen

		// Spielmodus und Feldgröße abspeichern

		mode = MODE.val();
		fields = FIELD_SIZE.val() * 1;

		// Beim Klicken des Neustarten Buttons soll das Spiel mit den gleichen Einstellungen nochmal gestartet werden
		
		RESTART.click(function() {
			RESULT.hide();
			startGame(); 
		});

		// Sperre aufheben, um Karten aufdecken zu können

		lock = false;

		// Aussehen und Position von Karten und Spielfeld vorbereiten

		numbers = new Array(fields);
		columnCount = Math.sqrt(fields);

		CARDS
			.css("width", 620)
			.css("-webkit-column-count", "" + columnCount)
			.css("-moz-column-count", "" + columnCount)
			.css("-o-column-count", "" + columnCount)
			.css("column-count", "" + columnCount);

		// Bilder laden und in Spielfeld einfügen

		getImages(generateImageMap);

		// Spieler 1 erstellen

		player1 = new Player();
		
		if (NAME_PLAYER_1.val() === "") {
			player1.playerName = "Spieler 1"
		} else {
			player1.playerName = NAME_PLAYER_1.val();
		}

		STATS_PLAYER_1.show();
		STATS_PLAYER_1__STATS_NAME.text(player1.playerName);
		console.log("Created PLAYER 1 with name: " + player1.playerName);

		// Nur im Multiplayer-Modus: Spieler 2 erstellen

		if(mode === "multiPlayer") {

			player2 = new Player();
			if (NAME_PLAYER_2.val() === "") {
				player2.playerName = "Spieler 2"
			} else {
				player2.playerName = NAME_PLAYER_2.val();
			}

			STATS_PLAYER_2.show();
			STATS_PLAYER_2__STATS_NAME.text(player2.playerName);
			console.log("Created PLAYER 2 with name: " + player2.playerName);

		}

		// Spieler 1 beginnt

		currentPlayer = player1;

		// Statistik der Spieler updaten, bis das Spiel zu Ende ist
		
		updateStatistics();
		update = setInterval(updateStatistics, 500);

	}

	// Funktion, zum Laden der benötigten Bilder aus der Google-Bildersuche

	function getImages(callback) {

		var temp = [];
		var imagesToLoad = (fields / 2);
		var search;
		var startNumber = 0;
		var ajaxRequests = Math.round(imagesToLoad / 8);

		if(GOOGLE_SEARCH.val().length != 0) {
			search = GOOGLE_SEARCH.val();
		} else {
			search = "Megan Fox";		// Standard Bilder-Thema, falls kein Suchbegriff eingegeben wurde
		}

		for (var i = 0; i < ajaxRequests; i++) {
			console.log('Sending Ajax Request...');
			$.ajax({
				url: 'https://ajax.googleapis.com/ajax/services/search/images?callback=?',
				data: {
					v: "1.0",
		            format: 'json',
		            q: search,
		            rsz: "8",
		            imgsz: "medium",
		            as_filetype: "jpg",
		            start: startNumber
		        },
		        dataType: 'json',
		        cache: false,
		        type: 'GET',
		        success: function(data) {
		        	console.log(data);
		        	for(var i = 0; i < data.responseData.results.length; i++ ) {
		        		temp.push(data.responseData.results[i].url);
		        	}
		        	preloadImages(temp);
		        	callback(temp);
		    	}
			});

			startNumber += 8;
			
		}

	}

	// Bilder in das Imagemap-Array laden und die Positionen zufällig verteilen

	function generateImageMap(images) {

		for(var i = 0, j = 0; i < fields; i += 2, j +=1 ) {
			var n = Math.floor(Math.random() * 100);

			if(!numbers.contains(n)) {
				numbers[i] = n;
				numbers[i+1] = n;
				imgMap[n] = images[j];
			} else {
				i -= 2;
				j -= 1;
			}
		}

		numbers.shuffle();
		generateBoard();

	}

	// Spielfeld erzeugen und IDs an die einzelnen Karten vergeben

	function generateBoard() {

		CARDS.empty();
		var scalingFactor = 1;		// Default-Skalierungsfaktor zur Bestimmung der Kartenbreite
		
		switch(numbers.length * 0.5) {
			case 18: scalingFactor = 1.5;
			break;
			case 32: scalingFactor = 2;
			break;
		}

		for(var i = 0; i < numbers.length; i++) {
			CARDS.append(
				$('<div />')
					.attr({
						class: "card",
						id: "pos" + (i+1),
					})
					.css("width", 115 / scalingFactor + "px")	// Kartenbreite
					.css("height", 115 / scalingFactor + "px")	// Kartenhöhe
					.click(setClickBehaviour)
					.append($('<span />').text(numbers[i]))
			);
		}

		CARDS_WRAPPER.css('width', ((CARD.css("width") + 30)  * columnCount) + 'px');
		
		if (mode === "multiPlayer") {

			STATS.css({
				display: 'inline-block',
				margin: '0 15px 0 0'
			});
				
			INFO_LINE.show();
			LINE_FOR_TIME.hide();
			CARDS_WRAPPER.css('top', '0px');
			CURRENT_PLAYER.text(currentPlayer.playerName);	

		} else {

			STATS.css({
				display: 'block',
				margin: 'auto',
				top: '30px'
			});
			
			INFO_LINE.hide();
			STATS_PLAYER_2.hide();			
			CARDS_WRAPPER.css('top', '60px');
			LINE_FOR_TIME.show();

		}
	}

	// Festlegung der Aufrufe, die nach dem "Aufdecken" einer Karte ausgeführt werden sollen

	function setClickBehaviour() {

		// Erste Karte des Spiels wird aufgedeckt -> Der Timer im Single-Player-Modus startet

		if (!gameStarted && mode === "singlePlayer") {
			gameStarted = true;
			player1.timer.start();
		}

		if(!lock) {

			if (($.inArray(imgMap[$(this).text()], imgsNotOk)) === -1 ) {

				// Wenn das Bild richtig geladen werden kann, wird es als Hintergrundbild gesetzt,...

				$(this)
					.attr("class", "clicked")
					.css("background-image", 'url("' + imgMap[$(this).text()] +'")')
					.css("background-size", "cover");

			} else {

				// ...ansonsten wird eine Zahl angezeigt.

				$(this)
					.css('background-image', 'none')
					.children('span').css('display', 'inline');

			}

			if (($(this).css('background-image').indexOf('undefined') !== -1) || ($(this).css('background-image') === 'none')) {
				
				$(this)
					.css('background-image', 'none')
					.children('span').css('display', 'inline');

			}

			check($(this).attr("id"), $(this).text());
		}
	}

	// Funktion zur Überprüfung, ob ein passendes Kartenpaar gefunden wurde

	function check(id, value) {

		if(!clicked.length) {
			
			// 1. Versuch: Die ID und der Wert der ersten aufgedeckten Karte wird zwischengespeichert.

			clicked[0] = id;
			clicked[1] = value;

			// Die Karte kann im nächsten Versuch nicht noch einmal aufgedeckt werden.

			$('#' + id).unbind("click");

		} else {

			lock = true;

			// 2. Versuch - Fall 1: Die aufgedeckte Karte passt zur vorherigen. Beide Karten können nicht mehr aufgedeckt werden.
			if(clicked[1] == value) {

				setTimeout(function() {

					$('#' + clicked[0]).attr("class", "found");
					$('#' + id).attr("class", "found").unbind('click');

					clicked = [];
					currentPlayer.found++;
					currentPlayer.attempts++;
					lock = false;

					// Alle Karten wurde bereits aufgedeckt. Spiel wird beendet und eine Zusammenfassung als Dialog angezeigt.

					if (isGameOver()) {

						if (!gameStarted && mode === "singlePlayer") {
							gameStarted = false;
							player1.timer.reset();
						}

						updateStatistics();
						clearInterval(update);
						setTimeout(showStatistics, 500);

						writeHighscore();
						updateHighscore();
					}

				}, 750);

			} else {

				// 2. Versuch - Fall 2: Die aufgedeckte Karte passt NICHT zur vorherigen. Beide Karten werden nach einer Weile wieder umgedreht.

				var temp = clicked[0];	// Die ID der zuletzt aufgedeckten Karte wird zwischenspeichert.
				clicked = [];			// Die Informationen über die erste aufgedeckte Karte werden gelöscht.

				currentPlayer.attempts++;

				if (mode === "multiPlayer") {
					switchPlayer();	
				}

				setTimeout(function() {

					$('#' + temp)
						.attr("class", "card")
						.bind('click', setClickBehaviour)
						.css("background-image", 'url("img/rauten.jpg")')
						.children('span').css('display', 'none');
						
					$('#' + id)
						.attr("class", "card")
						.css("background-image", 'url("img/rauten.jpg")')
						.children('span').css('display', 'none');

					CURRENT_PLAYER.text(currentPlayer.playerName);	
					lock = false;

				}, duration);
			}
		}
	}

	// Nur im Multiplayer-Modus: Spieler wechseln

	function switchPlayer() {
		if(currentPlayer === player1) {
			currentPlayer = player2;
		} else {
			currentPlayer = player1;
		}
	}

	// Statistiken aktualisieren und anzeigen

	function updateStatistics() {

		STATS_PLAYER_1__FOUND.text(player1.found + " von " + numbers.length * 0.5);
		STATS_PLAYER_1__ATTEMPTS.text(player1.attempts);
		STATS_PLAYER_1__TIME.text(player1.timer.update() + " Sek.");
		
		if (mode === "multiPlayer") {
			STATS_PLAYER_2__FOUND.text(player2.found + " von " + numbers.length * 0.5);
			STATS_PLAYER_2__ATTEMPTS.text(player2.attempts);
			STATS_PLAYER_2__TIME.text(player2.timer.update() + " Sek.");

			// Statistiken verbergen, falls style-xs.css eingebunden und das Logo nicht sichtbar ist
			// sowie weitere Responsive Design Änderungen, die dynamisch im JS festgelegt werden müssen

			if (LOGO.css('display') === "none") {

				STATS.hide();
				CARDS_WRAPPER.css('left', '0px');

			} else if ($(window).width() < 1270) {

				CARDS_WRAPPER.css('left', '170px');
				STATS.show();
				STATS.css('position', 'absolute');
				STATS.css('margin', '0 15px');
				STATS_PLAYER_2.css({
					left: '0px',
					top: '200px'
				});

			} else {

				STATS.css({
					position: 'relative',
					display: 'inline-block',
					margin: '0 15px 0 0'
				});	
				CARDS_WRAPPER.css('left', '0px');
				STATS_PLAYER_2.css({
					top: '30px',
				});
				STATS.show();

			}
		} else {

			STATS.css({
				position: 'relative',
				left: '0px'});

		}
	}

	// Funktion zur Ermittlung des Spielendes

	function isGameOver() {

		if (mode === "singlePlayer") {
			return player1.found >= numbers.length * 0.5;
		} else {
			return (player1.found + player2.found) >= numbers.length * 0.5;
		}
	}

	// Funktion für das Pre-Loading der Bilder, um die Performance des Spiels zu verbessern

	function preloadImages(images) {

		$.each(images, function(i, v) {
			$('<img />')
				.error(function() { imgsNotOk.push(images[i]); })
				.attr("src", images[i]);
		});

	}

	// Funktion zum Anzeigen des Ergebnisses

	function showStatistics() {

		RESULT_TEXT.empty();

		if(mode === "singlePlayer") {

			$('<span />').text("Gratuliere! Du gewinnst nach " + player1.timer.update() + " Sekunden mit " + player1.attempts + " Versuchen.")
				.prependTo(RESULT_TEXT);

			RESULT.show();
			player1.timer.reset();

		} else {

			if (player1.found > player2.found) {

				$('<span />').text(player1.playerName + " gewinnt mit " + player1.found + " gefundenen Paaren.")
				.prependTo(RESULT_TEXT);

			} else if (player1.found < player2.found) {

				$('<span />').text(player2.playerName + " gewinnt mit " + player2.found + " gefundenen Paaren.")
				.prependTo(RESULT_TEXT);

			} else {

				$('<span />').text("Unentschieden! Beide Spieler haben " + player1.found + " Paare.")
				.prependTo(RESULT_OPTIONS);

			}

			RESULT.show();

		}
	}

});