//Copyright (C) Ben Parbury - All Rights Reserved. Unauthorized copying of this file, via any medium is strictly prohibited. Written by Ben Parbury <ben@gridlockinteractive.com> 2014

function HubDefinition()
{
	this.levelDefs = new Array();
	this.loadDefTime = 16;
	this.transitionDistance = 0;
	
	gObjectivesOverlay.Disable();
	gScoreOverlay.SetMode(gLevelSystem.IsArcade() ? EOverlayMode.None : EOverlayMode.Completed);
	gCompleteOverlay.Disable();
	
	this.teleportSound = gSounds.Get("teleport");
	this.teleportIn = gSounds.Get("teleportIn");
	
	this.AddLevel = function(set, level, x, y, text)
	{
		var def = new LevelDefinition(set, level, x, y, text);
		if(level.toLowerCase() == "hub")
		{
			var haveRequirement = true;
			var setLowerCase = set.toLowerCase();
			if(IsHubSet(setLowerCase))
			{
				var currentSet = gLevelSystem.GetLevelSet();
				if(IsHubSet(currentSet))
				{
					var currentHubIndex = GetHubIndex(currentSet)
					var hubIndex = GetHubIndex(set.toLowerCase());
					if(currentHubIndex >= hubIndex)
					{
						haveRequirement = false;
					}
				}
				else if(setLowerCase == GetParentHub(currentSet))
				{
					haveRequirement = false;
				}
			}
			
			if(haveRequirement)
			{
				var unlock = gUnlockSystem.Get(set.toLowerCase());
				if (unlock)
				{
					def.unlockProgress = unlock.GetProgress();
					def.unlockRequirement = unlock.GetRequirement();
					def.unlocked = unlock.IsUnlocked();
				}
			}
		}
		this.levelDefs.push(def);
		this.playerHasMoved = false;
	}
	
	this.SetPlayerLocationByPreviousLevel = function()
	{
		var previousSetAnyCase = gLevelSystem.GetPreviouslevelSet();
		var previousLevelAnyCase = gLevelSystem.GetPreviouslevelName();
		if(previousSetAnyCase && previousLevelAnyCase)
		{
			var previousLevel = previousLevelAnyCase.toLowerCase();
			var previousSet = previousSetAnyCase.toLowerCase();
			for(var i = 0; i < this.levelDefs.length; i++)
			{
				var levelDef = this.levelDefs[i];
				if(levelDef.level.toLowerCase() == previousLevel && levelDef.set.toLowerCase() == previousSet)
				{
					gPlayerSystem.GetPlayerAtIndex(0).LoadToPosition(levelDef.x, levelDef.y);
					gConsole.Log(5, "[LVL] Move player to teleport location");
					return;
				}
			}
			for(var i = 0; i < this.levelDefs.length; i++)
			{
				var levelDef = this.levelDefs[i];
				if(levelDef.set.toLowerCase() == previousSet)
				{
					gPlayerSystem.GetPlayerAtIndex(0).LoadToPosition(levelDef.x, levelDef.y);
					gConsole.Log(5, "[LVL] Move player to teleport location based on set");
				}
			}
			
		}
	}
	
	this.Update = function()
	{
		if(this.playerHasMoved)
		{
			for(var i = 0; i < this.levelDefs.length; i++)
			{
				this.UpdateLevelDefinition(this.levelDefs[i])
			}
		}
		else
		{
			this.playerHasMoved = gPlayerSystem.GetPlayerAtIndex(0).IsMoving();
		}
	
	}

	this.Redraw = function()
	{
		for(var i = 0; i < this.levelDefs.length; i++)
		{
			this.levelDefs[i].redraw = true;
		}
	}
	
	this.DrawClear = function()
	{
		for(var i = 0; i < this.levelDefs.length; i++)
		{
			this.DrawClearLevelDefinition(this.levelDefs[i])
		}
	}
	
	this.Draw = function()
	{
		gDraw.hubs.save();
		for(var i = 0; i < this.levelDefs.length; i++)
		{
			this.DrawLevelDefinition(this.levelDefs[i])
		}
		gDraw.hubs.restore();
	}
	
	this.StartTransition = function()
	{
		//Relative to tileSystem distance
		this.transitionDistance = gTileSystem.transitionDistance - 2;
	}
	
	this.DrawTransition = function(fraction)
	{
		this.DrawClear();
		
		gDraw.hubs.save();
		for(var i = 0; i < this.levelDefs.length; i++)
		{
			var def = this.levelDefs[i];
			var dist = distance(gLevelSystem.transitionX, gLevelSystem.transitionY, def.x, def.y);
			if(dist < this.transitionDistance * fraction)
			{
				this.DrawLevelDefinition(def)
			}
		}
		gDraw.hubs.restore();
	}

	
	this.UpdateLevelDefinition = function(def)
	{
		var player = gPlayerSystem.GetPlayerAt(def.x, def.y);
		if(player && !player.IsMoving())
		{
			if(def.unlocked)
			{
				if(def.timer > this.loadDefTime)
				{
					if(!gLevelSystem.loading)
					{
						this.teleportSound.Play();
						if(def.level.toLowerCase() == "hub")
						{
							var level = GetNextLevelOrHub(def.set, def.level);
							gLevelSystem.LoadLevel(def.set, level);
						}
						else
						{
							gLevelSystem.LoadLevel(def.set, def.level);
						}
					}
				}
				else
				{
					var fraction = def.timer/this.loadDefTime;
					player.eyeController.Teleporting(fraction);
					if(!this.teleportIn.IsPlaying())
					{
						this.teleportIn.Play(fraction);
					}
					def.timer++;
				}
			}
		}
		else if(def.timer > 0)
		{
			def.timer--;
			if(this.teleportIn.IsPlaying())
			{
				this.teleportIn.Stop();
			}
		}
	}
	
	this.GetDrawX = function(def)
	{
		return (def.x * kTileSize) + (kTileSizeD2);
	}

	this.GetDrawY = function(def)
	{
		return (def.y * kTileSize) + (kTileSizeD2);
	}

	this.GetDrawInnerRadius = function(def)
	{
		return (kTileSizeD2);
	}
	
	this.GetDrawRadius = function(def)
	{
		return (kTileSize/3) * 2;
	}
	
	this.GetDrawOuterRadius = function(def)
	{
		return (kTileSize/5) * 4;
	}
	
	this.GetDrawTextX = function(def)
	{
		return this.GetDrawX(def);
	}
	
	this.GetDrawTextY = function(def)
	{
		return this.GetDrawY(def) - (this.GetDrawRadius(def) + (kTileSize/4));
	}
	
	this.GetDrawTextYBottom = function(def)
	{
		return this.GetDrawY(def) + (this.GetDrawRadius(def) + (kTileSize/4));
	}
	
	this.GetFontSize = function()
	{
		return 20;
	}

	this.DrawClearLevelDefinition = function(def)
	{
		if(def.redraw)
		{
			var x = (def.x - 1) * kTileSize;
			var y = (def.y - 1) * kTileSize;
			var width = kTileSize * 3;
			var height = kTileSize * 3;
			gDraw.hubs.clearRect(x, y, width, height);
			
			def.redraw = true;
		}
		else if(def.ptimer != def.timer)
		{
			var shadow = 2;
			var tileMaxPadding = kTileSize * 0.08;
			var x = (def.x) * kTileSize - tileMaxPadding;
			var y = (def.y) * kTileSize - tileMaxPadding;
			var width = kTileSize + (tileMaxPadding * 2) + shadow;
			var height = kTileSize + (tileMaxPadding * 2) + shadow;
			gDraw.hubs.clearRect(x, y, width, height);
			
			def.redrawCenter = true;
		}
	}
	
	this.DrawLevelDefinition = function(def)
	{
		if(def.redraw || def.redrawCenter)
		{
			var x = this.GetDrawX(def);
			var y = this.GetDrawY(def);
			var radius = this.GetDrawRadius(def);
			var color = gStyles.baseColor;
			var lowerSet = def.set.toLowerCase();
			if(lowerSet != gLevelSystem.levelSet.toLowerCase())
			{
				var setInfo = gSetManager.Get(lowerSet);
				color = new RGB(setInfo.r, setInfo.g, setInfo.b);
			}
			
			if(!def.unlocked)
			{
				color = new RGBA(0, 0, 0, 0.5);
			}
			
			gDraw.hubs.shadowOffsetX = 1;
			gDraw.hubs.shadowOffsetY = 1;
			gDraw.hubs.shadowBlur = 2;
			gDraw.hubs.shadowColor = "rgb(0, 0, 0)";

			var fraction = def.timer/this.loadDefTime;
			gDraw.hubs.fillStyle = gStyles.targetTileFill.GetLerp(color, 0.3 + (fraction * 0.7)).GetColor();
			gDraw.hubs.beginPath();
			
			var index = IsHubSet(lowerSet) ? gHubs.indexOf(lowerSet) : gHubs.indexOf(GetParentHub(lowerSet));
			switch(index)
			{
				case 0:
					var tilePadding = kTileSize * 0.05;
					gDraw.hubs.rect(def.x * kTileSize - tilePadding, def.y * kTileSize - tilePadding, kTileSize + (2 * tilePadding), kTileSize + (2 * tilePadding));
					break;
				case 1:
					var tilePadding = kTileSize * 0.1;
					gDraw.hubs.arc(def.x * kTileSize + kTileSizeD2, def.y * kTileSize + kTileSizeD2, (kTileSize + tilePadding) * 0.5, 0, Math.PI * 2);
					break;
				case 2:
					var tilePadding = kTileSize * 0.1;
					var centerX = def.x * kTileSize + kTileSizeD2;
					var centerY = def.y * kTileSize + kTileSizeD2;
					var offset = (kTileSize + tilePadding) * 0.5;
					gDraw.hubs.moveTo(centerX - offset, centerY);
					gDraw.hubs.lineTo(centerX, centerY + offset);
					gDraw.hubs.lineTo(centerX + offset, centerY);
					gDraw.hubs.lineTo(centerX, centerY - offset);
					gDraw.hubs.closePath();
					break;
			}
			
			gDraw.hubs.fill();

			if(def.redraw)
			{
				var current = def.unlockProgress;
				var targetRequirement = def.unlockRequirement;
				var requirementsMet = current >= targetRequirement;
				if(requirementsMet && !def.loaded)
				{
					var textX = x - (radius * 1.08);
					var textY = y;
					var textFontSize = GetFontScale(this.GetFontSize() * 0.5);
					
					gDraw.hubs.font	 = GetFont(textFontSize);
					gDraw.hubs.textAlign	 = 'right';
					gDraw.hubs.textBaseline	 = 'middle';
					
					var newText = "New";
					var width = gDraw.hubs.measureText(newText).width;
					var padding = kTileSize * 0.1;
					var height = textFontSize;
					var bgBoxX = textX - width - padding;
					var bgBoxY = textY - (textFontSize * 0.5) - padding;
					
					gDraw.hubs.fillStyle = color.GetColor();
					gDraw.hubs.beginPath();
					gDraw.hubs.fillRoundedRect(bgBoxX, bgBoxY, width + (padding * 2), textFontSize + (padding * 2), 7);
					
					gDraw.hubs.fillStyle = "rgb(255, 255, 255)";
					gDraw.hubs.fillText(newText, textX, textY);
				}
	
				var textx = this.GetDrawTextX(def);
				var texty = this.GetDrawTextY(def);
				var textFontSize = GetFontScale(this.GetFontSize());
	
				gDraw.hubs.font	 = GetFont(textFontSize);
				gDraw.hubs.textAlign	 = 'center';
				gDraw.hubs.textBaseline	 = 'middle';
				gDraw.hubs.fillStyle = "rgb(255, 255, 255)";
				
				var text = def.GetText();
				var width = gDraw.hubs.measureText(text).width;
				var paddingX = kTileSize * 0.2;
				var paddingY = kTileSize * 0.1;
				var height = textFontSize;
				var bgBoxX = textx - (width/2) - paddingX;
				var bgBoxY = texty - (textFontSize * 0.5) - paddingY;
				if(requirementsMet)
				{
					gDraw.hubs.fillStyle = color.GetColor();
					gDraw.hubs.beginPath();
					gDraw.hubs.fillRoundedRect(bgBoxX, bgBoxY, width + (paddingX * 2), textFontSize + (paddingY * 2), 7);
					gDraw.hubs.fillStyle = "rgb(255, 255, 255)";
					gDraw.hubs.fillText(text, textx, texty);
					def.textWidth = gDraw.hubs.measureText(text).width;
				}
				
				if(def.level.toLowerCase() == "hub")
				{
					if(!def.unlocked || !IsHubSet(lowerSet))
					{
						var starRadius = kTileSize * 0.2;
						var underText = def.unlocked ? gStatsSystem.GetStarsForSet(lowerSet) + " of " + (gStatsSystem.GetCountForSet(lowerSet) * gRulesSystem.kStarCount) : "" + def.unlockRequirement + "";
						var textbottomy = this.GetDrawTextYBottom(def);
						var textWidth = gDraw.hubs.measureText(underText).width
						width = textWidth + (starRadius * 2);
						bgBoxX = textx - (width/2) - paddingX;
						bgBoxY = textbottomy - (textFontSize * 0.5) - paddingY;
						
						gDraw.hubs.fillStyle = color.GetColor();
						gDraw.hubs.beginPath();
						gDraw.hubs.fillRoundedRect(bgBoxX, bgBoxY, width + (paddingX * 2), textFontSize + (paddingY * 2), 7);
						textx -= starRadius * 0.67;
						gDraw.hubs.fillStyle = "rgb(255, 255, 255)";
						gDraw.hubs.fillText(underText, textx, textbottomy);
						gDraw.hubs.fillStar(textx + textWidth/2 + starRadius, textbottomy, starRadius)
					}
				}
				else if(def.stars > 0)
				{
					var width = gRulesSystem.kStarCount * kTileSize * 0.5;
					var height = kTileSize * 0.35;
					var padding = kTileSize * 0.1;
					var bgBoxX = x - (width/2) - padding;
					var bgBoxY = y + kTileSize * 0.88 - (height/2) - padding;
					gDraw.hubs.fillStyle = color.GetColor();
					gDraw.hubs.beginPath();
					gDraw.hubs.fillRoundedRect(bgBoxX, bgBoxY, width + (padding * 2), height + (padding * 2), 7);
	
					for(var i = 1; i <= gRulesSystem.kStarCount; i++)
					{
						this.DrawStar(def, x, y, "rgb(255, 255, 255)", i)
					}
					if(def.better)
					{
						for(var i = 1; i <= gRulesSystem.kStarCount; i++)
						{
							this.DrawStar(def, x, y, "rgb(255, 255, 255)", i, true)
						}
					}
				}
				
			}
			def.ptimer = def.timer;
			def.redraw = false;
			def.redrawCenter = false;
		}
	}
	
	this.DrawStar = function(def, x, y, color, index, better)
	{
		var starRadius = kTileSize * 0.25;
		gDraw.hubs.strokeStyle = color;
		gDraw.hubs.fillStyle = color;
		gDraw.hubs.lineWidth = 1;
		var drawX = x + ((index - 2) * (kTileSize * 0.5));
		var drawY = y + kTileSize * 0.88;
		gDraw.hubs.Star(drawX, drawY, better ? kTileSize * 0.25 : kTileSize * 0.2);
		
		if(index <= def.stars && !better)
		{
			gDraw.hubs.fill();
		}
		else
		{
			gDraw.hubs.stroke();
		}
	}
}

