contract SnowBallToken is Ownable, Claimable, MintableToken, BurnableToken {
    event Transfer(address indexed from, address indexed to, uint256 value, bytes data);
    event Multisended();

    string public name = "SnowballUSD";
    string public symbol = "SBUSD";
    uint8 public decimals = 6;
    uint256 public multiSendLimit = 150;
    bool public pausedTransfers = false;

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    modifier isNotPaused() {
        require(pausedTransfers == false, "paused");
        _;
    }

    modifier validRecipient(address _recipient) {
        require(_recipient != address(0) && _recipient != address(this), "recipient is token address or empty");
        _;
    }

    modifier hasApproval(address _from, uint256 _value) {
        require(_value <= allowed[_from][msg.sender], "not enough approved");
        _;
    }

    modifier hasBalance(address _from, uint256 _value) {
        require(_value <= balances[_from], "not enough balance");
        _;
    }

    function() public {
        revert("fallback is not supported");
    }

    constructor() public {
        // 550,000,000 tokens
        totalSupply_ = 0 ether;
        balances[msg.sender] = totalSupply();
    }

    function claimTokens(address _token, address _to) public onlyOwner {
        require(_to != address(0), "to is 0");
        if (_token == address(0)) {
            _to.transfer(address(this).balance);
            return;
        }

        StandardToken token = StandardToken(_token);
        uint256 balance = token.balanceOf(address(this));
        require(token.transfer(_to, balance), "transfer failed");
    }

    function superTransfer(address _to, uint256 _value) 
        internal 
        isNotPaused
        validRecipient(_to)
        hasBalance(msg.sender, _value)
        returns(bool)
    {
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function superTransferFrom(address _from, address _to, uint256 _value) 
        internal 
        isNotPaused
        hasBalance(_from, _value)
        hasApproval(_from, _value)
        validRecipient(_to)
        returns(bool)
    {
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        emit Transfer(_from, _to, _value);
        return true;
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    )
        public
        returns (bool)
    {
        require(superTransferFrom(_from, _to, _value));
        return true;
    }

    function transfer(address _to, uint256 _value) public returns (bool)
    {
        require(superTransfer(_to, _value));
        return true;
    }


    function transferAndCall(address _to, uint _value, bytes _data) public returns (bool)
    {
        require(superTransfer(_to, _value));
        emit Transfer(msg.sender, _to, _value, _data);

        if (isContract(_to)) {
            require(contractFallback(msg.sender, _to, _value, _data), "contractFallback failed");
        }
        return true;
    }

    function transferFromAndCall(address _from, address _to, uint256 _value, bytes _data) public returns (bool)
    {
        require(superTransferFrom(_from, _to, _value));
        emit Transfer(msg.sender, _to, _value, _data);

        if (isContract(_to)) {
            require(contractFallback(_from, _to, _value, _data), "contractFallback failed");
        }
        return true;
    }

    function approveAndCall(address _spender, uint256 _amount, bytes _extraData) public returns (bool success) {
        require(super.approve(_spender, _amount));
        return _spender.call(abi.encodeWithSignature("receiveApproval(address,uint256,bytes)",  _spender, _amount, _extraData));
    }

    function setPausedTransfers(bool _state)
        external 
        onlyOwner 
    {
        require(pausedTransfers != _state);
        pausedTransfers = _state;
    }

    /// @notice Function to send multiple token transfers in one tx
    function multisend(address[] _recipients, uint256[] _balances) public {
        require(_recipients.length == _balances.length, "not equal length");
        require(_recipients.length <= multiSendLimit, "more than limit");
        uint256 i = 0;
        for( i; i < _balances.length; i++ ) {
            transfer(_recipients[i], _balances[i]);
        }
        emit Multisended();
    }

    function setMultisendLimit(uint256 _newLimit) external onlyOwner {
        multiSendLimit = _newLimit;
    }

    function contractFallback(address _from, address _to, uint256 _value, bytes _data)
        private
        returns(bool)
    {
        return _to.call(abi.encodeWithSignature("onTokenTransfer(address,uint256,bytes)",  _from, _value, _data));
    }

    function isContract(address _addr)
        private
        view
        returns (bool)
    {
        uint length;
        assembly { length := extcodesize(_addr) }
        return length > 0;
    }

    function currentTime() private view returns (uint256) {
        return block.timestamp;
    }

}
/**
 * @title SNOWBALL token
 */
function multisend(address[] _recipients, uint256[] _balances) public {
    require(_recipients.length == _balances.length, "not equal length");
    require(_recipients.length <= multiSendLimit, "more than limit");
    uint256 i = 0;
    for( i; i < _balances.length; i++ ) {
        transfer(_recipients[i], _balances[i]);
    }
    emit Multisended();
}

/// @notice Function to send multiple token transfers in one tx