<?php
/**
 * Mu Roulette
 * https://webenginecms.org/
 * 
 * @version 1.1.0
 * @author Lautaro Angelico <http://lautaroangelico.com/>
 * @copyright (c) 2013-2020 Lautaro Angelico, All Rights Reserved
 * @build 205d6fb249c4915c99b765ce1211743c
 */

namespace Plugin\MuRoulette;

class MuRoulette {
	
	private $_configXml = 'config.xml';
	private $_modulesPath = 'modules';
	private $_sqlTable = WE_PREFIX . 'WEBENGINE_ROULETTE_SPINS';
	private $_sqlPath = 'sql';
	private $_tokenSalt = 'WebEngineMuRoulette';
	
	private $_spinTicketCost;
	private $_spinTicketConfigId;
	private $_wcoinConfigId;
	private $_wcoincConfigId;
	private $_wcoinpConfigId;
	private $_goblinpointConfigId;
	private $_ruudConfigId;
	private $_rewardsList;
	private $_characterMaxZen = 2000000000;
	
	private $_userid;
	private $_username;
	private $_character;
	private $_ticketId;
	private $_token;
	private $_limit = 50;
	
	private $_usercpmenu = array(
		array(
			'active' => true,
			'type' => 'internal',
			'phrase' => 'roulette_title',
			'link' => 'roulette/ticket',
			'icon' => 'roulette.png',
			'visibility' => 'user',
			'newtab' => false,
			'order' => 999,
		),
	);
	
	// CONSTRUCTOR
	
	function __construct() {
		
		// load databases
		$this->common = new \common();
		$this->mu = \Connection::Database('MuOnline');
		$this->me = \Connection::Database('Me_MuOnline');
		
		// load configs
		$this->configFilePath = __PATH_ROULETTE_ROOT__.$this->_configXml;
		if(!file_exists($this->configFilePath)) throw new \Exception(lang('roulette_error_2'));
		$xml = simplexml_load_file($this->configFilePath);
		if(!$xml) throw new \Exception(lang('roulette_error_2'));
		
		// set configs
		$this->_spinTicketCost = (int) $xml->spin_ticket_cost;
		$this->_spinTicketConfigId = (int) $xml->spin_ticket_configid;
		$this->_wcoinConfigId = (int) $xml->wcoin_config_id;
		$this->_wcoincConfigId = (int) $xml->wcoinc_config_id;
		$this->_wcoinpConfigId = (int) $xml->wcoinp_config_id;
		$this->_goblinpointConfigId = (int) $xml->goblinpoint_config_id;
		$this->_ruudConfigId = (int) $xml->ruud_config_id;
		$this->_rewardsList = $xml->rewards;
		
		// check credit configs
		if($this->_spinTicketConfigId == 0) throw new \Exception(lang('roulette_error_9'));
		
		// sql file path
		$this->sqlFilePath = __PATH_ROULETTE_ROOT__.$this->_sqlPath.'/';
		
		// check tables
		$this->_checkTable();
	}
	
	// PUBLIC FUNCTIONS
	
	public function loadModule($module) {
		if(!\Validator::Alpha($module)) throw new \Exception(lang('roulette_error_3'));
		if(!$this->_moduleExists($module)) throw new \Exception(lang('roulette_error_3'));
		if(!@include_once(__PATH_ROULETTE_ROOT__ . $this->_modulesPath . '/' . $module . '.php')) throw new \Exception(lang('roulette_error_3'));
	}
	
	public function setUserid($userid) {
		$this->_userid = $userid;
	}
	
	public function setUsername($username) {
		if(!\Validator::UsernameLength($username)) throw new \Exception(lang('roulette_error_4'));
		$this->_username = $username;
	}
	
	public function setCharacter($character) {
		$accountCharacters = $this->getAccountCharacterList();
		if(!in_array($character, $accountCharacters)) throw new \Exception(lang('roulette_error_7'));
		$this->_character = $character;
	}
	
