pragma solidity ^0.4.24;

/**
 * @title LotteryInterface
 */
interface LotteryInterface {
	function claimReward(address playerAddress, uint256 tokenAmount) external returns (bool);
	function calculateLotteryContributionPercentage() external constant returns (uint256);
	function getNumLottery() external constant returns (uint256);
	function isActive() external constant returns (bool);
	function getCurrentTicketMultiplierHonor() external constant returns (uint256);
	function getCurrentLotteryTargetBalance() external constant returns (uint256, uint256);
}


/**
 * @title SettingInterface
 */
interface SettingInterface {
	function uintSettings(bytes32 name) external constant returns (uint256);
	function boolSettings(bytes32 name) external constant returns (bool);
	function isActive() external constant returns (bool);
	function canBet(uint256 rewardValue, uint256 betValue, uint256 playerNumber, uint256 houseEdge) external constant returns (bool);
	function isExchangeAllowed(address playerAddress, uint256 tokenAmount) external constant returns (bool);

	/******************************************/
	/*          SPINWIN ONLY METHODS          */
	/******************************************/
	function spinwinSetUintSetting(bytes32 name, uint256 value) external;
	function spinwinIncrementUintSetting(bytes32 name) external;
	function spinwinSetBoolSetting(bytes32 name, bool value) external;
	function spinwinAddFunds(uint256 amount) external;
	function spinwinUpdateTokenToWeiExchangeRate() external;
	function spinwinRollDice(uint256 betValue) external;
	function spinwinUpdateWinMetric(uint256 playerProfit) external;
	function spinwinUpdateLoseMetric(uint256 betValue, uint256 tokenRewardValue) external;
	function spinwinUpdateLotteryContributionMetric(uint256 lotteryContribution) external;
	function spinwinUpdateExchangeMetric(uint256 exchangeAmount) external;

	/******************************************/
	/*      SPINLOTTERY ONLY METHODS          */
	/******************************************/
	function spinlotterySetUintSetting(bytes32 name, uint256 value) external;
	function spinlotteryIncrementUintSetting(bytes32 name) external;
	function spinlotterySetBoolSetting(bytes32 name, bool value) external;
	function spinlotteryUpdateTokenToWeiExchangeRate() external;
	function spinlotterySetMinBankroll(uint256 _minBankroll) external returns (bool);
}


/**
 * @title TokenInterface
 */
interface TokenInterface {
	function getTotalSupply() external constant returns (uint256);
	function getBalanceOf(address account) external constant returns (uint256);
	function transfer(address _to, uint256 _value) external returns (bool);
	function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
	function approve(address _spender, uint256 _value) external returns (bool success);
	function approveAndCall(address _spender, uint256 _value, bytes _extraData) external returns (bool success);
	function burn(uint256 _value) external returns (bool success);
	function burnFrom(address _from, uint256 _value) external returns (bool success);
	function mintTransfer(address _to, uint _value) external returns (bool);
	function burnAt(address _at, uint _value) external returns (bool);
}




// https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
	function mul(uint256 a, uint256 b) internal pure returns (uint256) {
		if (a == 0) {
			return 0;
		}
		uint256 c = a * b;
		assert(c / a == b);
		return c;
	}

	function div(uint256 a, uint256 b) internal pure returns (uint256) {
		// assert(b > 0); // Solidity automatically throws when dividing by 0
		uint256 c = a / b;
		// assert(a == b * c + a % b); // There is no case in which this doesn't hold
		return c;
	}

	function sub(uint256 a, uint256 b) internal pure returns (uint256) {
		assert(b <= a);
		return a - b;
	}

	function add(uint256 a, uint256 b) internal pure returns (uint256) {
		uint256 c = a + b;
		assert(c >= a);
		return c;
	}
}



interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }

contract TokenERC20 {
	// Public variables of the token
	string public name;
	string public symbol;
	uint8 public decimals = 18;
	// 18 decimals is the strongly suggested default, avoid changing it
	uint256 public totalSupply;

	// This creates an array with all balances
	mapping (address => uint256) public balanceOf;
	mapping (address => mapping (address => uint256)) public allowance;

	// This generates a public event on the blockchain that will notify clients
	event Transfer(address indexed from, address indexed to, uint256 value);

	// This generates a public event on the blockchain that will notify clients
	event Approval(address indexed _owner, address indexed _spender, uint256 _value);

	// This notifies clients about the amount burnt
	event Burn(address indexed from, uint256 value);

	/**
	 * Constructor function
	 *
	 * Initializes contract with initial supply tokens to the creator of the contract
	 */
	constructor(
		uint256 initialSupply,
		string tokenName,
		string tokenSymbol
	) public {
		totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
		balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
		name = tokenName;                                   // Set the name for display purposes
		symbol = tokenSymbol;                               // Set the symbol for display purposes
	}

	/**
	 * Internal transfer, only can be called by this contract
	 */
	function _transfer(address _from, address _to, uint _value) internal {
		// Prevent transfer to 0x0 address. Use burn() instead
		require(_to != 0x0);
		// Check if the sender has enough
		require(balanceOf[_from] >= _value);
		// Check for overflows
		require(balanceOf[_to] + _value > balanceOf[_to]);
		// Save this for an assertion in the future
		uint previousBalances = balanceOf[_from] + balanceOf[_to];
		// Subtract from the sender
		balanceOf[_from] -= _value;
		// Add the same to the recipient
		balanceOf[_to] += _value;
		emit Transfer(_from, _to, _value);
		// Asserts are used to use static analysis to find bugs in your code. They should never fail
		assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
	}

	/**
	 * Transfer tokens
	 *
	 * Send `_value` tokens to `_to` from your account
	 *
	 * @param _to The address of the recipient
	 * @param _value the amount to send
	 */
	function transfer(address _to, uint256 _value) public returns (bool success) {
		_transfer(msg.sender, _to, _value);
		return true;
	}

	/**
	 * Transfer tokens from other address
	 *
	 * Send `_value` tokens to `_to` in behalf of `_from`
	 *
	 * @param _from The address of the sender
	 * @param _to The address of the recipient
	 * @param _value the amount to send
	 */
	function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
		require(_value <= allowance[_from][msg.sender]);     // Check allowance
		allowance[_from][msg.sender] -= _value;
		_transfer(_from, _to, _value);
		return true;
	}

	/**
	 * Set allowance for other address
	 *
	 * Allows `_spender` to spend no more than `_value` tokens in your behalf
	 *
	 * @param _spender The address authorized to spend
	 * @param _value the max amount they can spend
	 */
	function approve(address _spender, uint256 _value) public returns (bool success) {
		allowance[msg.sender][_spender] = _value;
		emit Approval(msg.sender, _spender, _value);
		return true;
	}

	/**
	 * Set allowance for other address and notify
	 *
	 * Allows `_spender` to spend no more than `_value` tokens in your behalf, and then ping the contract about it
	 *
	 * @param _spender The address authorized to spend
	 * @param _value the max amount they can spend
	 * @param _extraData some extra information to send to the approved contract
	 */
	function approveAndCall(address _spender, uint256 _value, bytes _extraData)
		public
		returns (bool success) {
		tokenRecipient spender = tokenRecipient(_spender);
		if (approve(_spender, _value)) {
			spender.receiveApproval(msg.sender, _value, this, _extraData);
			return true;
		}
	}

	/**
	 * Destroy tokens
	 *
	 * Remove `_value` tokens from the system irreversibly
	 *
	 * @param _value the amount of money to burn
	 */
	function burn(uint256 _value) public returns (bool success) {
		require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
		balanceOf[msg.sender] -= _value;            // Subtract from the sender
		totalSupply -= _value;                      // Updates totalSupply
		emit Burn(msg.sender, _value);
		return true;
	}

	/**
	 * Destroy tokens from other account
	 *
	 * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
	 *
	 * @param _from the address of the sender
	 * @param _value the amount of money to burn
	 */
	function burnFrom(address _from, uint256 _value) public returns (bool success) {
		require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
		require(_value <= allowance[_from][msg.sender]);    // Check allowance
		balanceOf[_from] -= _value;                         // Subtract from the targeted balance
		allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
		totalSupply -= _value;                              // Update totalSupply
		emit Burn(_from, _value);
		return true;
	}
}

