contract WastedWhalesDispensary is Ownable {

	WastedWhales public token;
	mapping(uint256 => uint256) private _etherClaimedByWhale;
	uint256 private _allTimeEthClaimed;

	constructor(address _tokenAddress) public {
		token = WastedWhales(_tokenAddress);
	}

	/**
	 * @dev gets total ether accrued.
	 */
	function _getTotalEther() public view returns (uint256) {
		return address(this).balance + _allTimeEthClaimed;
	}

	/**
	 * @dev gets total ether owed to to the whales in account.
	 */
	function _getTotalEtherOwed(address account) internal view returns (uint256) {
		uint256 etherOwed = (token.balanceOf(account) * _getTotalEther())/800;
		return etherOwed;
	}

	/**
	 * @dev gets total ether owed per whale.
	 */
	function _getTotalEtherOwedPerWhale() internal view returns (uint256) {
		uint256 etherOwed = (_getTotalEther()/800);
		return etherOwed;
	}

	/**
	 * @dev gets total ether claimed for whales in account.
	 */
	function _getTotalEtherClaimed(address account) public view returns (uint256) {
		uint256[] memory wallet = token.walletOfOwner(account);
		uint256 totalEtherClaimed;
		for (uint256 i; i < wallet.length; i++) {
			totalEtherClaimed += _etherClaimedByWhale[wallet[i]];
		}
		return totalEtherClaimed;
	}

	/**
	 * @dev gets current rewards for account.
	 */
	function _getRewardsForAccount(address account) public view returns (uint256) {
		uint256 rewards = _getTotalEtherOwed(account) - _getTotalEtherClaimed(account);
		return rewards;
	}

	/**
	 * @dev claims rewards for account.
	 */
	function claimRewards() public {
		address account = msg.sender;
		uint256[] memory wallet = token.walletOfOwner(account);
		uint256 totalEtherOwed = _getTotalEtherOwed(account);
		uint256 _totalEtherOwedPerWhale = _getTotalEtherOwedPerWhale();

		uint256 totalEtherClaimed;
		for (uint256 i; i < wallet.length; i++) {
			totalEtherClaimed += _etherClaimedByWhale[wallet[i]];
			uint256 diff = _totalEtherOwedPerWhale - _etherClaimedByWhale[wallet[i]];
			_etherClaimedByWhale[wallet[i]] += diff;
		}

		uint256 rewards = totalEtherOwed - totalEtherClaimed;
		if (rewards > address(this).balance) {
			rewards = address(this).balance;
		}
		_allTimeEthClaimed += rewards;

		address payable _to = payable(account);
		_to.transfer(rewards);
	}

	/**
	 * @dev deposit ETH
	 */
	function deposit() public payable {
		require(msg.value > 0, "Can't deposit zero ether.");
	}	

	/**
	 * @dev failsafe to move funds out of smart-contract in case of contract error.
	 */
	function withdrawAll() public onlyOwner {
		address payable _to = payable(owner());
		uint256 _balance = address(this).balance;
		_to.transfer(_balance);
	}
}
function _getRewardsForAccount(address account) public view returns (uint256) {
	uint256 rewards = _getTotalEtherOwed(account) - _getTotalEtherClaimed(account);
	return rewards;
}

/**
 	 * @dev gets current rewards for account.
 	 */