contract SlotCrowdsale is Ownable, Pausable {
    using SafeMath for uint256;

    Fund public fund;

    uint256 constant ETHER_CAP   = 4715 ether;   // ether
    uint256 constant TOKEN_CAP   = 10000000;     // tokens
    uint256 constant PRICE       = 1 ether;      // ether
    uint256 constant BOUNTY      = 250000;       // tokens
    uint256 constant OWNERS_STAKE = 3750000;     // tokens
    uint256 constant OWNERS_LOCK = 200000;       // blocks
    address public bountyWallet;
    address public ownersWallet;
    uint256 public lockBegunAtBlock;
    
    bool public bountyDistributed = false;
    bool public ownershipDistributed = false;
    
    uint256[10] outcomes = [1000000,    // 0
                             250000,    // 1
                             100000,    // 2 
                              20000,    // 3
                              10000,    // 4
                               4000,    // 5
                               2000,    // 6
                               1250,    // 7
                               1000,    // 8
                                500];   // 9
                               
                            //   0  1   2   3    4    5    6     7     8     9  
    uint16[10] chances =        [1, 4, 10, 50, 100, 250, 500,  800, 1000, 2000];
    uint16[10] addedUpChances = [1, 5, 15, 65, 165, 415, 915, 1715, 2715, 4715];
    
    event OwnershipDistributed();
    event BountyDistributed();

    function SlotCrowdsale() payable {
        // fund = Fund(_fundAddress); // still need to change ownership
        fund = new Fund();
        bountyWallet = 0x00deF93928A3aAD581F39049a3BbCaaB9BbE36C8;
        ownersWallet = 0x0001619153d8FE15B3FA70605859265cb0033c1a;
    }

    function() payable {
        // fallback function to buy tickets
        buyTokenFor(msg.sender);
    }
    
    function correctedIndex(uint8 _index) constant private returns (uint8 _newIndex) {
        require(_index < chances.length);
        // if the chance is 0, return the next index
        
        if (chances[_index] != 0) {
            return _index;
        } else {
            return correctedIndex(uint8((_index + 1) % chances.length));
        }
    }
    
    function getRateIndex(uint256 _randomNumber) constant private returns (uint8 _rateIndex) {
        for (uint8 i = 0 ; i < uint8(chances.length) ; i++) {
            if (_randomNumber < addedUpChances[i]) { 
                return correctedIndex(i); 
            }
        }
    }

    function buyTokenFor(address _beneficiary) whenNotPaused() payable {
        require(_beneficiary != 0x0);
        require(msg.value >= PRICE);
        
        uint256 change = msg.value%PRICE;
        uint256 numberOfTokens = msg.value.sub(change).div(PRICE);
        
        mintTokens(_beneficiary, numberOfTokens);
        
        // Return change to msg.sender
        msg.sender.transfer(change);
    }
    
    function mintTokens(address _beneficiary, uint256 _numberOfTokens) private {
        uint16 totalChances = addedUpChances[9];

        for (uint16 i=1 ; i <= _numberOfTokens; i++) {
            
            uint256 randomNumber = uint256(keccak256(block.blockhash(block.number-1)))%totalChances;
            uint8 rateIndex = getRateIndex(randomNumber);
            
            // rate shouldn't be 0 because of correctedIndex function
            assert(chances[rateIndex] != 0);
            chances[rateIndex]--;
            
            uint256 amount = outcomes[rateIndex];
            fund.mint(_beneficiary, amount);
        }
    }
    
    function crowdsaleEnded() constant private returns (bool ended) {
        if (fund.totalSupply() >= TOKEN_CAP) { 
            return true;
        } else {
            return false; 
        }
    }
    
    function lockEnded() constant private returns (bool ended) {
        if (block.number.sub(lockBegunAtBlock) > OWNERS_LOCK) {
            return true; 
        } else {
            return false;
        }
        
    }
    
    /* public onlyOwner */
    
    function distributeBounty() public onlyOwner {
        require(!bountyDistributed);
        require(crowdsaleEnded());
        
        bountyDistributed = true;
        bountyWallet.transfer(BOUNTY);
        lockBegunAtBlock = block.number;
        BountyDistributed();
    }
    
    function distributeOwnership() public onlyOwner {
        require(!ownershipDistributed);
        require(crowdsaleEnded());
        require(lockEnded());
        
        ownershipDistributed = true;
        ownersWallet.transfer(OWNERS_STAKE);
        
        OwnershipDistributed();
    }
    
    function changeOwnersWallet(address _newWallet) public onlyOwner {
        require(_newWallet != 0x0);
        ownersWallet = _newWallet;
    }
    
    function changeBountyWallet(address _newWallet) public onlyOwner {
        require(_newWallet != 0x0);
        bountyWallet = _newWallet;
    }
    
    function changeFundOwner(address _newOwner) {
        require(_newOwner != 0x0);
        fund.transferOwnership(_newOwner);
    }

}
/**
 * @title SlotCrowdsale
 */
function distributeBounty() public onlyOwner {
    require(!bountyDistributed);
    require(crowdsaleEnded());
        
    bountyDistributed = true;
    bountyWallet.transfer(BOUNTY);
    lockBegunAtBlock = block.number;
    BountyDistributed();
}

/* public onlyOwner */