	public function setTicketId($id) {
		if(!\Validator::UnsignedNumber($id)) throw new \Exception(lang('roulette_error_14'));
		$this->_ticketId = $id;
	}
	
	public function setToken($token) {
		$this->_token = $token;
	}
	
	public function setLimit($limit) {
		if(!\Validator::UnsignedNumber($limit)) $this->_limit = 50;
		$this->_limit = $limit;
	}
	
	public function getAccountCharacterList() {
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_5'));
		$Character = new \Character();
		$accountCharacters = $Character->AccountCharacter($this->_username);
		if(!is_array($accountCharacters)) throw new \Exception(lang('roulette_error_6'));
		return $accountCharacters;
	}
	
	public function buyTicket() {
		if(!check_value($this->_userid)) throw new \Exception(lang('roulette_error_8'));
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_8'));
		if(!check_value($this->_character)) throw new \Exception(lang('roulette_error_8'));
		
		// account info
		$Account = new \Account();
		$accountInfo = $Account->accountInformation($this->_userid);
		if(!is_array($accountInfo)) throw new \Exception(lang('roulette_error_10'));
		
		// check credits
		$creditSystem = new \CreditSystem();
		$creditSystem->setConfigId($this->_spinTicketConfigId);
		$configInfo = $creditSystem->showConfigs(true);
		switch($configInfo['config_user_col_id']) {
			case 'userid':
				$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
				break;
			case 'username':
				$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
				break;
			case 'email':
				$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
				break;
			default:
				throw new \Exception(lang('roulette_error_10'));
		}
		
		// check ticket cost
		if($this->_spinTicketCost > $creditSystem->getCredits()) throw new \Exception(lang('roulette_error_11'));
		
		// subtract credits
		$creditSystem->subtractCredits($this->_spinTicketCost);
		
		// create ticket
		$newTicket = $this->_newTicket();
		if(!$newTicket) {
			$creditSystem->addCredits($this->_spinTicketCost);
			throw new \Exception(lang('roulette_error_12'));
		}
		
		// get ticket id
		$ticketInfo = $this->_getNewTicketInfo();
		if(!is_array($ticketInfo)) throw new \Exception(lang('roulette_error_13'));
		
		// redirect
		redirect(1, 'roulette/spin/ticket/'.$ticketInfo['id'].'/');
	}
	
	public function useFreeSpin() {
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_8'));
		if(!check_value($this->_character)) throw new \Exception(lang('roulette_error_8'));
		
		// free spins
		$freeSpins = $this->getUnusedTickets();
		if(!is_array($freeSpins)) throw new \Exception(lang('roulette_error_17'));
		
		// ticket info
		$ticketInfo = $freeSpins[0];
		if(!is_array($ticketInfo)) throw new \Exception(lang('roulette_error_13'));
		
		// set character
		$updateTicket = $this->me->query("UPDATE ".$this->_sqlTable." SET character = ? WHERE id = ?", array($this->_character, $ticketInfo['id']));
		if(!$updateTicket) throw new \Exception(lang('roulette_error_15'));
		
		// redirect
		redirect(1, 'roulette/spin/ticket/'.$ticketInfo['id'].'/');
	}
	
	public function getTicketInfo() {
		if(!check_value($this->_ticketId)) throw new \Exception(lang('roulette_error_13'));
		$ticketInfo = $this->_loadTicketInfo();
		if(!is_array($ticketInfo)) throw new \Exception(lang('roulette_error_13'));
		return $ticketInfo;
	}
	
	public function generateToken() {
		if(!check_value($this->_ticketId)) return;
		if(!check_value($this->_username)) return;
		if(!check_value($this->_character)) return;
		return md5(md5($this->_ticketId).md5($this->_username).md5($this->_character).$this->_tokenSalt);
	}
	
