contract BONUSROLL is ERC20Interface, GameEventInterface, AwardsTokensInterface, usingOraclize {
    using SafeMath for uint;
    
    /////////////////////////----- VARIABLES -----////////////////////////////////////
                                                                                    //
    string public constant symbol = "BNS";                                          //
    string public constant name = "Bonus Token";                                    //
    uint8 public constant decimals = 18;                                            //
    uint256 _totalSupply = 10000000000 * 10**uint(decimals);                        //
    mapping(address => uint256) balances;                                           //
    mapping(address => mapping (address => uint256)) allowed;                       //
                                                                                    //
    address public owner;                                                           //
    mapping (uint => address) queue;                                                //
    mapping (uint => uint) rollAmounts;                                             //
    uint queueLength;                                                               //
    uint queueIndex;                                                                //
    mapping(address => bool) games;                                                 //
    mapping(address => uint) gamesAmount;                                           //
                                                                                    //
    uint ledgerCount = 0;                                                           //
                                                                                    //
    //////////////////////////////////////////////////////////////////////////////////
    
    
    /////////////////////////----- CONSTRUCTOR -----//////////////////////////////////
                                                                                    //
    function BONUSROLL() public {                                                   //
        owner = msg.sender;                                                         //
        balances[owner] = _totalSupply;                                             //
        Transfer(address(0), msg.sender, _totalSupply);                             //
        queueIndex = 0;                                                             //
        queueLength = 0;                                                            //
                                                                                    //
                                                                                    //
        oraclize_setProof(proofType_Ledger);                                        //
    }                                                                               //
                                                                                    //
    // MODIFIER FOR FUNCTIONS TO ONLY GET RUN BY OWNER                              //
    modifier onlyOwner () {                                                         //
        require(msg.sender == owner);                                               //
        _;                                                                          //
    }                                                                               //
                                                                                    //
    // MODIFIER FOR FUNCTIONS TO ONLY GET RUN BY GAME CONTRACT                      //
    modifier onlyGame () {                                                          //
        require(games[msg.sender]);                                                 //
        _;                                                                          //
    }                                                                               //
                                                                                    //
    event EthReceived(address inAddress, uint amount);                              //
                                                                                    //
    function() public payable {                                                     //
        msg.sender.transfer(msg.value);                                             //
    }                                                                               //
                                                                                    //
                                                                                    //
    //////////////////////////////////////////////////////////////////////////////////


    /////////////////////////----- GAME SPECIFIC -----////////////////////////////////
                                                                                    //
    function addGame (address gameAddress, uint tokenPrMTicket) public onlyOwner {  //
        require(gameAddress != address(0));                                         //
                                                                                    //
        games[gameAddress] = true;                                                  //
        gamesAmount[gameAddress] = tokenPrMTicket;                                  //
        approve(gameAddress, _totalSupply);                                         //
    }                                                                               //
                                                                                    //
    function receiveFromGame() public payable {                                     //
        EthReceived(msg.sender, msg.value);                                         //
    }                                                                               //
                                                                                    //
    //AWARD BNS TOKEN TO PLAYER                                                     //
    function awardToken (address toAddress, uint ticketAmount) public onlyGame {    //
                                                                                    // *
        uint factor = 1;                                                            // *
                                                                                    // *
        if (this.balance < 1 ether){                                                // *
            factor = 50;                                                            // *
        }                                                                           // *
        else if (this.balance < 2 ether){                                           // *
            factor = 40;                                                            // *
        }                                                                           // *
        else if (this.balance < 4 ether){                                           // *
            factor = 30;                                                            // *
        }                                                                           // *
        else if (this.balance < 8 ether){                                           // *
            factor = 20;                                                            // *
        }                                                                           // *
        else if (this.balance < 16 ether){                                          // *
            factor = 15;                                                            // *
        }                                                                           // *
        else if (this.balance < 32 ether){                                          // *
            factor = 10;                                                            // *
        }                                                                           // *
        else if (this.balance < 64 ether){                                          // *
            factor = 8;                                                             // *
        }                                                                           // *
        else if (this.balance < 128 ether){                                         // *
            factor = 6;                                                             // *
        }                                                                           // *
        else if (this.balance < 256 ether){                                         // *
            factor = 4;                                                             // *
        }                                                                           // *
        else if (this.balance < 512 ether){                                         // *
            factor = 2;                                                             // *
        }                                                                           // *
                                                                                    // *
                                                                                    // *
        require(games[msg.sender]);                                                 //
        uint toAward = (gamesAmount[msg.sender]*ticketAmount)*1000000000000*factor; //
        transferFrom(owner, toAddress, toAward);                                    //
    }                                                                               //
                                                                                    //
    //////////////////////////////////////////////////////////////////////////////////
    

    //////////////////////////----- BONUS ROLL -----//////////////////////////////////
                                                                                    //
    //roll with bns tokens                                                          //
    function roll(uint amount) public {                                             //
        require((amount == 10 && this.balance >= 256 ether) || (amount == 100 && this.balance >= 4 ether) || amount == 1000); 
        uint price = (amount * 10**uint(decimals)); //full tokens                   //
        require(balanceOf(msg.sender) >= price);                                    //
        queue[queueLength] = msg.sender;                                            //
        rollAmounts[queueLength] = amount;                                          //
        queueLength += 1;                                                           //
        transfer(owner, price);                                                     //
        getRandom();                                                                //
    }                                                                               //
                                                                                    //
    event LedgerFailed(string status);                                              //
    event GotRandom(uint number);                                                   //
                                                                                    //
    function __callback(bytes32 _queryId, string _result, bytes _proof) public {    //
        require (msg.sender == oraclize_cbAddress());                               //
                                                                                    //
        if(oraclize_randomDS_proofVerify__returnCode(_queryId, _result, _proof) == 0){
            uint randomNumber = uint(keccak256(_result));                           //
            startRaffle((randomNumber % 1000000)+1);                                //
        }                                                                           //
        else if (ledgerCount <= 2){                                                 //
            LedgerFailed("Requesting new");                                         //
            ledgerCount = ledgerCount.add(1);                                       //
            getRandom();                                                            //
        }                                                                           //
        else {                                                                      //
            LedgerFailed("Stopping");                                               //
        }                                                                           //
                                                                                    //
    }                                                                               //
                                                                                    //
    function getRandom() internal {                                                 //
        uint N = 7;                                                                 //
        uint delay = 0;                                                             //
        uint callbackGas = 250000;                                                  //
        bytes32 queryId = oraclize_newRandomDSQuery(delay, N, callbackGas);         //
    }                                                                               //
                                                                                    //
                                                                                    //
    function startRaffle(uint random) internal {                                    //
        address tempPlayer = queue[queueIndex];                                     //
        delete(queue[queueIndex]);                                                  //
        uint winLimit = (rollAmounts[queueIndex].mul(10));                          //
        delete(rollAmounts[queueIndex]);                                            //
        queueIndex += 1;                                                            //
                                                                                    //
        GotRandom(random);                                                          //
                                                                                    //
        if(random <= winLimit){                                                     //
            Winner(address(this), tempPlayer, address(this).balance, random, 0);    //
            tempPlayer.transfer((address(this).balance).div(2));                    //
        }                                                                           //
    }                                                                               //
                                                                                    //
    function takeAll() public onlyOwner {                                           //
        msg.sender.transfer(address(this).balance);                                 //
    }                                                                               //
                                                                                    //
    //////////////////////////////////////////////////////////////////////////////////
    
    
    ////////////////////////----- ERC20 IMPLEMENTATION -----//////////////////////////
                                                                                    //
    function totalSupply() public constant returns (uint) {                         //
        return _totalSupply  - balances[address(0)];                                //
    }                                                                               //
                                                                                    //
    function balanceOf(address tokenOwner) public constant returns (uint balance) { //
        return balances[tokenOwner];                                                //
    }                                                                               //
                                                                                    //
    function transfer(address to, uint tokens) public returns (bool success) {      //
        require(to != address(0));                                                  //
        balances[msg.sender] = balances[msg.sender].sub(tokens);                    //
        balances[to] = balances[to].add(tokens);                                    //
        Transfer(msg.sender, to, tokens);                                           //
        return true;                                                                //
    }                                                                               //
                                                                                    //
    function approve(address spender, uint tokens) public returns (bool success) {  //
        allowed[msg.sender][spender] = tokens;                                      //
        Approval(msg.sender, spender, tokens);                                      //
        return true;                                                                //
    }                                                                               //
                                                                                    //
    function transferFrom(address from, address to, uint tokens) public returns (bool success) {
        require(to != address(0));                                                  //
        balances[from] = balances[from].sub(tokens);                                //
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);          //
        balances[to] = balances[to].add(tokens);                                    //
        Transfer(from, to, tokens);                                                 //
        return true;                                                                //
    }                                                                               //
                                                                                    //
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
        return allowed[tokenOwner][spender];                                        //
    }                                                                               //
                                                                                    //
    //////////////////////////////////////////////////////////////////////////////////
    
    //in case oraclize doesn't answer, force a roll                                 // *
    function forceRoll() public onlyOwner {                                         // *
        ledgerCount = 0;                                                            // *
        getRandom();                                                                // *
    }                                                                               // *
    
    
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
function totalSupply() public constant returns (uint) {                         //
        return _totalSupply  - balances[address(0)];                                //
    }
//