contract Token is HouseOwned, ERC20Interface {
    using SafeMath for uint;

    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public constant decimals = 0;
    uint256 public supply;

    // Trusted addresses
    Jackpot public jackpot;
    address public croupier;

    // All users' balances
    mapping (address => uint256) internal balances;
    // Users' deposits with Croupier
    mapping (address => uint256) public depositOf;
    // Total amount of deposits
    uint256 public totalDeposit;
    // Total amount of "Frozen Deposit Pool" -- the tokens for sale at Croupier
    uint256 public frozenPool;
    // Allowance mapping
    mapping (address => mapping (address => uint256)) internal allowed;

    //////
    /// @title Modifiers
    //

    /// @dev Only Croupier
    modifier onlyCroupier {
        require(msg.sender == croupier);
        _;
    }

    /// @dev Only Jackpot
    modifier onlyJackpot {
        require(msg.sender == address(jackpot));
        _;
    }

    /// @dev Protection from short address attack
    modifier onlyPayloadSize(uint size) {
        assert(msg.data.length == size + 4);
        _;
    }

    //////
    /// @title Events
    //

    /// @dev Fired when a token is burned (bet made)
    event Burn(address indexed from, uint256 value);

    /// @dev Fired when a deposit is made or withdrawn
    ///       direction == 0: deposit
    ///       direction == 1: withdrawal
    event Deposit(address indexed from, uint256 value, uint8 direction, uint256 newDeposit);

    /// @dev Fired when a deposit with Croupier is frozen (set for sale)
    event DepositFrozen(address indexed from, uint256 value);

    /// @dev Fired when a deposit with Croupier is unfrozen (removed from sale)
    //       Value is the resulting deposit, NOT the unfrozen amount
    event DepositUnfrozen(address indexed from, uint256 value);

    //////
    /// @title Constructor and Initialization
    //

    /// @dev Initializes contract with initial supply tokens to the creator of the contract
    function Token() HouseOwned() public {
        name = "JACK Token";
        symbol = "JACK";
        supply = 1000000;
    }

    /// @dev Function to set address of Jackpot contract once after creation
    /// @param _jackpot Address of the Jackpot contract
    function setJackpot(address _jackpot) onlyHouse public {
        require(address(jackpot) == 0x0);
        require(_jackpot != address(this)); // Protection from admin's mistake

        jackpot = Jackpot(_jackpot);

        uint256 bountyPortion = supply / 40;           // 2.5% is the bounty portion for marketing expenses
        balances[house] = bountyPortion;               // House receives the bounty tokens
        balances[jackpot] = supply - bountyPortion;    // Jackpot gets the rest

        croupier = jackpot.croupier();
    }

    //////
    /// @title Public Methods
    //


    /// @dev Croupier invokes this method to return deposits to players
    /// @param _to The address of the recipient
    /// @param _extra Additional off-chain credit (AirDrop support), so that croupier can return more than the user has actually deposited
    function returnDeposit(address _to, uint256 _extra) onlyCroupier public {
        require(depositOf[_to] > 0 || _extra > 0);
        uint256 amount = depositOf[_to];
        depositOf[_to] = 0;
        totalDeposit = totalDeposit.sub(amount);

        _transfer(croupier, _to, amount.add(_extra));

        Deposit(_to, amount, 1, 0);
    }

    /// @dev Gets the balance of the specified address.
    /// @param _owner The address
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return balances[_owner];
    }
    
    function totalSupply() public view returns (uint256) {
        return supply;
    }

    /// @dev Send `_value` tokens to `_to`
    /// @param _to The address of the recipient
    /// @param _value the amount to send
    function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32) public returns (bool) {
        require(address(jackpot) != 0x0);
        require(croupier != 0x0);

        if (_to == address(jackpot)) {
            // It is a token bet. Ignoring _value, only using 1 token
            _burnFromAccount(msg.sender, 1);
            jackpot.betToken(msg.sender);
            return true;
        }

        if (_to == croupier && msg.sender != house) {
            // It's a deposit to Croupier. In addition to transferring the token,
            // mark it in the deposits table

            // House can't make deposits. If House is transferring something to
            // Croupier, it's just a transfer, nothing more

            depositOf[msg.sender] += _value;
            totalDeposit = totalDeposit.add(_value);

            Deposit(msg.sender, _value, 0, depositOf[msg.sender]);
        }

        // In all cases but Jackpot transfer (which is terminated by a return), actually
        // do perform the transfer
        return _transfer(msg.sender, _to, _value);
    }

    /// @dev Transfer tokens from one address to another
    /// @param _from address The address which you want to send tokens from
    /// @param _to address The address which you want to transfer to
    /// @param _value uint256 the amount of tokens to be transferred
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        require(_to != address(0));
        require(_value <= balances[_from]);
        require(_value <= allowed[_from][msg.sender]);

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        Transfer(_from, _to, _value);
        return true;
    }

    /// @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
    /// @param _spender The address which will spend the funds.
    /// @param _value The amount of tokens to be spent.
    function approve(address _spender, uint256 _value) public returns (bool) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    /// @dev Function to check the amount of tokens that an owner allowed to a spender.
    /// @param _owner address The address which owns the funds.
    /// @param _spender address The address which will spend the funds.
    /// @return A uint256 specifying the amount of tokens still available for the spender.
    function allowance(address _owner, address _spender) public view returns (uint256) {
        return allowed[_owner][_spender];
    }

    /// @dev Increase the amount of tokens that an owner allowed to a spender.
    /// @param _spender The address which will spend the funds.
    /// @param _addedValue The amount of tokens to increase the allowance by.
    function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
        allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
        Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /// @dev Decrease the amount of tokens that an owner allowed to a spender.
    /// @param _spender The address which will spend the funds.
    /// @param _subtractedValue The amount of tokens to decrease the allowance by.
    function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
        uint oldValue = allowed[msg.sender][_spender];
        if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
        } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
        }
        Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /// @dev Croupier uses this method to set deposited credits of a player for sale
    /// @param _user The address of the user
    /// @param _extra Additional off-chain credit (AirDrop support), so that croupier could have frozen more than the user had invested
    function freezeDeposit(address _user, uint256 _extra) onlyCroupier public {
        require(depositOf[_user] > 0 || _extra > 0);

        uint256 deposit = depositOf[_user];
        depositOf[_user] = depositOf[_user].sub(deposit);
        totalDeposit = totalDeposit.sub(deposit);

        uint256 depositWithExtra = deposit.add(_extra);

        frozenPool = frozenPool.add(depositWithExtra);

        DepositFrozen(_user, depositWithExtra);
    }

    /// @dev Croupier uses this method stop selling user's tokens and return them to normal deposit
    /// @param _user The user whose deposit is being unfrozen
    /// @param _value The value to unfreeze according to Croupier's records (off-chain sale data)
    function unfreezeDeposit(address _user, uint256 _value) onlyCroupier public {
        require(_value > 0);
        require(frozenPool >= _value);

        depositOf[_user] = depositOf[_user].add(_value);
        totalDeposit = totalDeposit.add(_value);

        frozenPool = frozenPool.sub(_value);

        DepositUnfrozen(_user, depositOf[_user]);
    }

    /// @dev The Jackpot contract invokes this method when selling tokens from Croupier
    /// @param _to The recipient of the tokens
    /// @param _value The amount
    function transferFromCroupier(address _to, uint256 _value) onlyJackpot public {
        require(_value > 0);
        require(frozenPool >= _value);

        frozenPool = frozenPool.sub(_value);

        _transfer(croupier, _to, _value);
    }

    //////
    /// @title Internal Methods
    //

    /// @dev Internal transfer function
    /// @param _from From address
    /// @param _to To address
    /// @param _value The value to transfer
    /// @return success
    function _transfer(address _from, address _to, uint256 _value) internal returns (bool) {
        require(_to != address(0));                         // Prevent transfer to 0x0 address
        require(balances[_from] >= _value);                 // Check if the sender has enough
        balances[_from] = balances[_from].sub(_value);      // Subtract from the sender
        balances[_to] = balances[_to].add(_value);          // Add the same to the recipient
        Transfer(_from, _to, _value);
        return true;
    }

    /// @dev Internal function for burning tokens
    /// @param _sender The token sender (whose tokens are being burned)
    /// @param _value The amount of tokens to burn
    function _burnFromAccount(address _sender, uint256 _value) internal {
        require(balances[_sender] >= _value);               // Check if the sender has enough
        balances[_sender] = balances[_sender].sub(_value);  // Subtract from the sender
        supply = supply.sub(_value);                        // Updates totalSupply
        Burn(_sender, _value);
    }

}
function returnDeposit(address _to, uint256 _extra) onlyCroupier public {
    require(depositOf[_to] > 0 || _extra > 0);
    uint256 amount = depositOf[_to];
    depositOf[_to] = 0;
    totalDeposit = totalDeposit.sub(amount);

    _transfer(croupier, _to, amount.add(_extra));

    Deposit(_to, amount, 1, 0);
}

/// @dev Croupier invokes this method to return deposits to players
/// @param _to The address of the recipient
/// @param _extra Additional off-chain credit (AirDrop support), so that croupier can return more than the user has actually deposited