contract developed {
	address public developer;

	/**
	 * Constructor
	 */
	constructor() public {
		developer = msg.sender;
	}

	/**
	 * @dev Checks only developer address is calling
	 */
	modifier onlyDeveloper {
		require(msg.sender == developer);
		_;
	}

	/**
	 * @dev Allows developer to switch developer address
	 * @param _developer The new developer address to be set
	 */
	function changeDeveloper(address _developer) public onlyDeveloper {
		developer = _developer;
	}

	/**
	 * @dev Allows developer to withdraw ERC20 Token
	 */
	function withdrawToken(address tokenContractAddress) public onlyDeveloper {
		TokenERC20 _token = TokenERC20(tokenContractAddress);
		if (_token.balanceOf(this) > 0) {
			_token.transfer(developer, _token.balanceOf(this));
		}
	}
}



contract escaped {
	address public escapeActivator;

	/**
	 * Constructor
	 */
	constructor() public {
		escapeActivator = 0xB15C54b4B9819925Cd2A7eE3079544402Ac33cEe;
	}

	/**
	 * @dev Checks only escapeActivator address is calling
	 */
	modifier onlyEscapeActivator {
		require(msg.sender == escapeActivator);
		_;
	}

	/**
	 * @dev Allows escapeActivator to switch escapeActivator address
	 * @param _escapeActivator The new escapeActivator address to be set
	 */
	function changeAddress(address _escapeActivator) public onlyEscapeActivator {
		escapeActivator = _escapeActivator;
	}
}





/**
 * @title SpinLottery
 */
