Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//only do anything if on the blackjack homepage
if (mw.config.get("wgPageName") == "User:コルモラン/blackjack")
{
	//Global state variables
	var currentBalance = 500;
	var currentBetSetting = 10;
	var splitBetValue = 10;
	var playerHand = {count:0,softAce:false,container:"#playerGroup",value:currentBetSetting};
	var dealerHand = {count:0,softAce:false,container:"#cardTableDealer"};
	var splitHand = {count:0,softAce:false,container:"#splitGroup",value:0};
	var previousBalanceExists = true;
	var faceDownCard = null;
	var isSplit = false;
	var splitWinnings = 0;
	var numDecks = 6;
	var shoe = null;
	var nextCard = -1;
	
	function shuffleDeck()
	{
		var rng = window.crypto || window.msCrypto;
		var shoeSize = 52*numDecks;
		var rngArray = new Uint16Array(shoeSize);
		var rejectArray = new Uint16Array(1);
		var maxInt = 65536;
		shoe = new Array(shoeSize);
		for(i = 0; i < shoe.length; i++)
		{
			shoe[i] = i;
		}
		rng.getRandomValues(rngArray);
		for(i=(shoe.length - 1); i >= 0; i--)
		{
			//discard values greater than the maximum multiple of shoeSize below maxInt; these values would skew the distribution
			while(rngArray[i] >= Math.floor(maxInt/shoeSize) * shoeSize)
			{
				rng.getRandomValues(rejectArray);
				rngArray[i] = rejectArray[0];
			}
			var tempStorage = shoe[i];
			shoe[i] = shoe[(rngArray[i]%shoeSize)];
			shoe[(rngArray[i]%shoeSize)] = tempStorage;
			shoeSize--;
		}
		nextCard = 0;
		$("#cardsDealt").width("0%");
		return shoe;
	}
	function changeButton(gameButton, clickFunction, label)
	{
		gameButton.off("click");
		gameButton.click(clickFunction);
		gameButton.find(".mw-ui-button").html(label);
		gameButton.show();
	}
	function changeActionButton(gameButton, clickFunction, gameHand,  label)
	{
		gameButton.off("click");
		gameButton.click({hand:gameHand},clickFunction);
		gameButton.find(".mw-ui-button").html(label);
		gameButton.show();
	}
	
	function changeBet()
	{
		var rawResponse = prompt("ここに賭け金を入力してね! (1 - " + currentBalance + "):");
		if(rawResponse == null)
		{
			return;
		}
		var userResponse = parseInt(rawResponse);
		if (isNaN(userResponse))
		{
			alert("それ数字じゃないから..");
			return;
		}
		if (userResponse > currentBalance)
		{
			alert("そんなにあなたの手元にありませんけど?");
			return;
		}
		if (userResponse < 1)
		{
			alert("寄付じゃあるまいし、1文くらい賭けたら?");
			return;
		}
		currentBetSetting = userResponse;
		playerHand.value = currentBetSetting;
		$("#betAmount").html(currentBetSetting);
	}
	function peaceOut()
	{
		var userResponse = confirm("残高記録のために編集を行います。\n\nよろしいでしょうか?");
		if (userResponse)
		{
			mw.loader.using("mediawiki.api.edit").done(function ()
			{
				var api = new mw.Api();
				if (previousBalanceExists)
				{
					api.edit("User:" + mw.config.get("wgUserName") + "/blackjackBalance.js", function ()
					{
						return {minor:true,text:currentBalance,summary:"[[User:コルモラン/blackjack|ブロックジャック]]の残高を更新"};
					}
					).done(function ()
					{
						location.reload(true);
					}
					);
				}
				else
				{
					api.create("User:" + mw.config.get("wgUserName") + "/blackjackBalance.js",
						{summary: "[[User:コルモラン/blackjack|ブラックジャック]]の残高を更新"},
						"" + currentBalance).done(function ()
					{
						location.reload(true);
					}
					).fail(function ()
					{
						api.edit("User:" + mw.config.get("wgUserName") + "/blackjackBalance.js", function ()
						{
							return {minor:true,text:currentBalance,summary:"[[User:コルモラン/blackjack|ブラックジャック]]の残高を更新"};
						}
						).done(function ()
						{
							location.reload(true);
						}
						);
					}
					);
				}
			}
			);
		}
	}
	function randomCard()
	{
		var cardIndex = shoe[nextCard];
		nextCard++;
		$("#cardsDealt").width("" + ((nextCard/(numDecks*26))*100) + "%");
		return {"suit": ((Math.floor(cardIndex/13)%4)+1),"rank":(cardIndex%13 + 1)};
	}
	function getCardBackground(card)
	{
		var cardBackground = {"x":0,"y":0};
		switch (card.rank)
		{
			case 1:
				cardBackground.x = -1;
				break;
			case 2:
				cardBackground.x = -100;
				break;
			case 3:
				cardBackground.x = -199;
				break;
			case 4:
				cardBackground.x = -298;
				break;
			case 5:
				cardBackground.x = -396;
				break;
			case 6:
				cardBackground.x = -495;
				break;
			case 7:
				cardBackground.x = -593;
				break;
			case 8:
				cardBackground.x = -691;
				break;
			case 9:
				cardBackground.x = -790;
				break;
			case 10:
				cardBackground.x = -888;
				break;
			case 11:
				cardBackground.x = -987;
				break;
			case 12:
				cardBackground.x = -1085;
				break;
			case 13:
				cardBackground.x = -1184;
				break;
			default:
				cardBackground.x = -199;
		}
		
		switch (card.suit)
		{
			case 1:
			case 2:
			case 3:
			case 4:
				cardBackground.y = (-2+-143*(card.suit-1));
				break;
			default:
				cardBackground.y = -574;
		}
		return cardBackground;
	}
	function addToCount(card, currentTotal)
	{
		switch(card.rank)
		{
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
				if(currentTotal.count + card.rank > 21 && currentTotal.softAce == true)
				{
					currentTotal.softAce = false;
					currentTotal.count = currentTotal.count - 10 + card.rank ;
				}
				else currentTotal.count += card.rank ;
				break;
			case 10:
			case 11:
			case 12:
			case 13:
				if(currentTotal.count + 10 > 21 && currentTotal.softAce == true)
				{
					currentTotal.softAce = false;
				}
				else currentTotal.count += 10;
				break;
			case 1:
				if(currentTotal.count + 11 > 21)
				{
					currentTotal.count += 1;
				}
				else
				{
					currentTotal.count += 11;
					currentTotal.softAce = true;
				}
		}
		
	}
	function addCard(card, cardContainer, isFaceDown)
	{
		var newCard = '<div class="cardContainer cardFaceDown newCard"><div class="cardFace"> </div></div>';
		var lastCard = $(cardContainer).children(".cardContainer").last();
		$(cardContainer).append(newCard);
		$("#verticalSpacer").hide();
		newCardDom = $(".newCard");
		newCardDom.removeClass("newCard");
		if(lastCard.length != 0)
		{
			lastCard.removeClass("cardFaceUp");
			lastCard.addClass("cardCovered");
		}
		if(!isFaceDown)
		{
			newCardDom.removeClass("cardFaceDown");
			var coords = getCardBackground(card);
			newCardDom.find(".cardFace").css("background-position", ""+ coords.x + "px " + coords.y + "px");
			newCardDom.addClass("cardFaceUp");
		}
	}
	function dealCard(hand, isFaceDown)
	{
		var nextCard = randomCard();
		addToCount(nextCard, hand);
		addCard(nextCard, hand.container, isFaceDown);
		if(isFaceDown)
		{
			faceDownCard = nextCard;
		}
		return nextCard;
	}
	function flipCard()
	{
		var lastCard = $(".cardFaceDown");
		lastCard.removeClass("cardFaceDown");
		var coords = getCardBackground(faceDownCard);
		lastCard.find(".cardFace").css("background-position", ""+ coords.x + "px " + coords.y + "px");
		lastCard.addClass("cardFaceUp");
	}
	function endHand(isBlackjack)
	{
		isSplit = false;
		$("#splitGroup").removeClass("selectedSplit");
		$("#playerGroup").removeClass("selectedSplit");
		var resultValue = (splitHand.value + playerHand.value)
		currentBalance += resultValue;
		var resultString = "";
		if(isBlackjack)
		{
			resultString = "ブラックジャック! ";
		}
		if(resultValue > 0)
		{
			resultString += "やったね!" + resultValue + "文獲得だよ! ";
		}
		else if(resultValue == 0)
		{
			resultString += "引き分けです。 ";
		}
		else
		{
			resultString += "あなたの負けです。" + Math.abs(resultValue) + "文失いました。 ";
		}
		playerHand.count = 0;
		playerHand.softAce = false;
		dealerHand.count = 0;
		dealerHand.softAce = false;
		splitHand.count = 0
		splitHand.softAce = false;
		playerHand.value = currentBetSetting;
		splitHand.value = 0;
		faceDownCard = null;
		
		if(currentBalance >= 1)
		{
			resultString += "もう一度遊びますか?";
			$("#gameStatus").html(resultString);
			$("#bankAmount").html(currentBalance.toFixed(2));
			if(currentBalance < currentBetSetting)
			{
				currentBetSetting = Math.floor(currentBalance);
				playerHand.value = currentBetSetting;
				$("#betAmount").html(currentBetSetting);
			}
			changeButton($("#gameOption1"), cleanAndDeal, "やる");
			changeButton($("#gameOption2"), changeBet, "賭け金の金額変更");
			changeButton($("#gameOption3"), peaceOut, "やめる");
			$("#gameOption4").hide();
		}
		else
		{
			resultString += "お疲れ様でした。なんで負けたか明日までに考えといてください。";
			$("#gameStatus").html(resultString);
			$("#bankAmount").html(currentBalance.toFixed(2));
			currentBetSetting = 0;
			playerHand.value = currentBetSetting;
			splitHand.value = 0;
			$("#betAmount").html("0");
			changeButton($("#gameOption1"), peaceOut, "やり直す");
			$("#gameOption2").hide();
			$("#gameOption3").hide();
			$("#gameOption4").hide();
		}
	}
	function playDealer()
	{
		flipCard();
		while(dealerHand.count < 17)
		{
			dealCard(dealerHand, false);
		}
		resolveHand(splitHand);
		resolveHand(playerHand);
		endHand(false);
	}
	function resolveHand(hand)
	{
		if(dealerHand.count <= 21 && hand.count > 0 && dealerHand.count > hand.count)
		{
			hand.value = -(hand.value);
		}
		else if(dealerHand.count == hand.count)
		{
			hand.value = 0;
		}
		return hand.value;
	}
	function cleanAndDeal()
	{
		$("#cardTableDealer").html("");
		$("#playerGroup").html("");
		$("#splitGroup").html("");
		$("#splitGroup").hide();
		dealHand();
	}
	function dealHand()
	{
		if(nextCard < 0 || nextCard > 26*numDecks)
		{
			shuffleDeck();
		}
		var firstCard = dealCard(playerHand, false);
		dealCard(dealerHand, false);
		var secondCard = dealCard(playerHand, false);
		dealCard(dealerHand, true);
		if(playerHand.count == 21)
		{
			flipCard();
			if(dealerHand.count == 21)
			{
				playerHand.value = 0;
				endHand(true);
				return;
			}
			playerHand.value = currentBetSetting*3/2;
			endHand(true);
			return;
		}
		if(dealerHand.count == 21)
		{
			flipCard();
			playerHand.value = -(currentBetSetting);
			endHand(false);
			return;
		}
		$("#gameStatus").html("あなたのカードの合計点数は" + playerHand.count + "点です。どうしますか?");
		changeActionButton($("#gameOption1"), hitMe, playerHand, "ヒット");
		changeActionButton($("#gameOption2"), standDown, playerHand, "スタンド");
		if(currentBalance >= 2*currentBetSetting)
		{
			changeActionButton($("#gameOption3"), doubleDown, playerHand, "ダブルダウン");
		}
		else
		{
			$("#gameOption3").hide();
		}
		if(firstCard.rank == secondCard.rank && currentBalance >= 2*currentBetSetting)
		{
			changeButton($("#gameOption4"), splitIt, "スプリット");
		}
		else
		{
			$("#gameOption4").hide();
		}
	}
	function hitMe(e)
	{
		var currentHand;
		if(e.data != null && e.data.hand != null)
		{
			currentHand = e.data.hand;
		}
		else
		{
			currentHand = playerHand;
		}
		dealCard(currentHand, false);
		if(currentHand.count > 21)
		{
			currentHand.value = -(currentBetSetting);
			currentHand.count = 0;
			standDown();
			return;
		}
		else if(currentHand.count == 21)
		{
			standDown();
			return;
		}
		else
		{
			$("#gameOption3").hide();
			$("#gameOption4").hide();
			$("#gameStatus").html("あなたのカードの合計点数は" + currentHand.count + "点です。どうしますか? ");
		}
	}
	function standDown()
	{
		if(playerHand.count == 0 && splitHand.count == 0)
		{
			endHand(false);
			return;
		}
		else if(isSplit)
		{
			isSplit = false;
			$("#splitGroup").removeClass("selectedSplit");
			$("#playerGroup").addClass("selectedSplit");
			changeActionButton($("#gameOption1"), hitMe, playerHand, "Hit");
			changeActionButton($("#gameOption2"), standDown, playerHand, "Stand");
			if(currentBalance >= (2*currentBetSetting + Math.abs(splitBetValue)))
			{
				changeActionButton($("#gameOption3"), doubleDown, playerHand, "Double");
			}
			else
			{
				$("#gameOption3").hide();
			}
			$("#gameStatus").html("あなたの2つ目のカードの合計点数は " + playerHand.count + "点です。どうしますか?");
		}
		else
		{
			playDealer();
		}
	}
	function doubleDown(e)
	{
		var currentHand;
		if(e.data != null && e.data.hand != null)
		{
			currentHand = e.data.hand;
		}
		else
		{
			currentHand = playerHand;
		}
		currentHand.value = currentBetSetting * 2;
		dealCard(currentHand, false);
		if(isSplit && playerHand.count < 21)
		{
			if(currentHand.count > 21)
			{
				currentHand.value = -(currentHand.value);
				currentHand.count = 0;
			}
			standDown();
			return;
		}
		else if(currentHand.count > 21)
		{
			currentHand.count = 0;
			currentHand.value = -(currentHand.value);
			endHand();
			return;
		}
		else
		{
			playDealer();
		}
	}
	function splitIt()
	{
		isSplit = true;
		splitHand.value = currentBetSetting;
		$("#gameOption4").hide();
		var firstCard = $("#playerGroup").find(".cardContainer")[0];
		$(firstCard).appendTo($("#splitGroup"));
		$("#splitGroup").show();
		if(playerHand.softAce)
		{
			splitHand.count = 11;
			splitHand.softAce = true;
			playerHand.count = 11;
			dealCard(splitHand, false);
			dealCard(playerHand, false);
			playDealer();
			return;
		}
		else
		{
			splitHand.count = playerHand.count / 2;
			splitHand.softAce = false;
			playerHand.count = splitHand.count;
			dealCard(splitHand, false);
			dealCard(playerHand, false);
			$("#splitGroup").addClass("selectedSplit");
		}
		changeActionButton($("#gameOption1"), hitMe, splitHand, "ヒット");
		changeActionButton($("#gameOption2"), standDown, splitHand, "スタンド");
		if(currentBalance >= (3*currentBetSetting))
		{
			changeActionButton($("#gameOption3"), doubleDown, splitHand, "ダブルダウン");
		}
		else
		{
			$("#gameOption3").hide();
		}
		$("#gameStatus").html("スプリット!あなたの1番目のカードの合計点数は " + splitHand.count + "点です。どうしますか?");
	}
	function runTheNumbers()
	{
		$("#bankAmount").html(currentBalance.toFixed(2));
		$("#betAmount").html(currentBetSetting);
		$("#gameStatus").html("用意はできていますか?");
		changeButton($("#gameOption1"), dealHand, "やる");
		changeButton($("#gameOption2"), changeBet, "賭け金の金額変更");
		changeButton($("#gameOption3"), peaceOut, "やめる");
		$("#gameOption4").hide();
	}
	function loadSave()
	{
		var loadRequestData =
		{
			"action": "raw",
			"title": "User:" + mw.config.get("wgUserName") + "/blackjackBalance.js"
		};
		$.post("/w/index.php", loadRequestData, function (response)
		{
			var retrievedValue = parseFloat(response);
			if (!(isNaN(retrievedValue)) && retrievedValue >= 1)
			{
				currentBalance = retrievedValue;
				if (Math.floor(currentBalance / 10) < 10)
				{
					currentBetSetting = Math.floor(currentBalance / 10);
					if (currentBetSetting < 1)
					{
						currentBetSetting = 1;
					}
				}
				else
				{
					currentBetSetting = 10;
				}
			}
			else
			{
				alert("お疲れ様でした。文字通り一文無しになっちゃいましたね。ここに500文あるので、なんで負けたか明日までに考えといてください。");
				currentBalance = 500;
				currentBetSetting = 10;
			}
			runTheNumbers();
		}
		).fail(function() 
		{
			alert("見かけない顔ですね。初めてのようですし、500文を贈呈します。");
			currentBalance = 500;
			currentBetSetting = 10;
			previousBalanceExists = false;
			runTheNumbers();
		});
	}
	function prepareBlackjack()
	{
		$("#gameStatus").html("ブラックジャックへようこそ!");
		changeButton($("#gameOption1"), loadSave, "始める");
		$("#splitGroup").hide();
		$("#gameOption2").hide();
		$("#gameOption3").hide();
		$("#gameOption4").hide();
	}
	$(document).ready(prepareBlackjack);
}