	public function useTicket() {
		if(!check_value($this->_ticketId)) throw new \Exception(lang('roulette_error_13'));
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_13'));
		if(!check_value($this->_character)) throw new \Exception(lang('roulette_error_13'));
		
		// load ticket info
		$ticketInfo = $this->getTicketInfo();
		
		// check ticket
		if($ticketInfo['username'] != $this->_username) throw new \Exception(lang('roulette_error_14'));
		if($ticketInfo['ticket_used'] != 0) throw new \Exception(lang('roulette_error_14'));
		if($ticketInfo['reward_redeem_status'] != 0) throw new \Exception(lang('roulette_error_14'));
		
		// choose reward
		$prizeArray = $this->_generatePrizeArray();
		$randomNumber = $this->_generateRandomNumber();
		$ticketPrize = $prizeArray[$randomNumber];
		if(!check_value($ticketPrize)) throw new \Exception(lang('roulette_error_15'));
		
		// reward list
		$rewardList = $this->_getRewardList();
		if(!is_array($rewardList)) throw new \Exception(lang('roulette_error_15'));
		if(!array_key_exists($ticketPrize, $rewardList)) throw new \Exception(lang('roulette_error_15'));
		
		// set ticket reward
		$setReward = $this->me->query("UPDATE ".$this->_sqlTable." SET reward_type = ?, reward_amount = ?, ticket_used = 1 WHERE id = ?", array($rewardList[$ticketPrize]['type'], $rewardList[$ticketPrize]['amount'], $this->_ticketId));
		if(!$setReward) throw new \Exception(lang('roulette_error_15'));
	}
	
	public function loadApiData() {
		if(!check_value($this->_ticketId)) throw new \Exception('Error');
		if(!check_value($this->_token)) throw new \Exception('Error');
		
		// load ticket info
		$ticketInfo = $this->_loadTicketInfo();
		if(!is_array($ticketInfo)) throw new \Exception('Error');
		
		// check ticket data
		if($ticketInfo['ticket_used'] != 1) throw new \Exception('Error');
		if($ticketInfo['reward_redeem_status'] != 0) throw new \Exception('Error');
		if($ticketInfo['spin_completed'] != 0) throw new \Exception('Error');
		if(!check_value($ticketInfo['reward_type'])) throw new \Exception('Error');
		if(!check_value($ticketInfo['reward_amount'])) throw new \Exception('Error');
		if(check_value($ticketInfo['reward_redeem_date'])) throw new \Exception('Error');
		
		// set ticket data
		$this->setUsername($ticketInfo['username']);
		$this->setCharacter($ticketInfo['character']);
		
		// get ticket token
		$ticketToken = $this->generateToken();
		
		// check token
		if($this->_token != $ticketToken) throw new \Exception('Error');
		
		// get reward index
		$rewardIndex = $this->_getPrizeIdBasedOnRewardTypeAndAmount($ticketInfo['reward_type'], $ticketInfo['reward_amount']);
		
		// load reward list
		$rewardList = $this->_getRewardList();
		foreach($rewardList as $row) {
			$segmentValuesArray[] = array(
				'type' => 'string',
				'value' => $this->_shortNumberFormat($row['amount']) . ' ' . $row['shortname'],
				'win' => true,
				'resultText' => langf('roulette_txt_7', array($row['amount'], $row['name']))
			);
		}
		
		// set spin complete
		$this->_setSpinCompleted();
		
		$result = array (
			'colorArray' => array('#ecac59', '#ec5959'),
			'segmentValuesArray' => $segmentValuesArray,
			'svgWidth' => 1024,
			'svgHeight' => 768,
			'wheelStrokeColor' => '#d28aff',
			'wheelStrokeWidth' => 18,
			'wheelSize' => 600,
			'wheelTextOffsetY' => 80,
			'wheelTextColor' => '#EDEDED',
			'wheelTextSize' => '2.0em',
			'wheelImageOffsetY' => 40,
			'wheelImageSize' => 50,
			'centerCircleSize' => 50,
			'centerCircleStrokeColor' => '#d28aff',
			'centerCircleStrokeWidth' => 12,
			'centerCircleFillColor' => '#9051b8',
			'segmentStrokeColor' => '#ffffff',
			'segmentStrokeWidth' => 4,
			'centerX' => 512,
			'centerY' => 384,
			'hasShadows' => true,
			'numSpins' => 1,
			'spinDestinationArray' => array($rewardIndex),
			'minSpinDuration' => 3,
			'gameOverText' => lang('roulette_txt_8'),
			'invalidSpinText' => 'INVALID SPIN. PLEASE SPIN AGAIN.',
			'introText' => 'SPIN!',
			'hasSound' => true,
			'gameId' => '9a0232ec06bc431114e2a7f3aea03bbe2164f1aa',
			'clickToSpin' => true,
		);
		
		echo json_encode($result);
	}
	
