'use strict';

/**
 @author María Andrea Cruz Blandón
*@description A module representing the rain game, this game is about element that are falling from top of screen
and the user has to figure out which option is the answer before the time finish
*@Module sgGameRain
*/

define(['jquery', 'sgPopUp', 'sgSound'], function($, sgPopUp, sgSound) {
	var app = {};

	app.init = function() {
		var $rainGame = $('[data-sg-id=game-rain]');

		if ($rainGame.length == 0) return;

		$rainGame.each(function(e, i) {
			var $me = $(this);

			// It is mandatory that each rainGame has time, number of attempts before change the time, the change of time and the stop element
			if ($me.attr('data-sg-time') == undefined || $me.attr('data-sg-attempt') == undefined ||
				$me.attr('data-sg-time-change') == undefined || $me.attr('data-sg-stop') == undefined) {
				console.error('sgGameRain: sg-game-rain should have all the attributes: sg-time, sg-attempt, sg-time-change, sg-stop.');
				return;
			}

			try {
				var time = parseInt($me.attr('data-sg-time'));
			} catch (error) {
				console.error('sgGameRain: sg-time should be an integer.');
				return;
			}

			if (time <= 0) {
				console.error('sgGameRain: sg-time should be an positive integer more than 0.');
				return;
			}

			try {
				var attempt = parseInt($me.attr('data-sg-attempt'));
			} catch (error) {
				console.error('sgGameRain: sg-attempt should be an integer.');
				return;
			}

			if (attempt <= 0) {
				console.error('sgGameRain: sg-attempt should be an positive integer more than 0.');
				return;
			}

			try {
				var timeChange = parseInt($me.attr('data-sg-time-change'));
			} catch (error) {
				console.error('sgGameRain: sg-time-change should be an integer.');
				return;
			}

			if (timeChange == 0) {
				console.error('sgGameRain: sg-time-change should be different of 0.');
				return;
			}

			var stopElement = $($me.attr('data-sg-stop'));

			if (stopElement.length == 0) {
				console.error('sgGameRain: sg-stop has to have the identifier of an existing element.');
				return;
			}

			var config = {
				'time': time,
				'attempt': attempt,
				'timeChange': timeChange,
				'stopElement': stopElement
			};
			$me.data('config', config);

			var summary = $me.attr('data-sg-fun-summary');
			if (summary == undefined) {
				console.warn('sgGameRain: data-sg-summary is not define when the btn-game has the summary function nothing is going to happen');
			}

			var $listElems = $me.find('[data-sg-id=list-elems]');

			if ($listElems.length == 0) {
				console.error('sgGameRain: sg-game-rain should have a sg-list-elems child.');
				return;
			} else if ($listElems.length > 1) {
				console.error('sgGameRain: sg-game-rain should have just one sg-list-elems child.');
				return;
			}

			var boolRand = $listElems.attr('data-sg-rand') != undefined ? 1 : 0;

			var $elements = $listElems.find('[data-sg-id=elem-rain]');
			var $totalElems = $elements.length;
			var elemsArray = [$totalElems];

			for (var index = 0; index < $totalElems; index++) {
				elemsArray[index] = undefined;
			}

			if ($totalElems == 0) {
				console.error('sgGameRain: sg-list-elems should have sg-elem-rain children.');
				return;
			}

			var $totalParts=0;

			$elements.each(function(f, j) {
				var $elem = $(this);

				var $parts = $elem.find('[data-sg-id=part-elem]');
				var totalPartsTemp = $parts.length;

				if(totalPartsTemp>$totalParts){
					$totalParts = totalPartsTemp;
				}

				if ($totalParts == 0) {
					console.error('sg-game-rain: sg-elem-rain should have sg-part-elem children or at least one.');
					return;
				}

				var elemJson = {};

				$parts.each(function(g, k) {
					var $part = $(this);
					var key = $part.find('[data-sg-id=part-complete]').attr('data-sg-right');

					if (key == undefined) {
						console.error('sg-game-rain: sg-part-elem should have sg-part-complete child with its respective sg-right attribute.');
						return;
					}
					elemJson[g] = {
						'key': key,
						'current': undefined
					};
				});

				elemJson['elem'] = f;
				elemJson['parts']= totalPartsTemp;

				if (boolRand) {
					var index = Math.floor(Math.random() * $totalElems);
					while (elemsArray[index] != undefined) {
						index = Math.floor(Math.random() * $totalElems);
					}
					elemsArray[index] = elemJson;
				} else {
					elemsArray[f] = elemJson;
				}
			});
			
			// console.log(elemsArray);
			// console.log($totalParts);

			//Add to main object $me the array of elements with its objects
			$me.data('elemsArray', elemsArray);
			$me.data('totalElems', $totalElems);
			$me.data('totalParts', $totalParts);

			var $listSpinners = $me.find('[data-sg-id=list-spinners]');

			if ($listSpinners.length == 0) {
				console.error('sgGameRain: sg-game-rain should have a sg-list-spinners child.');
				return;
			} else if ($listSpinners.length > 1) {
				console.error('sgGameRain: sg-game-rain should have just one sg-list-spinners child.');
				return;
			}

			var $spinners = $listSpinners.find('[data-sg-id=spinner]');
			var $totalSpinners = $spinners.length;
			if ($totalSpinners == 0) {
				console.error('sgGameRain: sg-list-spinners should have sg-spinner children or at least one.');
				return;
			}

			//This means that the developer use just one spinner to describe all the spinners which will be 
			//necessaries in the game.
			if ($totalSpinners == 1 && $totalParts > 1) {
				var extraSpinners = $totalParts - $totalSpinners;
				for (var index = 0; index < extraSpinners; index++) {
					$spinners.clone().appendTo($listSpinners);
				}
				$totalSpinners = $totalParts;
			}

			if ($totalSpinners != $totalParts) {
				console.error('sgGameRain: sg-list-spinners have to contain the same amount of sg-spinner than number of parts of the largest element.');
				return;
			}

			$spinners = $listSpinners.find('[data-sg-id=spinner]'); //Update

			var $totalOptions;

			$spinners.each(function(f, j) {

				var $spinner = $(this);

				var $options = $spinner.find('[data-sg-id=item-spinner]');
				if ($options.length == 0) {
					console.error('sgGameRain: sg-spinner should have at least one sg-item-spinner child.');
					return;
				}

				$totalOptions = $options.length;

				$options.each(function(g, k) {
					var $option = $(this);
					$option.css("cursor", "pointer");
					$option.click(itemSpinnerClick(f));

				});
			});

			var $numOptions = $listSpinners.attr('data-sg-num');
			if ($numOptions != undefined) {

				if ($numOptions == 0) {
					console.error('sgGameRain: sg-num in sg-list-spinners should be more than 0.');
					return;
				}
				if ($numOptions == $totalOptions) {
					$numOptions = undefined;
				}
				$me.data('numOptions', $numOptions);
			}

			if ($numOptions != undefined) {
				var optionsArray = {};
				for (var index = 0; index < $totalElems; index++) {
					var elemJson = elemsArray[index];
					var optionsJson = {};

					for (var parts = 0; parts < elemJson['parts']; parts++) {
						var arrayFinalOpt = [$numOptions];
						var indexesArray = [$totalOptions];
						for (var opt = 0; opt < $totalOptions; opt++) {
							indexesArray[opt] = opt;
						}
						var key = elemJson[parts]['key'];
						var indexItem = $spinners.eq(parts).find('[data-sg-id=item-spinner][data-sg-key=' + key + ']').index();
						arrayFinalOpt[0] = indexItem;
						indexesArray.splice(indexesArray.indexOf(indexItem), 1);
						for (var opt = 1; opt < $numOptions; opt++) {
							var indexOpt = indexesArray[(Math.floor(Math.random() * indexesArray.length))];
							arrayFinalOpt[opt] = indexOpt;
							indexesArray.splice(indexesArray.indexOf(arrayFinalOpt[opt]), 1);
						}
						optionsJson[parts] = arrayFinalOpt;
					}
					optionsArray[index] = optionsJson;
				}

				$me.data('optionsArray', optionsArray);
			}

			//Default is disabled
			var $checkBtn = $me.find('[data-sg-id=btn-check]');

			if ($checkBtn.length == 0) {
				console.error('sgGameRain: sg-game-rain should have a sg-btn-check child.');
				return;
			} else if ($checkBtn.length > 1) {
				console.error('sgGameRain: sg-game-rain should have just one sg-btn-check child.');
				return;
			}

			$checkBtn.click(checkElem);
			$checkBtn.unbind('click');
			$checkBtn.css('cursor', 'auto');


			//Game functions
			$me.data('activeElem', 0); //Element falling
			$me.data('gameStatus', 0); //0->init 1-totalElems->Elements falling (totalElems+1)->Summary

			var $gameBtn = $me.find('[data-sg-id=btn-game]');

			if ($gameBtn.length == 0) {
				console.error('sgGameRain: sg-game-rain should have a sg-btn-game child.');
				return;
			} else if ($gameBtn.length > 1) {
				console.error('sgGameRain: sg-game-rain should have just one sg-btn-game child.');
				return;
			}

			$gameBtn.click(functionGame);

			/***/
			if ($numOptions != undefined) {
				var elemOptions = optionsArray[$me.data('activeElem')];
				$spinners.find('[data-sg-id=item-spinner]').each(function(j, g){
					var $item = $(this);
					$item.hide();
					$item[0].className = $item[0].className.replace(/\bvisible.*?\b/g, '');
				});
				
				var totalPartsActiveElem = elemsArray[$me.data('activeElem')]['parts'];

				$spinners.hide();				
				for(var index = 0; index < totalPartsActiveElem; index++){
					$spinners.eq(index).show();
				}
				for (var index = 0; index < totalPartsActiveElem; index++) {
					var itemList = $spinners.eq(index).find('[data-sg-id=item-spinner]');
					for (var opt = 0; opt < $numOptions; opt++) {
						itemList.eq(elemOptions[index][opt]).show().addClass('visible');
					};
				}
				for (var index = 0; index < totalPartsActiveElem; index++) {
					$spinners.eq(index).find('[data-sg-id=item-spinner].visible').each(function(j, g) {
						var $item = $(this);
						$item[0].className = $item[0].className.replace(/\bvisible.*?\b/g, '');
						$item.addClass('visible' + j);
					});
				}
			}
			/***/
			removeClickItems($me);
			hideElements($me);
			instructions();
		});
	};

	function itemSpinnerClick(numPart) {
		return function() {
			var $me = $(this);
			var content = $me.html();
			//Find active elem
			var $game = $me.parent().parent().parent();
			var active = $game.data('activeElem');
			var key = $me.attr('data-sg-key');
			$game.data('elemsArray')[active][numPart]['current'] = key;
			var elemNum = $game.data('elemsArray')[active]['elem'];
			var $elem = $game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]').eq(elemNum);
			$elem.find('[data-sg-id=part-elem]').eq(numPart).find('[data-sg-id=part-complete]').html(content);
		}
	}

	function removeClickItems(game) {
		var $spinners = game.find('[data-sg-id=list-spinners]').find('[data-sg-id=spinner]');
		$spinners.each(function(i, l) {
			var $spinner = $(this);
			var $options = $spinner.find('[data-sg-id=item-spinner]');
			$options.each(function(j, k) {
				var $option = $(this);
				$option.unbind('click');
				$option.css('cursor', 'auto');
			})
		});
	}

	function addClickItems(game) {
		var $spinners = game.find('[data-sg-id=list-spinners]').find('[data-sg-id=spinner]');
		$spinners.each(function(i, l) {
			var $spinner = $(this);
			var $options = $spinner.find('[data-sg-id=item-spinner]');
			$options.each(function(j, k) {
				var $option = $(this);
				$option.bind('click');
				$option.click(itemSpinnerClick(i));
				$option.css('cursor', 'pointer');
			})
		});
	}

	function instructions() {
		$('[data-sg-id=game-rain]').each(function(e, i) {
			var $btnPopup = $(this).find('> [data-sg-id=btn-popup]');
			if ($(this).is(':visible'))
				$btnPopup.click();
		});
	}

	function checkElem() {
		var $me = $(this);
		var $game = $(this).parent();
		var active = $game.data('activeElem');
		var elemJson = $game.data('elemsArray')[active];

		var elemNum = $game.data('elemsArray')[active]['elem'];
		var $elem = $game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]').eq(elemNum);

		var $parts = $elem.find('[data-sg-id=part-elem].wrong');

		$parts.each(function(i, k) {
			var $part = $(this);

			var index = $part.index();
			var key = elemJson[index]['key'];

			var rightItem = $game.find('[data-sg-id=list-spinners]').find('[data-sg-id=spinner]').
			eq(index).find('[data-sg-id=item-spinner][data-sg-key=' + key + ']').html();
			$part.removeClass('wrong').addClass('corrected')
			$part.find('[data-sg-id=part-complete]').html(rightItem);
		});

		//Update data
		$game.data('activeElem', (active + 1)); //Change active element
		$me.unbind('click');
		$me.css('cursor', 'auto');
		$game.find('[data-sg-id=btn-game]').bind('click').css('cursor', 'pointer');
		$game.find('[data-sg-id=btn-game]').click(functionGame);

	}

	function functionGame() {
		var $me = $(this);
		var $game = $me.parent();

		var config = $game.data('config');
		var stopElement = $(config['stopElement']);
		var time = config['time'];
		var attempt = config['attempt'];
		var timeChange = config['timeChange'];
		var active = $game.data('activeElem');
		var gameStatus = $game.data('gameStatus');
		var totalElems = $game.data('totalElems');
		var totalParts = $game.data('totalParts');

		$me.unbind('click');
		$me.css('cursor', 'auto');

		if (gameStatus == 0) { //INIT
			$me.removeClass('init');
			$me.addClass('game');

			var elemJson = $game.data('elemsArray')[active];
			var elemNum = elemJson['elem'];
			var $elemAnimation = $game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]').eq(elemNum);
			$elemAnimation.css('top', '0px');
			$elemAnimation.show();
			$elemAnimation.find('[data-sg-id=part-elem]').addClass("current_elem");
//			console.log($elemAnimation.html());
			var finalPos = stopElement.css('top');
			addClickItems($game);
			$elemAnimation.animate({
					"top": "+=" + finalPos
				}, time * 1000,
				function() {
					removeClickItems($game);
					verifyAnswer($elemAnimation, elemJson);
					//Update variables		
					gameStatus = gameStatus + 1;
					$game.data('gameStatus', gameStatus);
					$game.data('config', config);
					$(this).find('[data-sg-id=part-elem]').removeClass("current_elem");
				}
			);

		} else if (gameStatus > 0 && gameStatus < totalElems) { //NEXT ELEMENT
			//Order options
			if ($game.data('numOptions') != undefined) {
				var elemOptions = $game.data('optionsArray')[active];
				var $spinners = $game.find('[data-sg-id=list-spinners]').find('[data-sg-id=spinner]');
				$spinners.find('[data-sg-id=item-spinner]').each(function(j, g){
					var $item = $(this);
					$item.hide();
					$item[0].className = $item[0].className.replace(/\bvisible.*?\b/g, '');
				});

				var totalPartsActiveElem = $game.data('elemsArray')[active]['parts'];

				$spinners.hide();
				for(var index = 0; index < totalPartsActiveElem; index++){
					$spinners.eq(index).show();
					console.log($spinners.eq(index));
				}
				
				for (var index = 0; index < totalPartsActiveElem; index++) {
					var itemList = $spinners.eq(index).find('[data-sg-id=item-spinner]');
					for (var opt = 0; opt < $game.data('numOptions'); opt++) {
						itemList.eq(elemOptions[index][opt]).show().addClass('visible');
					};
				}
				for (var index = 0; index < totalPartsActiveElem; index++) {
					$spinners.eq(index).find('[data-sg-id=item-spinner].visible').each(function(j, g) {
						var $item = $(this);
						$item[0].className = $item[0].className.replace(/\bvisible.*?\b/g, '');
						$item.addClass('visible' + j);
					});
				}
			}


			//hide last element
			var lastElemNum = $game.data('elemsArray')[active - 1]['elem'];
			$game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]').eq(lastElemNum).hide();

			var elemJson = $game.data('elemsArray')[active];
			var elemNum = elemJson['elem'];
			var totalPartsActiveElem = elemJson['parts'];
			var $elemAnimation = $game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]').eq(elemNum);
			$elemAnimation.css('top', '0px');
			$elemAnimation.find('[data-sg-id=part-elem]').addClass("current_elem");
			$elemAnimation.show();
			var finalPos = stopElement.css('top');
			addClickItems($game);

			//Which spinner show
			var $spinners = $game.find('[data-sg-id=list-spinners]').find('[data-sg-id=spinner]');
			$spinners.hide();
			for (var index = 0; index < totalPartsActiveElem; index++) {
				$spinners.eq(index).show();
				console.log($spinners.eq(index));
			}

			//Update level
			var slot = (active / attempt);
			if ((typeof slot === 'number') && (slot % 1 === 0)) {
				time = slot * timeChange + time;
			}

			$elemAnimation.animate({
					"top": "+=" + finalPos
				}, time * 1000,
				function() {
					removeClickItems($game);
					verifyAnswer($elemAnimation, elemJson);
					//Update variables		
					gameStatus = gameStatus + 1;
					$game.data('gameStatus', gameStatus);
					$game.data('config', config);

					if (gameStatus == totalElems) {
						$me.removeClass('game');
						$me.addClass('summary');
					}
					$(this).find('[data-sg-id=part-elem]').removeClass("current_elem");
				}
			);

		} else if (gameStatus == totalElems) { //SUMMARY
			summaryFunction($game);
			return;
		}
		// For plugins effects personalization
		app.changecontrols();
	}

	function verifyAnswer(elem, elemJson) {
		var $parts = elem.find('[data-sg-id=part-elem]');
		var totalParts = elemJson['parts'];

		var correct = false;

		for (var i = 0; i < totalParts; i++) {
			var current = elemJson[i]['current'];
			var key = elemJson[i]['key'];

			if (current != key) {
				$parts.eq(i).addClass('wrong');
				correct = true;
			} else {
				$parts.eq(i).addClass('right');
			}
		};

		elem.parent().parent().find('[data-sg-id=btn-check]').bind('click');
		elem.parent().parent().find('[data-sg-id=btn-check]').css('cursor', 'pointer');
		elem.parent().parent().find('[data-sg-id=btn-check]').click(checkElem);

		app.changecontrols2();
	}

	function hideElements(game) {
		var $elems = game.find('[data-sg-id=list-elems]').find('[data-sg-id=elem-rain]');
		$elems.each(function(i, k) {
			var $elem = $(this);
			$elem.hide();
		});
	}

	function summaryFunction(game) {
		var summary = game.attr('data-sg-fun-summary');

		var fn = window[summary];
		console.log(fn)
		if (typeof fn == 'function') {
			fn.apply(null, [game]);
		} else {
			var elemsArray = game.data('elemsArray');
			//console.log(elemsArray);
			alert('RESUMEN POR DEFECTO: \N'+elemsArray);
		}
	}



	/*for plugin effects personalizations*/
	app.changecontrols = function(){};
	app.changecontrols2 = function(){};


	return app;
});


// CHANGES: 
// 
//	1. Add for plugin effects personalizations:
//		app.changecontrols = function(){};
//		app.changecontrols2 = function(value){};
//	At last plugin last part.
// 	2. Invoice the changecontrols function at functionGame last line
// 	3. Invoice the changecontrols2 function at verifyAnswer last line
//	4. Add class "current_elem", to elem active. Line 436, 500
//	5. Remove class "current_elem", to elem active when this finish the animation. Line 450, 534
