contract DoubleOrNothingImpl is DoubleOrNothing, Owned, Random, SafeMath {
    
    // Initialize state by assigning the owner to the contract deployer.
    function DoubleOrNothingImpl() {
        owner = msg.sender;
        maxWagerWei = 100000000000000000;
        waitTimeBlocks = 2;
        payoutOdds = 4950;
    }
    
    // Allow the owner to set maxWagerWei.
    function setMaxWagerWei(uint256 maxWager) public onlyOwner {
        maxWagerWei = maxWager;
    }
    
    // Allow the owner to set waitTimeBlocks.
    function setWaitTimeBlocks(uint waitTime) public onlyOwner {
        waitTimeBlocks = waitTime;
    }
    
    // Allow the owner to set payoutOdds.
    function setPayoutOdds(uint odds) public onlyOwner {
        payoutOdds = odds;
    }
    
    // Allow the owner to cash out the holdings of this contract.
    function withdraw(address recipient, uint256 balance) public onlyOwner {
        recipient.transfer(balance);
    }
    
    // Allow the owner to payout outstanding wagers on others' behalf.
    function ownerPayout(address wager_owner) public onlyOwner {
        _payout(wager_owner);
    }
    
    // Assume that simple transactions are trying to make a wager, unless it is
    // from the owner.
    function () payable public {
        if (msg.sender != owner) {
            makeWager();
        }
    }
    
    // Make a wager.
    function makeWager() payable public {
        if (msg.value == 0 || msg.value > maxWagerWei) throw;
        if (wagers[msg.sender].active) {
            // A Wager already exists for this user.
            throw;
        }
        wagers[msg.sender] = Wager({
            sender: msg.sender,
            wagerWei: msg.value,
            creationBlockNumber: block.number,
            active: true,
        });
    }
    
    // View your wager.
    function getMyWager() constant public returns (
        uint256 wagerWei,
        uint creationBlockNumber,
        bool active) {
        return getWager(msg.sender);
    }
    
    // View the wager for a given address.
    function getWager(address wager_owner) constant public returns (
        uint256 wagerWei,
        uint creationBlockNumber,
        bool active) {
        Wager thisWager = wagers[wager_owner];
        return (thisWager.wagerWei, thisWager.creationBlockNumber, thisWager.active);
    }
    
    // Payout any wagers associated with the sending address.
    function payout() public {
        _payout(msg.sender);
    }
    
    // Internal implementation of payout().
    function _payout(address wager_owner) internal {
        if (!wagers[wager_owner].active) {
            // No outstanding active Wager.
            throw;
        }
        uint256 blockDepth = block.number - wagers[wager_owner].creationBlockNumber;
        if (blockDepth > waitTimeBlocks) {
            // waitTimeBlocks has passed, resolve and payout this wager.
            uint256 payoutBlock = wagers[wager_owner].creationBlockNumber + waitTimeBlocks - 1;
            uint randNum = getRand(payoutBlock, 10000);
            if (randNum < payoutOdds) {
                // Wager wins, payout wager.
                uint256 winnings = safeMult(wagers[wager_owner].wagerWei, 2);
                if (wagers[wager_owner].sender.send(winnings)) {
                    wagers[wager_owner].active = false;
                }
            } else {
                // Wager loses, disable wager.
                wagers[wager_owner].active = false;
            }
        }
    }
}
function withdraw(address recipient, uint256 balance) public onlyOwner {
    recipient.transfer(balance);
}

// Allow the owner to cash out the holdings of this contract.