	public function getUnusedTickets() {
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_16'));
		$result = $this->me->query_fetch("SELECT * FROM ".$this->_sqlTable." WHERE username = ? AND Character IS NULL AND ticket_used = 0 AND spin_completed = 0 AND reward_type IS NULL AND reward_amount IS NULL AND reward_redeem_status = 0 ORDER BY ticket_purchase_date ASC", array($this->_username));
		if(!is_array($result)) return;
		return $result;
	}
	
	public function getTicketCost() {
		return $this->_spinTicketCost;
	}
	
	public function getAccountSpinHistory() {
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_4'));
		$results = $this->me->query_fetch("SELECT * FROM ".$this->_sqlTable." WHERE username = ? AND ticket_used = 1 AND spin_completed = 1 ORDER BY spin_date DESC", $this->_username);
		if(!is_array($results)) return;
		return $results;
	}
	
	public function redeemPrize() {
		if(!check_value($this->_ticketId)) throw new \Exception(lang('roulette_error_13'));
		if(!check_value($this->_userid)) throw new \Exception(lang('roulette_error_13'));
		if(!check_value($this->_username)) throw new \Exception(lang('roulette_error_13'));
		
		// load ticket info
		$ticketInfo = $this->getTicketInfo();
		if(!is_array($ticketInfo)) throw new \Exception(lang('roulette_error_13'));
		
		// check ticket data
		if(!check_value($ticketInfo['character'])) throw new \Exception(lang('roulette_error_19'));
		if($ticketInfo['ticket_used'] != 1) throw new \Exception(lang('roulette_error_19'));
		if($ticketInfo['spin_completed'] != 1) throw new \Exception(lang('roulette_error_19'));
		if(!check_value($ticketInfo['spin_date'])) throw new \Exception(lang('roulette_error_19'));
		if(!check_value($ticketInfo['reward_type'])) throw new \Exception(lang('roulette_error_19'));
		if(!check_value($ticketInfo['reward_amount'])) throw new \Exception(lang('roulette_error_19'));
		if($ticketInfo['reward_redeem_status'] != 0) throw new \Exception(lang('roulette_error_19'));
		if($ticketInfo['username'] != $this->_username) throw new \Exception(lang('roulette_error_19'));
		
		// account info
		$Account = new \Account();
		$accountInfo = $Account->accountInformation($this->_userid);
		if(!is_array($accountInfo)) throw new \Exception(lang('roulette_error_10'));
		
		// account online status
		if($Account->accountOnline($this->_username)) throw new \Exception(lang('roulette_error_20'));
		
		// send prize
		switch($ticketInfo['reward_type']) {
			case 'wcoin':
				if($this->_wcoinConfigId == 0) throw new \Exception(lang('roulette_error_9'));
				$creditSystem = new \CreditSystem();
				$creditSystem->setConfigId($this->_wcoinConfigId);
				$configInfo = $creditSystem->showConfigs(true);
				switch($configInfo['config_user_col_id']) {
					case 'userid':
						$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
						break;
					case 'username':
						$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
						break;
					case 'email':
						$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
						break;
					case 'character':
						$creditSystem->setIdentifier($ticketInfo['character']);
						break;
					default:
						throw new \Exception(lang('roulette_error_9'));
				}
				$creditSystem->addCredits($ticketInfo['reward_amount']);
				break;
			case 'wcoinc':
				if($this->_wcoincConfigId == 0) throw new \Exception(lang('roulette_error_9'));
				$creditSystem = new \CreditSystem();
				$creditSystem->setConfigId($this->_wcoincConfigId);
				$configInfo = $creditSystem->showConfigs(true);
				switch($configInfo['config_user_col_id']) {
					case 'userid':
						$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
						break;
					case 'username':
						$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
						break;
					case 'email':
						$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
						break;
					case 'character':
						$creditSystem->setIdentifier($ticketInfo['character']);
						break;
					default:
						throw new \Exception(lang('roulette_error_9'));
				}
				$creditSystem->addCredits($ticketInfo['reward_amount']);
				break;
			case 'wcoinp':
				if($this->_wcoinpConfigId == 0) throw new \Exception(lang('roulette_error_9'));
				$creditSystem = new \CreditSystem();
				$creditSystem->setConfigId($this->_wcoinpConfigId);
				$configInfo = $creditSystem->showConfigs(true);
				switch($configInfo['config_user_col_id']) {
					case 'userid':
						$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
						break;
					case 'username':
						$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
						break;
					case 'email':
						$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
						break;
					case 'character':
						$creditSystem->setIdentifier($ticketInfo['character']);
						break;
					default:
						throw new \Exception(lang('roulette_error_9'));
				}
				$creditSystem->addCredits($ticketInfo['reward_amount']);
				break;
			case 'goblinpoints':
				if($this->_goblinpointConfigId == 0) throw new \Exception(lang('roulette_error_9'));
				$creditSystem = new \CreditSystem();
				$creditSystem->setConfigId($this->_goblinpointConfigId);
				$configInfo = $creditSystem->showConfigs(true);
				switch($configInfo['config_user_col_id']) {
					case 'userid':
						$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
						break;
					case 'username':
						$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
						break;
					case 'email':
						$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
						break;
					case 'character':
						$creditSystem->setIdentifier($ticketInfo['character']);
						break;
					default:
						throw new \Exception(lang('roulette_error_9'));
				}
				$creditSystem->addCredits($ticketInfo['reward_amount']);
				break;
			case 'ruud':
				if($this->_ruudConfigId == 0) throw new \Exception(lang('roulette_error_9'));
				$creditSystem = new \CreditSystem();
				$creditSystem->setConfigId($this->_ruudConfigId);
				$configInfo = $creditSystem->showConfigs(true);
				switch($configInfo['config_user_col_id']) {
					case 'userid':
						$creditSystem->setIdentifier($accountInfo[_CLMN_MEMBID_]);
						break;
					case 'username':
						$creditSystem->setIdentifier($accountInfo[_CLMN_USERNM_]);
						break;
					case 'email':
						$creditSystem->setIdentifier($accountInfo[_CLMN_EMAIL_]);
						break;
					case 'character':
						$creditSystem->setIdentifier($ticketInfo['character']);
						break;
					default:
						throw new \Exception(lang('roulette_error_9'));
				}
				$creditSystem->addCredits($ticketInfo['reward_amount']);
				break;
			case 'zen':
				if(!defined('_CLMN_CHR_ZEN_') || !check_value(_CLMN_CHR_ZEN_)) throw new \Exception(lang('roulette_error_25'));
				$addZen = $this->mu->query("UPDATE "._TBL_CHR_." SET "._CLMN_CHR_ZEN_." = "._CLMN_CHR_ZEN_." + ? WHERE "._CLMN_CHR_NAME_." = ?", array($ticketInfo['reward_amount'], $ticketInfo['character']));
				if(!$addZen) throw new \Exception(lang('roulette_error_22'));
				break;
			case 'resets':
				if(!defined('_CLMN_CHR_RSTS_') || !check_value(_CLMN_CHR_RSTS_)) throw new \Exception(lang('roulette_error_24'));
				$addResets = $this->mu->query("UPDATE "._TBL_CHR_." SET "._CLMN_CHR_RSTS_." = "._CLMN_CHR_RSTS_." + ? WHERE "._CLMN_CHR_NAME_." = ?", array($ticketInfo['reward_amount'], $ticketInfo['character']));
				if(!$addResets) throw new \Exception(lang('roulette_error_22'));
				break;
			case 'freespin':
				for($i=0; $i<$ticketInfo['reward_amount']; $i++) {
					if(!$this->_addFreeSpin()) throw new \Exception(lang('roulette_error_22'));
				}
				break;
			default:
				throw new \Exception(lang('roulette_error_21'));
		}
		
		// update ticket
		$updateTicket = $this->me->query("UPDATE ".$this->_sqlTable." SET reward_redeem_status = 1, reward_redeem_date = CURRENT_TIMESTAMP WHERE id = ?", array($ticketInfo['id']));
		if(!$updateTicket) throw new \Exception(lang('roulette_error_23'));
		
		// redirect
		redirect(1, 'roulette/results/redeem/1');
	}
	
