contract Controller is Ownable {
    using SafeMath for uint256;

    // Contract implementing tokenomics events.
    IMilker private _milker;

    // Number of last "happened" round.
    uint256 private _lastPeriod;

    event Round(
        uint256 indexed round,
        bool indexed banditsComing,
        bool indexed sheriffsPotDistributing,
        uint256 banditsPercent,
        uint256 banditsAmount,
        uint256 arrestedAmount,
        uint256 burntAmount,
        uint256 vaultCommissionAmount,
        uint256 potDistributionAmount,
        uint256 timestamp
    );

    function setMilker(address milker) external onlyOwner {
        require(address(_milker) == address(0), "Controller: MILK token contract is set up already");
        require(milker != address(0), "Controller: MILK token contract cannot be set up to nothing");
        _milker = IMilker(milker);
    }

    ////////////////////////////////////////////////////////////////
    // [Event] All in one function to play a round
    // NOTE: Use more gas than estimated since random is used.
    ////////////////////////////////////////////////////////////////

    function round() external {
        uint256 period = _milker.getPeriod();
        require(period > _lastPeriod, "Controller: need to wait for a new round");
        _lastPeriod = _lastPeriod.add(1);

        // Randomization and results
        uint256 randomNumber = _randomNumber();
        bool banditsComing = (((randomNumber >> 24) % 10) < 3); // 30% chance
        bool sheriffsPotDistributing = false; // will be calculated later if necessary
        uint256 banditsPercent = 0; // will be calculated later if necessary

        // Results
        uint256 banditsAmount = 0;
        uint256 arrestedAmount = 0;
        uint256 burntAmount = 0;
        uint256 vaultCommissionAmount = 0;
        uint256 potDistributionAmount = 0;

        // Bandits
        if (banditsComing) {
            banditsPercent = (((randomNumber >> 40) % 99) + 1); // from 1% to 99% bandits share
            (banditsAmount, arrestedAmount, burntAmount) = _milker.bandits(banditsPercent);
        }

        // Sheriff's vault comission
        vaultCommissionAmount = _milker.sheriffsVaultCommission();

        // Sheriff's pot distribution
        if (!banditsComing) {
            sheriffsPotDistributing = (((randomNumber >> 64) % 10) < 3); // 30% chance
            if (sheriffsPotDistributing) {
                potDistributionAmount = _milker.sheriffsPotDistribution();
            }
        }

        emit Round(
            _lastPeriod, banditsComing, sheriffsPotDistributing, banditsPercent,
            banditsAmount, arrestedAmount, burntAmount,
            vaultCommissionAmount, potDistributionAmount,
            block.timestamp // solium-disable-line security/no-block-members
        );
    }

    ////////////////////////////////////////////////////////////////
    // Contract getters
    ////////////////////////////////////////////////////////////////

    function milker() external view returns (address) {
        return address(_milker);
    }

    function lastPeriod() external view returns (uint256) {
        return _lastPeriod;
    }

    ////////////////////////////////////////////////////////////////
    // Internal functions
    ////////////////////////////////////////////////////////////////

    function _randomNumber() private view returns (uint256) {
        bytes memory seed = abi.encodePacked(
            block.timestamp,           // solium-disable-line security/no-block-members
            blockhash(block.number-1), // solium-disable-line security/no-block-members
            blockhash(block.number-2), // solium-disable-line security/no-block-members
            blockhash(block.number-3), // solium-disable-line security/no-block-members
            blockhash(block.number-4), // solium-disable-line security/no-block-members
            blockhash(block.number-5), // solium-disable-line security/no-block-members
            _milker, _lastPeriod
        );
        return uint256(keccak256(seed));
    }
}
function round() external {
    uint256 period = _milker.getPeriod();
    require(period > _lastPeriod, "Controller: need to wait for a new round");
    _lastPeriod = _lastPeriod.add(1);

    // Randomization and results
    uint256 randomNumber = _randomNumber();
    bool banditsComing = (((randomNumber >> 24) % 10) < 3); // 30% chance
    bool sheriffsPotDistributing = false; // will be calculated later if necessary
    uint256 banditsPercent = 0; // will be calculated later if necessary

    // Results
    uint256 banditsAmount = 0;
    uint256 arrestedAmount = 0;
    uint256 burntAmount = 0;
    uint256 vaultCommissionAmount = 0;
    uint256 potDistributionAmount = 0;

    // Bandits
    if (banditsComing) {
        banditsPercent = (((randomNumber >> 40) % 99) + 1); // from 1% to 99% bandits share
        (banditsAmount, arrestedAmount, burntAmount) = _milker.bandits(banditsPercent);
    }

    // Sheriff's vault comission
    vaultCommissionAmount = _milker.sheriffsVaultCommission();

    // Sheriff's pot distribution
    if (!banditsComing) {
        sheriffsPotDistributing = (((randomNumber >> 64) % 10) < 3); // 30% chance
        if (sheriffsPotDistributing) {
            potDistributionAmount = _milker.sheriffsPotDistribution();
        }
    }

    emit Round(
        _lastPeriod, banditsComing, sheriffsPotDistributing, banditsPercent,
        banditsAmount, arrestedAmount, burntAmount,
        vaultCommissionAmount, potDistributionAmount,
        block.timestamp // solium-disable-line security/no-block-members
    );
}

////////////////////////////////////////////////////////////////