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

this.payoffHands = expandMissionText("hoopy-poker-payoff").split("|");;
this.payoffTable = [
	[10, 20, 30, 40, 60, 90, 250, 500, 2500],
	[20, 40, 60, 80, 120, 180, 500, 1000, 5000],
	[30, 60, 90, 120, 180, 270, 750, 1500, 7500],
	[40, 80, 120, 160, 240, 360, 1000, 2000, 10000],
	[50, 100, 150, 200, 300, 450, 1250, 2500, 40000]
];

//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.hold = 0;
			deck.push(card);
		}
	}
	return deck;
}

//helper function for tabulating text on screen
this.$tabulate = function (line, width) {
	var hairSpace = String.fromCharCode(31);
	var space = defaultFont.measureString(" ");
	while (defaultFont.measureString(line) < width - space)
		line += " ";
	while (defaultFont.measureString(line) < width)
		line += hairSpace;
	return line;
}

//intro screen
this.$intro = function () {
	//build and format the payoff table for screen
	var payoffMessage = this.$tabulate("Hand", 10);
	for (var i = 0; i < 5; i++) {
		payoffMessage += formatCredits(10 * (i + 1), true, true);
		payoffMessage = this.$tabulate(payoffMessage, 10 + 4 * (i + 1));
	}
	payoffMessage = "\n\n" + payoffMessage + "\n\n";
	for (i = 0; i < this.payoffHands.length; i++) {
		var line = this.payoffHands[this.payoffHands.length - i - 1];
		line = this.$tabulate(line, 10);
		for (var j = 0; j < 5; j++) {
			line = this.$tabulate(line, 10 + 4 * j);
			line += this.payoffTable[j][this.payoffHands.length - i - 1];
		}
		payoffMessage += line + "\n";
	}

	//format player credits for screen
	var credits = expandMissionText("hoopy-credits", { amount: formatCredits(player.credits, true, true) });

	//gambling choices
	var options = {
		"1_EXIT": expandMissionText("hoopy-exit")
	};
	if (player.credits >= 10) {
		options["2_10"] = formatCredits(10, true, true);
	}
	else credits += expandMissionText("hoopy-no-credit");
	if (player.credits >= 20)
		options["3_20"] = formatCredits(20, true, true);
	if (player.credits >= 30)
		options["4_30"] = formatCredits(30, true, true);
	if (player.credits >= 40)
		options["5_40"] = formatCredits(40, true, true);
	if (player.credits >= 50)
		options["6_50"] = formatCredits(50, true, true);


	mission.runScreen({
		screenID: "hoopy_casino",
		titleKey: "hoopy-poker-title",
		message: expandMissionText("hoopy-poker-intro-story") + payoffMessage + credits,
		model: "hoopy_casino_poker_card_spin",
		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_20") this.$play(20);
			else if (choice === "4_30") this.$play(30);
			else if (choice === "5_40") this.$play(40);
			else if (choice === "6_50") this.$play(50);
			else if (choice == "1_EXIT") worldScripts.hoopy_populator.$displayMenu();
		}.bind(this)
	);
}

//first pay, then deal
this.$play = function (bet) {
	player.credits -= bet;
	//init a new deck and draw a hand (don't show it yet)
	this.$playDeck = this.$virginDeck();
	var hand = new Array();
	for (var i = 0; i < 5; i++) hand.push(this.$drawCard());
	this.$deal(bet, hand);
}

//Deal
this.$deal = function (bet, hand, choice) {
	if (typeof choice === undefined) var choice = "0_HOLD";
	var options = {
		"0_HOLD": expandMissionText("hoopy-poker-hold1"),
		"1_HOLD": expandMissionText("hoopy-poker-hold2"),
		"2_HOLD": expandMissionText("hoopy-poker-hold3"),
		"3_HOLD": expandMissionText("hoopy-poker-hold4"),
		"4_HOLD": expandMissionText("hoopy-poker-hold5"),
		"5_DEAL": expandMissionText("hoopy-poker-draw")
	}
	mission.runScreen({
		screenID: "hoopy_casino",
		titleKey: "hoopy-poker-title",
		messageKey: "hoopy-poker-deal-story",
		model: "hoopy_casino_poker_card_base",
		background: { name: "hoopy_table_bg2.png", height: 546 },
		spinModel: false,
		choices: options,
		initialChoicesKey: choice
	},
		function (choice) {
			if (choice === "0_HOLD")
				hand[0].hold = (hand[0].hold + 1) % 2;
			else if (choice === "1_HOLD")
				hand[1].hold = (hand[1].hold + 1) % 2;
			else if (choice === "2_HOLD")
				hand[2].hold = (hand[2].hold + 1) % 2;
			else if (choice === "3_HOLD")
				hand[3].hold = (hand[3].hold + 1) % 2;
			else if (choice === "4_HOLD")
				hand[4].hold = (hand[4].hold + 1) % 2;
			else if (choice === "5_DEAL") {
				this.$outCome(bet, hand);
				return;
			}
			this.$deal(bet, hand, choice);
			return;
		}.bind(this)
	);
	//update the cards on screen
	for (var i = 0; i < 5; i++)
		this.$changeCard(i, hand[i]);
}