	public function getFullLogs() {
		if($this->_limit == 0) {
			$result = $this->me->query_fetch("SELECT * FROM ".$this->_sqlTable." ORDER BY id DESC");
		} else {
			$result = $this->me->query_fetch("SELECT TOP ".$this->_limit." * FROM ".$this->_sqlTable." ORDER BY id DESC");
		}
		if(!is_array($result)) return;
		return $result;
	}
	
	public function getFullAccountLogs() {
		if(!check_value($this->_username)) return;
		$result = $this->me->query_fetch("SELECT * FROM ".$this->_sqlTable." WHERE username = ? ORDER BY id DESC", array($this->_username));
		if(!is_array($result)) return;
		return $result;
	}
	
	public function getFullUnusedTicketsList() {
		if($this->_limit == 0) {
			$result = $this->me->query_fetch("SELECT * FROM ".$this->_sqlTable." WHERE ticket_used = 0 ORDER BY id DESC");
		} else {
			$result = $this->me->query_fetch("SELECT TOP ".$this->_limit." * FROM ".$this->_sqlTable." WHERE ticket_used = 0 ORDER BY id DESC");
		}
		if(!is_array($result)) return;
		return $result;
	}
	
	public function checkPluginUsercpLinks() {
		if(!is_array($this->_usercpmenu)) return;
		$cfg = loadConfig('usercp');
		if(!is_array($cfg)) return;
		foreach($cfg as $usercpMenu) {
			$usercpLinks[] = $usercpMenu['link'];
		}
		foreach($this->_usercpmenu as $pluginMenuLink) {
			if(in_array($pluginMenuLink['link'],$usercpLinks)) continue;
			$cfg[] = $pluginMenuLink;
		}
		usort($cfg, function($a, $b) {
			return $a['order'] - $b['order'];
		});
		$usercpJson = json_encode($cfg, JSON_PRETTY_PRINT);
		$cfgFile = fopen(__PATH_CONFIGS__.'usercp.json', 'w');
		if(!$cfgFile) throw new \Exception('There was a problem opening the usercp file.');
		fwrite($cfgFile, $usercpJson);
		fclose($cfgFile);
	}
	