function LevelDefinition(set, level, x, y, text)
{
	this.GetStars = function()
	{
		if(this.level.toLowerCase() == "hub")
		{
			if(this.set.toLowerCase() == "hub")
			{
				var minStars = gRulesSystem.kStarCount;
				for(set in gLevelsBySet)
				{
					var stars = gStatsSystem.GetMinStarsForSet(set.toLowerCase())
					if(stars == 0)
					{
						return 0;
					}
					else
					{
						minStars = Math.min(minStars, stars);
					}
				}
				
				return minStars;
			}
			else
			{
				return gStatsSystem.GetMinStarsForSet(this.set.toLowerCase());
			}
		}
		else
		{
			var stars = gStorage.getItem(this.set, this.level, "stars")
			if(stars)
			{
				return parseInt(stars);
			}
		}
		
		return 0;
	}
	
	this.GetBetter = function()
	{
		if(this.level.toLowerCase() != "hub")
		{
			var better = gStorage.getItem(this.set, this.level, "better")
			if(better)
			{
				return true;
			}
		}
		
		return false;
	}
	
	this.set = set;
	this.level = level;
	this.x = x;
	this.y = y;
	this.text = text;
	this.redraw = true;
	this.redrawCenter = true;
	this.textWidth = 0;
	this.unlockRequirement = null;
	this.unlockProgress = null;
	this.unlocked = true;
	
	this.loaded = gStorage.getItem(set, level, "loaded");
	this.stars = this.GetStars();
	this.better = this.GetBetter();
	
	this.timer = 0;
	this.ptimer = 0;

	this.GetText = function()
	{
		if(this.text)
		{
			return Localized(this.text);
		}
		else if(this.level.toLowerCase() == gLevelSystem.GetLevelName().toLowerCase())
		{
			return Localized(this.set);
		}
		else
		{
			return Localized(this.level);
		}
	}
}