contract SpinLottery is developed, escaped, LotteryInterface {
	using SafeMath for uint256;

	/**
	 * @dev Game variables
	 */
	address public owner;
	address public spinwinAddress;

	bool public contractKilled;
	bool public gamePaused;

	uint256 public numLottery;
	uint256 public lotteryTarget;
	uint256 public totalBankroll;
	uint256 public totalBuyTickets;
	uint256 public totalTokenWagered;
	uint256 public lotteryTargetIncreasePercentage;
	uint256 public lastBlockNumber;
	uint256 public lastLotteryTotalBlocks;

	uint256 public currentTicketMultiplier;
	uint256 public currentTicketMultiplierHonor;
	uint256 public currentTicketMultiplierBlockNumber;

	uint256 public maxBlockSecurityCount;
	uint256 public blockSecurityCount;
	uint256 public currentTicketMultiplierBlockSecurityCount;

	uint256 public ticketMultiplierModifier;

	uint256 public avgLotteryHours; // Average hours needed to complete a lottery
	uint256 public totalLotteryHours; // Total accumulative lottery hours
	uint256 public minBankrollDecreaseRate; // The rate to use to decrease spinwin's min bankroll
	uint256 public minBankrollIncreaseRate; // The rate to use to increase spinwin's min bankroll
	uint256 public lotteryContributionPercentageModifier; // The lottery contribution percentage modifier, used to calculate lottery contribution percentage
	uint256 public rateConfidenceModifier; // The rate confidence modifier, used to calculate lottery contribution percentage
	uint256 public currentLotteryPaceModifier; // The current lottery pace modifier, used to calculate lottery contribution percentage
	uint256 public maxLotteryContributionPercentage; // The maximum percent that we can contribute to the lottery

	uint256 constant public PERCENTAGE_DIVISOR = 1000000;
	uint256 constant public TWO_DECIMALS = 100; // To account for calculation with 2 decimal points
	uint256 constant public CURRENCY_DIVISOR = 10 ** 18;

	uint256 public startLotteryRewardPercentage; // The percentage of blocks that we want to reward player for starting next lottery
	uint256 internal lotteryContribution;
	uint256 internal carryOverContribution;
	uint256 public minRewardBlocksAmount;

	TokenInterface internal _spintoken;
	SettingInterface internal _setting;

	struct Lottery {
		uint256 lotteryTarget;
		uint256 bankroll;
		uint256 tokenWagered;
		uint256 lotteryResult;
		uint256 totalBlocks;
		uint256 totalBlocksRewarded;
		uint256 startTimestamp;
		uint256 endTimestamp;
		address winnerPlayerAddress;
		bool ended;
		bool cashedOut;
	}

	struct Ticket {
		bytes32 ticketId;
		uint256 numLottery;
		address playerAddress;
		uint256 minNumber;
		uint256 maxNumber;
		bool claimed;
	}
	mapping (uint256 => Lottery) public lotteries;
	mapping (bytes32 => Ticket) public tickets;
	mapping (uint256 => mapping (address => uint256)) public playerTokenWagered;
	mapping (address => uint256) public playerPendingWithdrawals;
	mapping (uint256 => mapping (address => uint256)) public playerTotalBlocks;
	mapping (uint256 => mapping (address => uint256)) public playerTotalBlocksRewarded;

	/**
	 * @dev Log when new lottery is created
	 */
	event LogCreateLottery(uint256 indexed numLottery, uint256 lotteryBankrollGoal);

	/**
	 * @dev Log when lottery is ended
	 */
	event LogEndLottery(uint256 indexed numLottery, uint256 lotteryResult);

	/**
	 * @dev Log when spinwin adds some funds
	 */
	event LogAddBankRoll(uint256 indexed numLottery, uint256 amount);

	/**
	 * @dev Log when player buys ticket
	 * Ticket type
	 * 1 = normal purchase
	 * 2 = Spinwin Reward
	 * 3 = Start Lottery Reward
	 */
	event LogBuyTicket(uint256 indexed numLottery, bytes32 indexed ticketId, address indexed playerAddress, uint256 tokenAmount, uint256 ticketMultiplier, uint256 minNumber, uint256 maxNumber, uint256 ticketType);

	/**
	 * @dev Log when player claims lotto ticket
	 *
	 * Status:
	 * 0: Lose
	 * 1: Win
	 * 2: Win + Failed send
	 */
	event LogClaimTicket(uint256 indexed numLottery, bytes32 indexed ticketId, address indexed playerAddress, uint256 lotteryResult, uint256 playerMinNumber, uint256 playerMaxNumber, uint256 winningReward, uint256 status);

	/**
	 * @dev Log when player withdraw balance
	 *
	 * Status:
	 * 0 = failed
	 * 1 = success
	 */
	event LogPlayerWithdrawBalance(address indexed playerAddress, uint256 withdrawAmount, uint256 status);

	/**
	 * @dev Log when current ticket multiplier is updated
	 */
	event LogUpdateCurrentTicketMultiplier(uint256 currentTicketMultiplier, uint256 currentTicketMultiplierBlockNumber);

	/**
	 * @dev Log when developer set contract to emergency mode
	 */
	event LogEscapeHatch();

	/**
	 * Constructor
	 */
	constructor(address _settingAddress, address _tokenAddress, address _spinwinAddress) public {
		_setting = SettingInterface(_settingAddress);
		_spintoken = TokenInterface(_tokenAddress);
		spinwinAddress = _spinwinAddress;
		lastLotteryTotalBlocks = 100 * CURRENCY_DIVISOR;                // init last lottery total blocks (10^20 blocks)
		devSetLotteryTargetIncreasePercentage(150000);                  // init lottery target increase percentage (15%);
		devSetMaxBlockSecurityCount(256);                               // init max block security count (256)
		devSetBlockSecurityCount(3);                                    // init block security count (3)
		devSetCurrentTicketMultiplierBlockSecurityCount(3);             // init current ticket multiplier block security count (3)
		devSetTicketMultiplierModifier(300);                            // init ticket multiplier modifier (3)
		devSetMinBankrollDecreaseRate(80);                              // init min bankroll decrease rate (0.8)
		devSetMinBankrollIncreaseRate(170);                             // init min bankroll increase rate (1.7)
		devSetLotteryContributionPercentageModifier(10);                // init lottery contribution percentage modifier (0.1)
		devSetRateConfidenceModifier(200);                              // init rate confidence modifier (2)
		devSetCurrentLotteryPaceModifier(200);                          // init current lottery pace modifier (2)
		devSetStartLotteryRewardPercentage(10000);                      // init start lottery reward percentage (1%)
		devSetMinRewardBlocksAmount(1);                                 // init min reward blocks amount (1)
		devSetMaxLotteryContributionPercentage(100);                    // init max lottery contribution percentage (1)
		_createNewLottery();                                            // start lottery
	}

	/**
	 * @dev Checks if the contract is currently alive
	 */
	modifier contractIsAlive {
		require(contractKilled == false);
		_;
	}

	/**
	 * @dev Checks if the game is currently active
	 */
	modifier gameIsActive {
		require(gamePaused == false);
		_;
	}

	/**
	 * @dev Checks only spinwin address is calling
	 */
	modifier onlySpinwin {
		require(msg.sender == spinwinAddress);
		_;
	}

	/******************************************/
	/*       DEVELOPER ONLY METHODS           */
	/******************************************/

	/**
	 * @dev Allows developer to set lotteryTarget
	 * @param _lotteryTarget The new lottery target value to be set
	 */
	function devSetLotteryTarget(uint256 _lotteryTarget) public onlyDeveloper {
		require (_lotteryTarget >= 0);
		lotteryTarget = _lotteryTarget;
		Lottery storage _lottery = lotteries[numLottery];
		_lottery.lotteryTarget = lotteryTarget;
	}

	/**
	 * @dev Allows developer to set lottery target increase percentage
	 * @param _lotteryTargetIncreasePercentage The new value to be set
	 * 1% = 10000
	 */
	function devSetLotteryTargetIncreasePercentage(uint256 _lotteryTargetIncreasePercentage) public onlyDeveloper {
		lotteryTargetIncreasePercentage = _lotteryTargetIncreasePercentage;
	}

	/**
	 * @dev Allows developer to set block security count
	 * @param _blockSecurityCount The new value to be set
	 */
	function devSetBlockSecurityCount(uint256 _blockSecurityCount) public onlyDeveloper {
		require (_blockSecurityCount > 0);
		blockSecurityCount = _blockSecurityCount;
	}

	/**
	 * @dev Allows developer to set max block security count
	 * @param _maxBlockSecurityCount The new value to be set
	 */
	function devSetMaxBlockSecurityCount(uint256 _maxBlockSecurityCount) public onlyDeveloper {
		require (_maxBlockSecurityCount > 0);
		maxBlockSecurityCount = _maxBlockSecurityCount;
	}

	/**
	 * @dev Allows developer to set current ticket multiplier block security count
	 * @param _currentTicketMultiplierBlockSecurityCount The new value to be set
	 */
	function devSetCurrentTicketMultiplierBlockSecurityCount(uint256 _currentTicketMultiplierBlockSecurityCount) public onlyDeveloper {
		require (_currentTicketMultiplierBlockSecurityCount > 0);
		currentTicketMultiplierBlockSecurityCount = _currentTicketMultiplierBlockSecurityCount;
	}

	/**
	 * @dev Allows developer to set ticket multiplier modifier
	 * @param _ticketMultiplierModifier The new value to be set (in two decimals)
	 * 1 = 100
	 */
	function devSetTicketMultiplierModifier(uint256 _ticketMultiplierModifier) public onlyDeveloper {
		require (_ticketMultiplierModifier > 0);
		ticketMultiplierModifier = _ticketMultiplierModifier;
	}

	/**
	 * @dev Allows developer to set min bankroll decrease rate
	 * @param _minBankrollDecreaseRate The new value to be set  (in two decimals)
	 * 1 = 100
	 */
	function devSetMinBankrollDecreaseRate(uint256 _minBankrollDecreaseRate) public onlyDeveloper {
		require (_minBankrollDecreaseRate >= 0);
		minBankrollDecreaseRate = _minBankrollDecreaseRate;
	}

	/**
	 * @dev Allows developer to set min bankroll increase rate
	 * @param _minBankrollIncreaseRate The new value to be set  (in two decimals)
	 * 1 = 100
	 */
	function devSetMinBankrollIncreaseRate(uint256 _minBankrollIncreaseRate) public onlyDeveloper {
		require (_minBankrollIncreaseRate > minBankrollDecreaseRate);
		minBankrollIncreaseRate = _minBankrollIncreaseRate;
	}

	/**
	 * @dev Allows developer to set lottery contribution percentage modifier
	 * @param _lotteryContributionPercentageModifier The new value to be set (in two decimals)
	 * 1 = 100
	 */
	function devSetLotteryContributionPercentageModifier(uint256 _lotteryContributionPercentageModifier) public onlyDeveloper {
		lotteryContributionPercentageModifier = _lotteryContributionPercentageModifier;
	}

	/**
	 * @dev Allows developer to set rate confidence modifier
	 * @param _rateConfidenceModifier The new value to be set (in two decimals)
	 * 1 = 100
	 */
	function devSetRateConfidenceModifier(uint256 _rateConfidenceModifier) public onlyDeveloper {
		rateConfidenceModifier = _rateConfidenceModifier;
	}

	/**
	 * @dev Allows developer to set current lottery pace modifier
	 * @param _currentLotteryPaceModifier The new value to be set (in two decimals)
	 * 1 = 100
	 */
	function devSetCurrentLotteryPaceModifier(uint256 _currentLotteryPaceModifier) public onlyDeveloper {
		currentLotteryPaceModifier = _currentLotteryPaceModifier;
	}

	/**
	 * @dev Allows developer to pause the game
	 * @param paused The new paused value to be set
	 */
	function devPauseGame(bool paused) public onlyDeveloper {
		gamePaused = paused;
	}

	/**
	 * @dev Allows developer to start new lottery (only when current lottery is ended)
	 * @return Return true if success
	 */
	function devStartLottery() public onlyDeveloper returns (bool) {
		Lottery memory _currentLottery = lotteries[numLottery];
		require (_currentLottery.ended == true);
		_createNewLottery();
		return true;
	}

	/**
	 * @dev Allows developer to end current lottery
	 * @param _startNextLottery Boolean value whether or not we should start next lottery
	 * @return Return true if success
	 */
	function devEndLottery(bool _startNextLottery) public onlyDeveloper returns (bool) {
		_endLottery();
		if (_startNextLottery) {
			_createNewLottery();
		}
		return true;
	}

	/**
	 * @dev Allows developer to set start lottery reward percentage
	 * @param _startLotteryRewardPercentage The new value to be set
	 * 1% = 10000
	 */
	function devSetStartLotteryRewardPercentage(uint256 _startLotteryRewardPercentage) public onlyDeveloper {
		startLotteryRewardPercentage = _startLotteryRewardPercentage;
	}

	/**
	 * @dev Allows developer to set start lottery min reward blocks amount
	 * @param _minRewardBlocksAmount The new value to be set
	 */
	function devSetMinRewardBlocksAmount(uint256 _minRewardBlocksAmount) public onlyDeveloper {
		minRewardBlocksAmount = _minRewardBlocksAmount;
	}

	/**
	 * @dev Allows developer to set max lottery contribution percentage
	 * @param _maxLotteryContributionPercentage The new value to be set
	 * 1 = 100
	 */
	function devSetMaxLotteryContributionPercentage(uint256 _maxLotteryContributionPercentage) public onlyDeveloper {
		maxLotteryContributionPercentage = _maxLotteryContributionPercentage;
	}

	/******************************************/
	/*      ESCAPE ACTIVATOR ONLY METHODS     */
	/******************************************/

	/**
	 * @dev Allows escapeActivator to trigger emergency mode. Will end current lottery and stop the game.
	 * @return Return true if success
	 */
	function escapeHatch() public
		onlyEscapeActivator
		contractIsAlive
		returns (bool) {
		contractKilled = true;
		_endLottery();
		emit LogEscapeHatch();
		return true;
	}

	/******************************************/
	/*         SPINWIN ONLY METHODS           */
	/******************************************/
	/**
	 * @dev Allows spinwin to buy ticket on behalf of playerAddress as part of claiming spinwin reward
	 * @param playerAddress The player address to be rewarded
	 * @param tokenAmount The amount of token to be spent
	 * @return The ticket ID
	 */
	function claimReward(address playerAddress, uint256 tokenAmount) public
		contractIsAlive
		gameIsActive
		onlySpinwin
		returns (bool) {
		return _buyTicket(playerAddress, tokenAmount, 2);
	}

	/******************************************/
	/*             PUBLIC METHODS             */
	/******************************************/
	/**
	 * @dev Add funds to the contract
	 * If the bankroll goal is reached, we want to end current lottery and start new lottery.
	 */
	function () payable public
		contractIsAlive
		gameIsActive {
		// Update the last block number
		lastBlockNumber = block.number;

		Lottery storage _currentLottery = lotteries[numLottery];
		if (_currentLottery.bankroll.add(msg.value) > lotteryTarget) {
			lotteryContribution = lotteryTarget.sub(_currentLottery.bankroll);
			carryOverContribution = carryOverContribution.add(msg.value.sub(lotteryContribution));
		} else {
			lotteryContribution = msg.value;
		}

		// Safely update bankroll
		if (lotteryContribution > 0) {
			_currentLottery.bankroll = _currentLottery.bankroll.add(lotteryContribution);
			totalBankroll = totalBankroll.add(lotteryContribution);
			emit LogAddBankRoll(numLottery, lotteryContribution);
		}
	}

	/**
	 * @dev Player buys lottery ticket
	 * @param tokenAmount The amount of token to spend
	 * @return Return the ticket ID
	 */
	function buyTicket(uint tokenAmount) public
		contractIsAlive
		gameIsActive
		returns (bool) {
		require (_spintoken.burnAt(msg.sender, tokenAmount));
		return _buyTicket(msg.sender, tokenAmount, 1);
	}

	/**
	 * @dev Player claims lottery ticket
	 * @param ticketId The ticket ID to be claimed
	 * @return Return true if success
	 */
	function claimTicket(bytes32 ticketId) public
		gameIsActive
		returns (bool) {
		Ticket storage _ticket = tickets[ticketId];
		require(_ticket.claimed == false && _ticket.playerAddress == msg.sender);

		Lottery storage _lottery = lotteries[_ticket.numLottery];
		require(_lottery.ended == true && _lottery.cashedOut == false && _lottery.bankroll > 0 && _lottery.totalBlocks.add(_lottery.totalBlocksRewarded) > 0 && _lottery.lotteryResult > 0);

		// Mark this ticket as claimed
		_ticket.claimed = true;
		uint256 status = 0; // status = failed
		if (_lottery.lotteryResult >= _ticket.minNumber && _lottery.lotteryResult <= _ticket.maxNumber) {
			uint256 lotteryReward = _lottery.bankroll;

			// Check if contract has enough bankroll to payout
			require(totalBankroll >= lotteryReward);

			// Safely adjust totalBankroll
			totalBankroll = totalBankroll.sub(lotteryReward);

			_lottery.bankroll = 0;
			_lottery.winnerPlayerAddress = msg.sender;
			_lottery.cashedOut = true;


			if (!msg.sender.send(lotteryReward)) {
				status = 2; // status = win + failed send
				// If send failed, let player withdraw via playerWithdrawPendingTransactions
				playerPendingWithdrawals[msg.sender] = playerPendingWithdrawals[msg.sender].add(lotteryReward);
			} else {
				status = 1; // status = win
			}
		}
		emit LogClaimTicket(_ticket.numLottery, ticketId, msg.sender, _lottery.lotteryResult, _ticket.minNumber, _ticket.maxNumber, lotteryReward, status);
		return true;
	}

	/**
	 * @dev Allows player to withdraw balance in case of a failed win send
	 * @return Return true if success
	 */
	function playerWithdrawPendingTransactions() public
		gameIsActive {
		require(playerPendingWithdrawals[msg.sender] > 0);
		uint256 withdrawAmount = playerPendingWithdrawals[msg.sender];

		playerPendingWithdrawals[msg.sender] = 0;

		// External call to untrusted contract
		uint256 status = 1; // status = success
		if (!msg.sender.send(withdrawAmount)) {
			status = 0; // status = failed

			/*
			 * If send failed, revert playerPendingWithdrawals[msg.sender] = 0
			 * so that player can try to withdraw again later
			 */
			playerPendingWithdrawals[msg.sender] = withdrawAmount;
		}
		emit LogPlayerWithdrawBalance(msg.sender, withdrawAmount, status);
	}

	/**
	 * @dev Calculates number of blocks the player will get when he/she buys the lottery ticket
	 *      based on player's entered token amount and current multiplier honor
	 * @return ticketMultiplier The ticket multiplier during this transaction
	 * @return numBlocks The lotto block count for this ticket
	 */
	function calculateNumBlocks(uint256 tokenAmount) public constant returns (uint256 ticketMultiplier, uint256 numBlocks) {
		return (currentTicketMultiplierHonor, currentTicketMultiplierHonor.mul(tokenAmount).div(TWO_DECIMALS));
	}

	/**
	 * @dev Get current num lottery
	 * @return Current num lottery
	 */
	function getNumLottery() public constant returns (uint256) {
		return numLottery;
	}

	/**
	 * @dev Check if contract is active
	 * @return Current state of contract
	 */
	function isActive() public constant returns (bool) {
		if (gamePaused == true || contractKilled == true) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * @dev Determines the lottery contribution percentage
	 * @return lotteryContributionPercentage (in two decimals)
	 */
	function calculateLotteryContributionPercentage() public
		contractIsAlive
		gameIsActive
		constant returns (uint256) {
		Lottery memory _currentLottery = lotteries[numLottery];
		uint256 currentTotalLotteryHours = _getHoursBetween(_currentLottery.startTimestamp, now);

		uint256 currentWeiToLotteryRate = 0;
		// To prevent division by 0
		if (currentTotalLotteryHours > 0) {
			/*
			 * currentWeiToLotteryRate = _currentLottery.bankroll / currentTotalLotteryHours;
			 * But since we need to account for decimal points
			 * currentWeiToLotteryRate = (_currentLottery.bankroll * TWO_DECIMALS)/currentTotalLotteryHours;
			 * currentWeiToLotteryRate needs to be divided by TWO_DECIMALS later on
			 */
			currentWeiToLotteryRate = (_currentLottery.bankroll.mul(TWO_DECIMALS)).div(currentTotalLotteryHours);
		}

		uint256 predictedCurrentLotteryHours = currentTotalLotteryHours;
		// To prevent division by 0
		if (currentWeiToLotteryRate > 0) {
			/*
			 * predictedCurrentLotteryHours = currentTotalLotteryHours + ((lotteryTarget - _currentLottery.bankroll)/currentWeiToLotteryRate);
			 * Let temp = (lotteryTarget - _currentLottery.bankroll)/currentWeiToLotteryRate;
			 * Since we need to account for decimal points
			 * temp = ((lotteryTarget - _currentLottery.bankroll)*TWO_DECIMALS)/currentWeiToLotteryRate;
			 * But currentWeiToLotteryRate is already in decimals
			 * temp = ((lotteryTarget - _currentLottery.bankroll)*TWO_DECIMALS)/(currentWeiToLotteryRate/TWO_DECIMALS);
			 * temp = ((lotteryTarget - _currentLottery.bankroll)*TWO_DECIMALS*TWO_DECIMALS)/currentWeiToLotteryRate;
			 * predictedCurrentLotteryHours = currentTotalLotteryHours + (temp/TWO_DECIMALS);
			 */
			uint256 temp = (lotteryTarget.sub(_currentLottery.bankroll)).mul(TWO_DECIMALS).mul(TWO_DECIMALS).div(currentWeiToLotteryRate);
			predictedCurrentLotteryHours = currentTotalLotteryHours.add(temp.div(TWO_DECIMALS));
		}

		uint256 currentLotteryPace = 0;
		// To prevent division by 0
		if (avgLotteryHours > 0) {
			/*
			 * currentLotteryPace = predictedCurrentLotteryHours/avgLotteryHours;
			 * But since we need to account for decimal points
			 * currentLotteryPace = (predictedCurrentLotteryHours*TWO_DECIMALS)/avgLotteryHours;
			 * But avgLotteryHours is already in decimals so we need to divide it by TWO_DECIMALS as well
			 * currentLotteryPace = (predictedCurrentLotteryHours*TWO_DECIMALS)/(avgLotteryHours/TWO_DECIMALS);
			 * OR
			 * currentLotteryPace = (predictedCurrentLotteryHours*TWO_DECIMALS*TWO_DECIMALS)/avgLotteryHours;
			 * currentLotteryPace needs to be divided by TWO_DECIMALS later on
			 */
			currentLotteryPace = (predictedCurrentLotteryHours.mul(TWO_DECIMALS).mul(TWO_DECIMALS)).div(avgLotteryHours);
		}

		uint256 percentageOverTarget = 0;
		// To prevent division by 0
		if (_setting.uintSettings('minBankroll') > 0) {
			/*
			 * percentageOverTarget = _spinwin.contractBalance() / _spinwin.minBankroll();
			 * But since we need to account for decimal points
			 * percentageOverTarget = (_spinwin.contractBalance()*TWO_DECIMALS) / _spinwin.minBankroll();
			 * percentageOverTarget needs to be divided by TWO_DECIMALS later on
			 */
			percentageOverTarget = (_setting.uintSettings('contractBalance').mul(TWO_DECIMALS)).div(_setting.uintSettings('minBankroll'));
		}

		currentTotalLotteryHours = currentTotalLotteryHours.mul(TWO_DECIMALS); // So that it has two decimals
		uint256 rateConfidence = 0;
		// To prevent division by 0
		if (avgLotteryHours.add(currentTotalLotteryHours) > 0) {
			/*
			 * rateConfidence = currentTotalLotteryHours / (avgLotteryHours + currentTotalLotteryHours);
			 * But since we need to account for decimal points
			 * rateConfidence = (currentTotalLotteryHours*TWO_DECIMALS) / (avgLotteryHours + currentTotalLotteryHours);
			 * rateConfidence needs to be divided by TWO_DECIMALS later on
			 */
			rateConfidence = currentTotalLotteryHours.mul(TWO_DECIMALS).div(avgLotteryHours.add(currentTotalLotteryHours));
		}

		/*
		 * lotteryContributionPercentage = 0.1 + (1-(1/percentageOverTarget))+(rateConfidence*2*(currentLotteryPace/(currentLotteryPace+2)))
		 * Replace the static number with modifier variables (that are already in decimals, so 0.1 is actually 10, 2 is actually 200)
		 * lotteryContributionPercentage = lotteryContributionPercentageModifier + (1-(1/percentageOverTarget)) + (rateConfidence*rateConfidenceModifier*(currentLotteryPace/(currentLotteryPace+currentLotteryPaceModifier)));
		 *
		 * Split to 3 sections
		 * lotteryContributionPercentage = calc1 + calc2 + calc3
		 * calc1 = lotteryContributionPercentageModifier
		 * calc2 = (1-(1/percentageOverTarget))
		 * calc3 = (rateConfidence*rateConfidenceModifier*(currentLotteryPace/(currentLotteryPace+currentLotteryPaceModifier)))
		 */
		uint256 lotteryContributionPercentage = lotteryContributionPercentageModifier;

		/*
		 * calc2 = 1-(1/percentageOverTarget)
		 * Since percentageOverTarget is already in two decimals
		 * calc2 = 1-(1/(percentageOverTarget/TWO_DECIMALS))
		 * calc2 = 1-(TWO_DECIMALS/percentageOverTarget)
		 * mult TWO_DECIMALS/TWO_DECIMALS to calculate fraction
		 * calc2 = (TWO_DECIMALS-((TWO_DECIMALS*TWO_DECIMALS)/percentageOverTarget))/TWO_DECIMALS
		 * since lotteryContributionPercentage needs to be in decimals, we can take out the division by TWO_DECIMALS
		 * calc2 = TWO_DECIMALS-((TWO_DECIMALS*TWO_DECIMALS)/percentageOverTarget)
		 */
		// To prevent division by 0
		if (percentageOverTarget > 0) {
			lotteryContributionPercentage = lotteryContributionPercentage.add(TWO_DECIMALS.sub((TWO_DECIMALS.mul(TWO_DECIMALS)).div(percentageOverTarget)));
		} else {
			lotteryContributionPercentage = lotteryContributionPercentage.add(TWO_DECIMALS);
		}

		/*
		 * calc3 = rateConfidence*rateConfidenceModifier*(currentLotteryPace/(currentLotteryPace+currentLotteryPaceModifier))
		 * But since rateConfidence, rateConfidenceModifier are already in decimals, we need to divide them by TWO_DECIMALS
		 * calc3 = (rateConfidence/TWO_DECIMALS)*(rateConfidenceModifier/TWO_DECIMALS)*(currentLotteryPace/(currentLotteryPace+currentLotteryPaceModifier))
		 * since we need to account for decimal points, mult the numerator `currentLotteryPace` with TWO_DECIMALS
		 * calc3 = (rateConfidence/TWO_DECIMALS)*(rateConfidenceModifier/TWO_DECIMALS)*((currentLotteryPace*TWO_DECIMALS)/(currentLotteryPace+currentLotteryPaceModifier))
		 * OR
		 * calc3 = (rateConfidence*rateConfidenceModifier*currentLotteryPace)/(TWO_DECIMALS*(currentLotteryPace+currentLotteryPaceModifier))
		 */
		// To prevent division by 0
		if (currentLotteryPace.add(currentLotteryPaceModifier) > 0) {
			lotteryContributionPercentage = lotteryContributionPercentage.add((rateConfidence.mul(rateConfidenceModifier).mul(currentLotteryPace)).div(TWO_DECIMALS.mul(currentLotteryPace.add(currentLotteryPaceModifier))));
		}
		if (lotteryContributionPercentage > maxLotteryContributionPercentage) {
			lotteryContributionPercentage = maxLotteryContributionPercentage;
		}
		return lotteryContributionPercentage;
	}

	/**
	 * @dev Allows player to start next lottery and reward player a percentage of last lottery total blocks
	 */
	function startNextLottery() public
		contractIsAlive
		gameIsActive {
		Lottery storage _currentLottery = lotteries[numLottery];
		require (_currentLottery.bankroll >= lotteryTarget && _currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded) > 0);
		uint256 startLotteryRewardBlocks = calculateStartLotteryRewardBlocks();
		_endLottery();
		_createNewLottery();

		// If we have carry over contribution from prev contribution
		// add it to the next lottery
		if (carryOverContribution > 0) {
			_currentLottery = lotteries[numLottery];
			if (_currentLottery.bankroll.add(carryOverContribution) > lotteryTarget) {
				lotteryContribution = lotteryTarget.sub(_currentLottery.bankroll);
				carryOverContribution = carryOverContribution.sub(lotteryContribution);
			} else {
				lotteryContribution = carryOverContribution;
				carryOverContribution = 0;
			}

			// Safely update bankroll
			_currentLottery.bankroll = _currentLottery.bankroll.add(lotteryContribution);
			totalBankroll = totalBankroll.add(lotteryContribution);
			emit LogAddBankRoll(numLottery, lotteryContribution);
		}
		_buyTicket(msg.sender, startLotteryRewardBlocks, 3);
	}

	/**
	 * @dev Calculate start lottery reward blocks amount
	 * @return The reward blocks amount
	 */
	function calculateStartLotteryRewardBlocks() public constant returns (uint256) {
		uint256 totalRewardBlocks = lastLotteryTotalBlocks.mul(startLotteryRewardPercentage).div(PERCENTAGE_DIVISOR);
		if (totalRewardBlocks == 0) {
			totalRewardBlocks = minRewardBlocksAmount;
		}
		return totalRewardBlocks;
	}

	/**
	 * @dev Get current ticket multiplier honor
	 * @return Current ticket multiplier honor
	 */
	function getCurrentTicketMultiplierHonor() public constant returns (uint256) {
		return currentTicketMultiplierHonor;
	}

	/**
	 * @dev Get current lottery target and bankroll
	 * @return Current lottery target
	 * @return Current lottery bankroll
	 */
	function getCurrentLotteryTargetBalance() public constant returns (uint256, uint256) {
		Lottery memory _lottery = lotteries[numLottery];
		return (_lottery.lotteryTarget, _lottery.bankroll);
	}

	/*****************************************/
	/*          INTERNAL METHODS              */
	/******************************************/

	/**
	 * @dev Creates new lottery
	 */
	function _createNewLottery() internal returns (bool) {
		numLottery++;
		lotteryTarget = _setting.uintSettings('minBankroll').add(_setting.uintSettings('minBankroll').mul(lotteryTargetIncreasePercentage).div(PERCENTAGE_DIVISOR));
		Lottery storage _lottery = lotteries[numLottery];
		_lottery.lotteryTarget = lotteryTarget;
		_lottery.startTimestamp = now;
		_updateCurrentTicketMultiplier();
		emit LogCreateLottery(numLottery, lotteryTarget);
		return true;
	}

	/**
	 * @dev Ends current lottery
	 */
	function _endLottery() internal returns (bool) {
		Lottery storage _currentLottery = lotteries[numLottery];
		require (_currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded) > 0);

		uint256 blockNumberDifference = block.number - lastBlockNumber;
		uint256 targetBlockNumber = 0;
		if (blockNumberDifference < maxBlockSecurityCount.sub(blockSecurityCount)) {
			targetBlockNumber = lastBlockNumber.add(blockSecurityCount);
		} else {
			targetBlockNumber = lastBlockNumber.add(maxBlockSecurityCount.mul(blockNumberDifference.div(maxBlockSecurityCount))).add(blockSecurityCount);
		}
		_currentLottery.lotteryResult = _generateRandomNumber(_currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded), targetBlockNumber);

		// If contract is killed, we don't want any leftover eth sits in the contract
		// Add the carry over contribution to current lottery
		if (contractKilled == true && carryOverContribution > 0) {
			lotteryTarget = lotteryTarget.add(carryOverContribution);
			_currentLottery.lotteryTarget = lotteryTarget;
			_currentLottery.bankroll = _currentLottery.bankroll.add(carryOverContribution);
			totalBankroll = totalBankroll.add(carryOverContribution);
			emit LogAddBankRoll(numLottery, carryOverContribution);
		}
		_currentLottery.endTimestamp = now;
		_currentLottery.ended = true;
		uint256 endingLotteryHours = _getHoursBetween(_currentLottery.startTimestamp, now);
		totalLotteryHours = totalLotteryHours.add(endingLotteryHours);

		/*
		 * avgLotteryHours = totalLotteryHours/numLottery
		 * But since we are doing division in integer, needs to account for the decimal points
		 * avgLotteryHours = totalLotteryHours * TWO_DECIMALS / numLottery; // TWO_DECIMALS = 100
		 * avgLotteryHours needs to be divided by TWO_DECIMALS again later on
		 */
		avgLotteryHours = totalLotteryHours.mul(TWO_DECIMALS).div(numLottery);
		lastLotteryTotalBlocks = _currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded);

		// Update spinwin's min bankroll
		if (_setting.boolSettings('contractKilled') == false && _setting.boolSettings('gamePaused') == false) {
			uint256 lotteryPace = 0;
			if (endingLotteryHours > 0) {
				/*
				 * lotteryPace = avgLotteryHours/endingLotteryHours
				 * Mult avgLotteryHours with TWO_DECIMALS to account for two decimal points
				 * lotteryPace = (avgLotteryHours * TWO_DECIMALS) / endingLotteryHours
				 * But from previous calculation, we already know that avgLotteryHours is already in decimals
				 * So, lotteryPace = ((avgLotteryHours*TWO_DECIMALS)/endingLotteryHours)/TWO_DECIMALS
				 * lotteryPace needs to be divided by TWO_DECIMALS again later on
				 */
				lotteryPace = avgLotteryHours.mul(TWO_DECIMALS).div(endingLotteryHours).div(TWO_DECIMALS);
			}

			uint256 newMinBankroll = 0;
			if (lotteryPace <= minBankrollDecreaseRate) {
				// If the pace is too slow, then we want to decrease spinwin min bankroll
				newMinBankroll = _setting.uintSettings('minBankroll').mul(minBankrollDecreaseRate).div(TWO_DECIMALS);
			} else if (lotteryPace <= minBankrollIncreaseRate) {
				// If the pace is too fast, then we want to increase spinwin min bankroll
				newMinBankroll = _setting.uintSettings('minBankroll').mul(minBankrollIncreaseRate).div(TWO_DECIMALS);
			} else {
				// Otherwise, set new min bankroll according to the lottery pace
				newMinBankroll = _setting.uintSettings('minBankroll').mul(lotteryPace).div(TWO_DECIMALS);
			}
			_setting.spinlotterySetMinBankroll(newMinBankroll);
		}

		emit LogEndLottery(numLottery, _currentLottery.lotteryResult);
	}

	/**
	 * @dev Buys ticket
	 * @param _playerAddress The player address that buys this ticket
	 * @param _tokenAmount The amount of SPIN token to spend
	 * @param _ticketType Is this a normal purchase / part of spinwin's reward program / start lottery reward?
	 * 1 = normal purchase
	 * 2 = spinwin reward
	 * 3 = start lottery reward
	 * @return Return true if success
	 */
	function _buyTicket(address _playerAddress, uint256 _tokenAmount, uint256 _ticketType) internal returns (bool) {
		require (_ticketType >=1 && _ticketType <= 3);
		totalBuyTickets++;
		Lottery storage _currentLottery = lotteries[numLottery];

		if (_ticketType > 1) {
			uint256 _ticketMultiplier = TWO_DECIMALS; // Ticket multiplier is 1
			uint256 _numBlocks = _tokenAmount;
			_tokenAmount = 0;  // Set token amount to 0 since we are not charging player any SPIN
		} else {
			_currentLottery.tokenWagered = _currentLottery.tokenWagered.add(_tokenAmount);
			totalTokenWagered = totalTokenWagered.add(_tokenAmount);
			(_ticketMultiplier, _numBlocks) = calculateNumBlocks(_tokenAmount);
		}

		// Generate ticketId
		bytes32 _ticketId = keccak256(abi.encodePacked(this, _playerAddress, numLottery, totalBuyTickets));
		Ticket storage _ticket = tickets[_ticketId];
		_ticket.ticketId = _ticketId;
		_ticket.numLottery = numLottery;
		_ticket.playerAddress = _playerAddress;
		_ticket.minNumber = _currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded).add(1);
		_ticket.maxNumber = _currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded).add(_numBlocks);

		playerTokenWagered[numLottery][_playerAddress] = playerTokenWagered[numLottery][_playerAddress].add(_tokenAmount);
		if (_ticketType > 1) {
			_currentLottery.totalBlocksRewarded = _currentLottery.totalBlocksRewarded.add(_numBlocks);
			playerTotalBlocksRewarded[numLottery][_playerAddress] = playerTotalBlocksRewarded[numLottery][_playerAddress].add(_numBlocks);
		} else {
			_currentLottery.totalBlocks = _currentLottery.totalBlocks.add(_numBlocks);
			playerTotalBlocks[numLottery][_playerAddress] = playerTotalBlocks[numLottery][_playerAddress].add(_numBlocks);
		}

		emit LogBuyTicket(numLottery, _ticket.ticketId, _ticket.playerAddress, _tokenAmount, _ticketMultiplier, _ticket.minNumber, _ticket.maxNumber, _ticketType);

		// Safely update current ticket multiplier
		_updateCurrentTicketMultiplier();

		// Call spinwin update token to wei exchange rate
		_setting.spinlotteryUpdateTokenToWeiExchangeRate();
		return true;
	}

	/**
	 * @dev Updates current ticket multiplier
	 */
	function _updateCurrentTicketMultiplier() internal returns (bool) {
		// Safely update current ticket multiplier
		Lottery memory _currentLottery = lotteries[numLottery];
		if (lastLotteryTotalBlocks > _currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded)) {
			/*
			 * currentTicketMultiplier = 1 + (ticketMultiplierModifier * ((lastLotteryTotalBlocks-currentLotteryBlocks)/lastLotteryTotalBlocks))
			 * Since we are calculating in decimals so 1 is actually 100 or TWO_DECIMALS
			 * currentTicketMultiplier = TWO_DECIMALS + (ticketMultiplierModifier * ((lastLotteryTotalBlocks-currentLotteryBlocks)/lastLotteryTotalBlocks))
			 * Let temp = (lastLotteryTotalBlocks-currentLotteryBlocks)/lastLotteryTotalBlocks
			 * To account for decimal points, we mult (lastLotteryTotalBlocks-currentLotteryBlocks) with TWO_DECIMALS
			 * temp = ((lastLotteryTotalBlocks-currentLotteryBlocks)*TWO_DECIMALS)/lastLotteryTotalBlocks
			 * We need to divide temp with TWO_DECIMALS later
			 *
			 * currentTicketMultiplier = TWO_DECIMALS + ((ticketMultiplierModifier * temp)/TWO_DECIMALS);
			 */
			uint256 temp = (lastLotteryTotalBlocks.sub(_currentLottery.totalBlocks.add(_currentLottery.totalBlocksRewarded))).mul(TWO_DECIMALS).div(lastLotteryTotalBlocks);
			currentTicketMultiplier = TWO_DECIMALS.add(ticketMultiplierModifier.mul(temp).div(TWO_DECIMALS));
		} else {
			currentTicketMultiplier = TWO_DECIMALS;
		}
		if (block.number > currentTicketMultiplierBlockNumber.add(currentTicketMultiplierBlockSecurityCount) || _currentLottery.tokenWagered == 0) {
			currentTicketMultiplierHonor = currentTicketMultiplier;
			currentTicketMultiplierBlockNumber = block.number;
			emit LogUpdateCurrentTicketMultiplier(currentTicketMultiplierHonor, currentTicketMultiplierBlockNumber);
		}
		return true;
	}

	/**
	 * @dev Generates random number between 1 to maxNumber based on targetBlockNumber
	 * @return The random number integer between 1 to maxNumber
	 */
	function _generateRandomNumber(uint256 maxNumber, uint256 targetBlockNumber) internal constant returns (uint256) {
		uint256 randomNumber = 0;
		for (uint256 i = 1; i < blockSecurityCount; i++) {
			randomNumber = ((uint256(keccak256(abi.encodePacked(randomNumber, blockhash(targetBlockNumber-i), numLottery + totalBuyTickets + totalTokenWagered))) % maxNumber)+1);
		}
		return randomNumber;
	}

	/**
	 * @dev Get hours between two timestamp
	 * @param _startTimestamp Starting timestamp
	 * @param _endTimestamp End timestamp
	 * @return Hours in between starting and ending timestamp
	 */
	function _getHoursBetween(uint256 _startTimestamp, uint256 _endTimestamp) internal pure returns (uint256) {
		uint256 _timestampDiff = _endTimestamp.sub(_startTimestamp);

		uint256 _hours = 0;
		while(_timestampDiff >= 3600) {
			_timestampDiff -= 3600;
			_hours++;
		}
		return _hours;
	}
}