//draw && outcome
this.$outCome = function (bet, hand) {
	//draw new cards
	for (var i = 0; i < 5; i++) {
		if (!hand[i].hold)
			hand[i] = this.$drawCard();
		else hand[i].hold = 0;
	}
	//check for wins
	var result = this.winCheck(hand);
	//fail
	if (result === -1) {
		var sound = "hoopy_lose.ogg";
		var resultText = expandMissionText("hoopy-poker-fail");
	}
	//win
	else {
		var win = this.payoffTable[(bet / 10 - 1)][result];
		var resultText = expandMissionText("hoopy-poker-win", { result: this.payoffHands[result], amount: formatCredits(win, false, true) });
		player.credits += win;
		var sound = "hoopy_win.ogg";
	}
	//format player credits for screen
	var credits = "\n" + expandMissionText("hoopy-credits", { amount: formatCredits(player.credits, true, true) }) + "\n" + expandMissionText("hoopy-casino-bet", { amount: formatCredits(bet, true, true) });
	var options = {
		"1_EXIT": expandMissionText("hoopy-exit"),
		"2_AGAIN": expandMissionText("hoopy-poker-changebet"),
	};
	if (player.credits >= bet) options["3_DEAL"] = expandMissionText("hoopy-poker-dealagain");
	mission.runScreen({
		screenID: "hoopy_casino",
		titleKey: "hoopy-poker-title",
		message: resultText + credits,
		model: "hoopy_casino_poker_card_base",
		background: { name: "hoopy_table_bg2.png", height: 546 },
		spinModel: false,
		choices: options,
		music: sound,
		allowInterrupt: true,
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
		function (choice) {
			if (choice === "2_AGAIN") {
				this.$intro();
				return;
			} else if (choice === "3_DEAL") {
				this.$play(bet);
				return;
			} else if (choice == "1_EXIT") {
				worldScripts.hoopy_populator.$displayMenu();
				return;
			}
		}.bind(this)
	)
	//update the cards on screen
	for (var i = 0; i < 5; i++)
		this.$changeCard(i, hand[i]);
}

//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];
}

//update the texture and position for a card
this.$changeCard = function (place, card) {
	var fileName = "hoopy_card_" + card.suit + "_" + card.rank + ".png";
	mission.displayModel.subEntities[place].setMaterials({ "casino_poker_card_diffuse.png": { diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor" } });
	if (card.hold) {
		var position = mission.displayModel.subEntities[place].position;
		position[2] = 3;
		mission.displayModel.subEntities[place].position = position;
	}
}

//rules for a winning hand
this.winCheck = function (hand) {
	//work with a hand that has been ordered by rank
	var orderedHand = hand.concat();
	orderedHand.sort(function (a, b) { return a.rank - b.rank });

	//check for flush
	var suit = orderedHand[0].suit;
	var i = 0;
	var flush = false;
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].suit !== suit) {
			i = -1;
			break;
		}
	}
	//flush found
	if (i !== -1) flush = true;

	//check for straight
	var prevRank = orderedHand[0].rank;
	var straight = false
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].rank - prevRank !== 1 && (i !== 1 || orderedHand[i].rank !== 10 || prevRank !== 1)) {
			i = -1;
			break;
		}
		prevRank = orderedHand[i].rank;
	}

	//straight found
	if (i !== -1) straight = true;

	//straight flush
	if (flush && straight) {
		if (orderedHand[0].rank === 1 && orderedHand[4].rank === 13)
			return 8;//royal_flush
		else return 7;//straight_flush
	}

	//flush 
	if (flush) return 4;//flush"

	//straight
	if (straight) return 3;//straight

	//in the ordered list, for every adjacent two cards, check if they form a rank pair.
	prevRank = orderedHand[0].rank;
	var pairs = new Array();
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].rank === prevRank) pairs.push(i);
		prevRank = orderedHand[i].rank;
	}

	//four of a kind (3 adjacent pairs)
	//full house (3 adjacent pairs)
	if (pairs.length === 3) {
		if (orderedHand[1].rank === orderedHand[2].rank && orderedHand[2].rank === orderedHand[3].rank)
			return 6;//four_of_a_kind
		else return 5;//full_house
	}

	//three of a kind (2 adjacent pairs)
	//two pair (2 adjacent pairs)
	if (pairs.length === 2) {
		if (pairs[1] - pairs[0] === 1)
			return 2;//three_of_a_kind
		else return 1;//two pair
	}

	//pair (jacks or better)
	if (pairs.length === 1) {
		if (orderedHand[pairs[0]].rank > 10 || orderedHand[pairs[0]].rank === 1)
			return 0;
	}

	return -1;
}
