"use strict";
this.name = "hoopy_holdem";
this.author = "spara";
this.copyright = "2014 spara";
this.license = "CC BY-NC-SA 4.0";

this.$highNames = expandMissionText("hoopy-holdem-highnames").split("|");
this.$handRanks = expandMissionText("hoopy-holdem-handranks").split("|");

//init a new deck
this.$virginDeck = function () {
	var deck = new Array();
	var suits = ["triangle", "crescent", "square", "star"];
	for (var i = 0; i < 4; i++) {
		for (var j = 1; j < 14; j++) {
			var card = new Object();
			card.suit = suits[i];
			card.rank = j;
			card.show = false;
			deck.push(card);
		}
	}
	return deck;
}

//draws a card from the current deck in play
this.$drawCard = function () {
	return this.$playDeck.splice(Math.floor(this.$playDeck.length * Math.random()), 1)[0];
}

this.$intro = function () {
	var credits = expandMissionText("hoopy-credits", { amount: formatCredits(player.credits, true, true) });
	var options = {};
	options["1_EXIT"] = expandMissionText("hoopy-exit");
	if (player.credits >= 30)
		options["2_10"] = expandMissionText("hoopy-casino-bet", { amount: formatCredits(10, true, true) });
	else credits += expandMissionText("hoopy-no-credit");
	if (player.credits >= 150)
		options["3_50"] = expandMissionText("hoopy-casino-bet", { amount: formatCredits(50, true, true) });
	if (player.credits >= 300)
		options["4_100"] = expandMissionText("hoopy-casino-bet", { amount: formatCredits(100, true, true) });

	mission.runScreen({
		screenID: "hoopy_casino",
		title: expandMissionText("hoopy-holdem-title", {name: worldScripts.hoopy_populator._hoopyName}),
		message: expandMissionText("hoopy-holdem-intro-story") + credits,
		model: "hoopy_casino_holdem_intro",
		background: { name: "hoopy_table_bg2.png", height: 546 },
		choices: options,
		allowInterrupt: true,
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
		function (choice) {
			if (choice === "2_10") this.$play(10);
			else if (choice === "3_50") this.$play(50);
			else if (choice === "4_100") this.$play(100);
			else if (choice == "1_EXIT") worldScripts.hoopy_populator.$displayMenu();
			return;
		}.bind(this)
	);
}

//first pay, then deal
this.$play = function (bet) {
	player.credits -= bet;
	this.$ante = bet;
	this.$bets = 0;
	this.$playDeck = this.$virginDeck();
	this.$cards = new Array();
	for (var i = 0; i < 9; i++) this.$cards.push(this.$drawCard());
	this.$deal("deal");
}

this.$deal = function (phase) {
	var message = expandMissionText("hoopy-holdem-ante", { amount: formatCredits(this.$ante, true, true) });
	if (this.$bets > 0)
		message += expandMissionText("hoopy-holdem-bets", { amount: formatCredits(this.$bets, true, true) });
	message += "\n" + expandMissionText("hoopy-credits", { amount: formatCredits(player.credits, true, true) });
	var options = {};
	switch (phase) {
		case "deal": this.$cards[7].show = true;
			this.$cards[8].show = true;
			options["1_FLOP"] = expandMissionText("hoopy-holdem-play", { amount: formatCredits(this.$ante * 2, true, true) });
			options["2_FOLD"] = expandMissionText("hoopy-fold");
			break;
		case "flop": this.$cards[2].show = true;
			this.$cards[3].show = true;
			this.$cards[4].show = true;
			options["3_CHECK_TURN"] = expandMissionText("hoopy-check");
			if (player.credits >= this.$ante)
				options["4_BET_TURN"] = expandMissionText("hoopy-holdem-bet", { amount: formatCredits(this.$ante, true, true) });
			break;
		case "turn": this.$cards[5].show = true;
			options["5_CHECK_RIVER"] = expandMissionText("hoopy-check");
			if (player.credits >= this.$ante)
				options["6_BET_RIVER"] = expandMissionText("hoopy-holdem-bet", { amount: formatCredits(this.$ante, true, true) });
			break;
	};
	mission.runScreen({
		screenID: "hoopy_casino",
		titleKey: "hoopy-holdem-title",
		model: "hoopy_casino_holdem_base",
		message: message,
		background: { name: "hoopy_table_bg2.png", height: 546 },
		spinModel: false,
		choices: options
	},
		function (choice) {
			switch (choice) {
				case "1_FLOP": player.credits -= 2 * this.$ante;
					this.$bets += 2 * this.$ante;
					this.$deal("flop");
					return;
				case "2_FOLD": this.$showDown(true);
					return;
				case "3_CHECK_TURN": this.$deal("turn");
					return;
				case "4_BET_TURN": player.credits -= this.$ante;
					this.$bets += this.$ante;
					this.$deal("turn");
					return;
				case "5_CHECK_RIVER": this.$showDown(false);
					return;
				case "6_BET_RIVER": player.credits -= this.$ante;
					this.$bets += this.$ante;
					this.$showDown(false);
					return;
			}
		}.bind(this)
	);
	this.$updateCards();
}

this.$handName = function (value, high) {
	if (value > 0)
		return this.$handRanks[value];
	else
		return this.$highNames[high - 7] + " " + this.$handRanks[0];
}

this.$formatHand = function (hand) {
	var formatted = "(";
	for (var i = 0; i < 5; i++) {
		var value = hand[0][i].value;
		if (value === 11) value = expandMissionText("hoopy-casino-jack");
		else if (value === 12) value = expandMissionText("hoopy-casino-queen");
		else if (value === 13) value = expandMissionText("hoopy-casino-king");
		else if (value === 14 || value === 1) value = expandMissionText("hoopy-casino-ace");
		formatted += value;
		if (i < 4) formatted += ", ";
		else formatted += ")";
	}
	return formatted;
}

this.$showDown = function (fold) {
	for (var i = 0; i < 9; i++) this.$cards[i].show = true;
	var playerHand = this.$bestHand(2);
	var dealerHand = this.$bestHand(0);
	var playerValues = "\n" + this.$formatHand(playerHand) + "\n\n";
	var dealerValues = "\n" + this.$formatHand(dealerHand) + "\n\n";
	var message = expandMissionText("hoopy-holdem-player", { hand: this.$handName(playerHand[1], playerHand[0][0].value) + playerValues });
	message += expandMissionText("hoopy-holdem-dealer", { hand: this.$handName(dealerHand[1], dealerHand[0][0].value) + dealerValues });

	if (fold) var result = "fold";
	else {
		var result = "push";
		if (dealerHand[1] > playerHand[1])
			result = "loss";
		else if (dealerHand[1] < playerHand[1]) {
			result = "win";
		} else {
			for (var i = 0; i < 5; i++) {
				if (playerHand[0][i].value > dealerHand[0][i].value) {
					result = "win";
					break;
				} else if (playerHand[0][i].value < dealerHand[0][i].value) {
					result = "loss";
					break;
				}
			}
		}
	}
	switch (result) {
		case "win": if (playerHand[1] > 3)
			var win = 2 * (this.$bets + this.$ante);
		else var win = this.$ante + 2 * (this.$bets);
			message += expandMissionText("hoopy-holdem-win", { amount: formatCredits(win - this.$bets - this.$ante, true, true) });
			player.credits += win;
			break;
		case "loss": message += expandMissionText("hoopy-holdem-dealerwin", { amount: formatCredits(this.$bets + this.$ante, true, true) });
			break;
		case "push": message += expandMissionText("hoopy-holdem-push");
			player.credits += this.$bets + this.$ante;
			break;
		case "fold": message += expandMissionText("hoopy-holdem-fold", { amount: formatCredits(this.$ante, true, true) });
			break;
	}
	message += "\n" + expandMissionText("hoopy-credits", { amount: formatCredits(player.credits, true, true) });
	var options = {};
	if (player.credits >= 3 * this.$ante)
		options["7_DEAL"] = expandMissionText("hoopy-dealagain", { amount: formatCredits(this.$ante, true, true) });
	options["8_BET"] = expandMissionText("hoopy-holdem-changeante");
	options["9_EXIT"] = expandMissionText("hoopy-exit");
	mission.runScreen({
		screenID: "hoopy_casino",
		titleKey: "hoopy-holdem-title",
		model: "hoopy_casino_holdem_base",
		message: message,
		background: { name: "hoopy_table_bg2.png", height: 546 },
		spinModel: false,
		choices: options,
		allowInterrupt: true,
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
		function (choice) {
			switch (choice) {
				case "7_DEAL": 
					this.$play(this.$ante);
					return;
				case "8_BET": 
					this.$intro(1);
					return;
				case "9_EXIT": 
					worldScripts.hoopy_populator.$displayMenu();
					return;
			};
		}.bind(this)
	);
	this.$updateCards();
}

this.$updateCards = function () {
	for (var i = 0; i < 9; i++) {
		var card = this.$cards[i];
		if (card.show)
			var fileName = "hoopy_card_" + card.suit + "_" + card.rank + ".png";
		else var fileName = "casino_holdem_card_diffuse.png";
		mission.displayModel.subEntities[i].setMaterials({ "casino_poker_card_diffuse.png": { diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor" } });
	}
}

this.$bestHand = function (start) {

	//make a new hand with new objects
	var hand = new Array();
	for (var i = start; i < start + 7; i++) {
		var suits = ["triangle", "crescent", "square", "star"];
		var card = new Object();
		card.value = this.$cards[i].rank;
		card.suit = suits.indexOf(this.$cards[i].suit);
		if (card.value === 1) card.value = 14;
		hand.push(card);
	}

	//order cards by suit
	hand.sort(function (a, b) { return a.suit - b.suit });

	//handle flushes first	
	if (hand[0].suit === hand[4].suit || hand[1].suit === hand[5].suit || hand[2].suit === hand[6].suit) {
		//suit of flush
		var suit = hand[2].suit;
		//remove wrong suit cards
		for (var i = 0; i < 7; i++) {
			if (hand[6 - i].suit !== suit)
				hand.splice(6 - i, 1);
		}
		//order cards by value
		hand.sort(function (a, b) { return b.value - a.value })
		//handle possible ace by duplicating to a different value
		if (hand[0].value === 14) {
			card = new Object();
			card.value = 1;
			card.suit = suit;
			hand.push(card);
		}
		//look for a straight
		var straight = -1;
		var length = 0;
		for (var i = 0; i < hand.length - 1; i++) {
			//tracking a straight
			if (hand[i].value - hand[i + 1].value === 1) length++;
			else if (hand[i].value - hand[i + 1].value != 0) length = 0;
			if (length === 4) {
				//highest straight starts from index i - 3
				straight = i - 3;
				break;
			}
		}
		//straight flush found
		if (straight > -1) {
			hand = hand.splice(straight, 5);
			//royal flush
			if (hand[0].value === 14)
				return [hand, 9];
			//straight flush
			else return [hand, 8];
		}
		//a plain flush found
		else {
			//take five most valuable cards
			hand = hand.splice(0, 5);
			return [hand, 5];
		}
	}

	//order cards by value
	hand.sort(function (a, b) { return b.value - a.value });

	//handle possible ace by duplicating to a different value
	if (hand[0].value === 14) {
		card = new Object();
		card.value = 1;
		card.suit = hand[0].suit;
		hand.push(card);
	}

	//look for a straight
	var straight = -1;
	var length = 0;
	for (var i = 0; i < hand.length - 1; i++) {
		//tracking a straight
		if (hand[i].value - hand[i + 1].value === 1) length++;
		else if (hand[i].value - hand[i + 1].value != 0) length = 0;
		if (length === 4) {
			//highest straight starts from index i - 3
			straight = i - 3;
			break;
		}
	}

	//straight found
	if (straight > -1) {
		hand = hand.splice(straight, 5);
		return [hand, 4];
	}

	//remove possible added ace. this was needed for straight search
	if (hand[0].value === 14)
		hand.pop();

	//make a new array of the cards so that cards with the same value are grouped ot sub arrays
	var grouped = new Array();
	grouped.push([hand[0]]);
	for (var i = 1; i < hand.length; i++) {
		//if there is a group for this card value, then push the card into it.
		if (hand[i].value === grouped[grouped.length - 1][0].value)
			grouped[grouped.length - 1].push(hand[i]);
		//otherwise create a new group
		else grouped.push([hand[i]]);
	}

	//sort grouped cards by group size
	grouped.sort(function (a, b) { return b.length - a.length });

	//four of a kind
	if (grouped[0].length === 4) {
		var newHand = grouped[0];
		var kicker = grouped[1][0];
		for (var i = 2; i < grouped.length; i++) {
			if (grouped[i][0] > kicker) kicker = grouped[i][0];
		}
		newHand.push(kicker);
		return [newHand, 7];
	}

	//three of a kind or full house
	if (grouped[0].length === 3) {
		var newHand = grouped[0];
		//full house
		if (grouped[1].length > 1) {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[1][1]);
			return [newHand, 6];
		}
		//three of a kind
		else {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[2][0]);
			return [newHand, 3];
		}
	}

	//pair or two pair
	if (grouped[0].length === 2) {
		var newHand = grouped[0];
		//two pair
		if (grouped[1].length > 1) {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[1][1]);
			newHand.push(grouped[2][0]);
			return [newHand, 2];
		}
		//pair
		else {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[2][0]);
			newHand.push(grouped[3][0]);
			return [newHand, 1];
		}
	}

	hand = hand.splice(0, 5);
	return [hand, 0];
}