	// PROTECTED FUCNTIONS
	
	protected function _newTicket() {
		if(!check_value($this->_username)) return;
		if(!check_value($this->_character)) return;
		
		$newTicket = $this->me->query("INSERT INTO ".$this->_sqlTable." (username, character, ticket_purchase_date) VALUES (?, ?, CURRENT_TIMESTAMP)", array($this->_username, $this->_character));
		if(!$newTicket) return;
		return true;
	}
	
	protected function _getNewTicketInfo() {
		if(!check_value($this->_username)) return;
		if(!check_value($this->_character)) return;
		
		$result = $this->me->query_fetch_single("SELECT * FROM ".$this->_sqlTable." WHERE username = ? AND character = ? AND ticket_used = 0 AND reward_redeem_status = 0", array($this->_username, $this->_character));
		if(!is_array($result)) return;
		return $result;
	}
	
	protected function _loadTicketInfo() {
		if(!check_value($this->_ticketId)) return;
		$result = $this->me->query_fetch_single("SELECT * FROM ".$this->_sqlTable." WHERE id = ?", array($this->_ticketId));
		if(!is_array($result)) return;
		return $result;
	}
	
	protected function _getRewardList() {
		$i = 1;
		foreach($this->_rewardsList->reward as $row) {
			if($i > 10) continue;
			$result[$i] = array(
				'name' => (string) $row->name,
				'shortname' => (string) $row->shortname,
				'type' => (string) $row->type,
				'amount' => (int) $row->amount,
				'chance' => (int) $row->chance,
			);
			$i++;
		}
		if(!is_array($result)) return;
		return $result;
	}
	
