contract BucketContract is Mortal {
	mapping (address => uint) public betAmount;
	mapping (address => bool) public hasBet;
	address[] public betters;
	uint[] public amountWon;
	uint[] public amountBid;
	address public owner;
	uint256 public totalBid;
	bool public payoutComplete;
	bool public isWinner;
	uint256 public gameId;
	uint256 public referralAmount;
	uint256 public settlementType;
	uint256 public processed;/* no of payouts processed */
	uint256 public remaining;/* no of payouts remaining */
	uint256 public totalBalance;

	GameContract public gameContractObject;

	event StateChanged(bool status, string message);
	event SendReward(address winner, uint amount);

	modifier onlyGameContractOrOwner {
		require (msg.sender == address(gameContractObject) || msg.sender == owner);
		_;
	}

	modifier onlyGameContract {
		require (msg.sender == address(gameContractObject));
		_;
	}

  modifier onlyOwner {
	  require(msg.sender == owner);
	  _;
  }

  constructor(address gcAddress/*, uint256 _gameId*/) public {
		owner = msg.sender;
		// gameId = _gameId;
		gameContractObject = GameContract(gcAddress);
		emit StateChanged(true, "bucket contract deployed");
	}

	function getBettersArrayLength() public view returns(uint256) {
		return betters.length;
	}

	function getBetter() public view returns(address[]) {
		return betters;
	} 

	function getWinningAmount() public view returns(uint[]) {
		return amountWon;
	}

	function getBidAmount() public view returns(uint[]) {
		return amountBid;
	}

	function setGameId(uint256 _gameId) public onlyGameContract {
		assert(gameId == 0);
		gameId = _gameId;
	}

	function bet() public payable /*gameRunning*/ {
		require (msg.value >= gameContractObject.getPrice(), "Too small bet");
		assert(gameContractObject.canBet());
		if (hasBet[msg.sender] == false) {
			betters.push(msg.sender);
			hasBet[msg.sender] = true;
		}
		betAmount[msg.sender] += msg.value;
		totalBid += msg.value;
		emit StateChanged(true,"Bet submitted");
	}

	function transferToOtherBucketContract(address _bucketContract) public onlyGameContractOrOwner {
		_bucketContract.transfer(address(this).balance);
	}

	function () public payable {
		emit StateChanged(true, "Ether Received");
	}

	/* setWinner function - set the winning contract */
	function setWinner(uint256 _gameId) public onlyGameContractOrOwner {
		require(_gameId == gameContractObject.gameId());
		assert(gameContractObject.state() == GameContract.GameState.RandomReceived);
		assert(!isWinner);
		isWinner = true;
		address houseAddressOne = gameContractObject.getHouseAddressOne();
		address houseAddressTwo = gameContractObject.getHouseAddressTwo();
		address referralAddress = gameContractObject.getReferralAddress();
		if (totalBid == 0) {
			houseAddressOne.transfer((address(this).balance * 70)/100);
			houseAddressTwo.transfer(address(this).balance);
      settlementType = 0;
		} else if (totalBid == address(this).balance) {
		    settlementType = 1;
		} else {
			totalBalance = address(this).balance - totalBid;
			uint256 houseAddressShare = gameContractObject.getHouseAddressShare();
			houseAddressOne.transfer((totalBalance * houseAddressShare * 70) / 10000);/* 70 percent of house share goes to bucket one */
			houseAddressTwo.transfer((totalBalance * houseAddressShare * 30) / 10000);/* 30 percent of house share goes to bucket one */
			referralAmount = (totalBalance * gameContractObject.getReferralAddressShare())/100;	
			referralAddress.transfer(referralAmount);
			totalBalance = address(this).balance;
			settlementType = 2;
		}
		processed = 0;
		remaining = betters.length;
	}

	function payout() public onlyGameContract {
		assert(!payoutComplete);
		assert(isWinner);
		uint256 batchsize = gameContractObject.getBatchSize();
		uint256 i;
		if (betters.length - processed <= batchsize) {
			batchsize = remaining;
		}
		uint256 processLimit = processed + batchsize;
		if (settlementType == 0) {
		    gameContractObject.finishGame();
		    return;
		}
		else if (settlementType == 1) {
			for (i = processed; i < processLimit && i < betters.length; i++) {
				address better = betters[i];
				uint amount = betAmount[better];
				better.transfer(amount);
				emit SendReward(better, amount);
				amountWon.push(amount);
			}
		
		} else if (settlementType == 2) {
			for (i = processed; i < processLimit && i < betters.length; i++) {
				address better2 = betters[i];
				uint amountToTransfer = (betAmount[better2]*totalBalance)/totalBid;
				better2.transfer(amountToTransfer); 
				emit SendReward(better2, amountToTransfer);
				amountWon.push(amountToTransfer - betAmount[better2]);
				amountBid.push(betAmount[better2]);
			}
		}
		processed = i;	
		remaining = betters.length - processed;
		if (processed > betters.length - 1) {
			payoutComplete = true;
			gameContractObject.getHouseAddressOne().transfer(address(this).balance);
			gameContractObject.finishGame();
		}
	}
	
	function resetBucket() public onlyGameContract {
	    assert(gameContractObject.state() == GameContract.GameState.Finishing);
	    uint256 i;
	    for (i = 0; i < betters.length; i++) {
	        delete betAmount[betters[i]];
	        delete hasBet[betters[i]];
	    }
	    delete betters;
	    delete amountWon;
	    delete amountBid;
	    totalBid = 0;
	    payoutComplete = false;
        isWinner = false;
	    gameId = 0;
			referralAmount = 0;
	    settlementType = 0;
	    processed = 0;/* no of payouts processed */
			remaining = 0;/* no of payouts remaining */ 
	    totalBalance = 0;
	}
	
	function drain() public onlyGameContractOrOwner {
		assert(gameContractObject.state() == GameContract.GameState.Deployed || gameContractObject.state() == GameContract.GameState.Finished);
		gameContractObject.getHouseAddressOne().transfer((address(this).balance * 7) / 10);
		gameContractObject.getHouseAddressTwo().transfer(address(this).balance);
		emit StateChanged(true, "Drain Successful");
	}

}
function setWinner(uint256 _gameId) public onlyGameContractOrOwner {
	require(_gameId == gameContractObject.gameId());
	assert(gameContractObject.state() == GameContract.GameState.RandomReceived);
	assert(!isWinner);
	isWinner = true;
	address houseAddressOne = gameContractObject.getHouseAddressOne();
	address houseAddressTwo = gameContractObject.getHouseAddressTwo();
	address referralAddress = gameContractObject.getReferralAddress();
	if (totalBid == 0) {
		houseAddressOne.transfer((address(this).balance * 70)/100);
		houseAddressTwo.transfer(address(this).balance);
     settlementType = 0;
	} else if (totalBid == address(this).balance) {
	    settlementType = 1;
	} else {
		totalBalance = address(this).balance - totalBid;
		uint256 houseAddressShare = gameContractObject.getHouseAddressShare();
		houseAddressOne.transfer((totalBalance * houseAddressShare * 70) / 10000);/* 70 percent of house share goes to bucket one */
		houseAddressTwo.transfer((totalBalance * houseAddressShare * 30) / 10000);/* 30 percent of house share goes to bucket one */
		referralAmount = (totalBalance * gameContractObject.getReferralAddressShare())/100;	
		referralAddress.transfer(referralAmount);
		totalBalance = address(this).balance;
		settlementType = 2;
	}
	processed = 0;
	remaining = betters.length;
}

/* setWinner function - set the winning contract */