	protected function _generatePrizeArray() {
		$rewardList = $this->_getRewardList();
		if(!is_array($rewardList)) return;
		$rewards = array();
		foreach($rewardList as $rewardId => $rewardData) {
			$rewards = array_merge($rewards, array_fill(0, $rewardData['chance'], $rewardId));
		}
		if(!is_array($rewards)) return;
		return $rewards;
	}
	
	protected function _generateRandomNumber() {
		return mt_rand(0,100);
	}
	
	protected function _getPrizeIdBasedOnRewardTypeAndAmount($type, $amount) {
		foreach($this->_getRewardList() as $rewardId => $row) {
			if($row['type'] != $type) continue;
			if($row['amount'] != $amount) continue;
			return $rewardId;
		}
	}
	
	protected function _setSpinCompleted() {
		if(!check_value($this->_ticketId)) return;
		$result = $this->me->query("UPDATE ".$this->_sqlTable." SET spin_completed = 1, spin_date = CURRENT_TIMESTAMP WHERE id = ?", array($this->_ticketId));
		if(!$result) return;
		return true;
	}
	
	protected function _addFreeSpin() {
		if(!check_value($this->_username)) return;
		$result = $this->me->query("INSERT INTO ".$this->_sqlTable." (username, ticket_purchase_date) VALUES (?, CURRENT_TIMESTAMP)", array($this->_username));
		if(!$result) return;
		return true;
	}
	
	protected function _shortNumberFormat($num) {
		if($num>1000) {
			$x = $num;
			$x_number_format = number_format($x);
			$x_array = explode(',', $x_number_format);
			$x_parts = array('k', 'm', 'b', 't');
			$x_count_parts = count($x_array) - 1;
			$x_display = $x;
			$x_display = $x_array[0] . ((int) $x_array[1][0] !== 0 ? '.' . $x_array[1][0] : '');
			$x_display .= $x_parts[$x_count_parts - 1];
			return $x_display;
		}
		return $num;
	}
	
	// PRIVATE FUNCTIONS
	
	private function _moduleExists($module) {
		if(!check_value($module)) return;
		if(!file_exists(__PATH_ROULETTE_ROOT__ . $this->_modulesPath . '/' . $module . '.php')) return;
		return true;
	}
	
	private function _checkTable() {
		$tableExists = $this->me->query_fetch_single("SELECT * FROM sysobjects WHERE xtype = 'U' AND name = ?", array($this->_sqlTable));
		if($tableExists) return true;
		if(!$this->_createTable()) throw new \Exception(lang('roulette_error_27', true));
	}
	
	private function _createTable() {
		if(!file_exists($this->sqlFilePath.'WEBENGINE_ROULETTE_SPINS.txt')) return;
		$query = file_get_contents($this->sqlFilePath.'WEBENGINE_ROULETTE_SPINS.txt');
		if(!check_value($query)) return;
		$queryFinal = str_replace('{TABLE_NAME}', $this->_sqlTable, $query);
		if(!$queryFinal) return;
		if(!$this->me->query($queryFinal)) return;
		return true;
	}
	
}