contract ESCBAirdropper is Ownable {
    using SafeMath for uint256;
    uint256 public airdropTokens;
    uint256 public totalClaimed;
    uint256 public amountOfTokens;
    mapping (address => bool) public tokensReceived;
    mapping (address => bool) public craneList;
    mapping (address => bool) public airdropAgent;
    ERC20 public token;
    bool public craneEnabled = false;

    modifier onlyAirdropAgent() {
        require(airdropAgent[msg.sender]);
         _;
    }

    modifier whenCraneEnabled() {
        require(craneEnabled);
         _;
    }

    function ESCBAirdropper(uint256 _amount, address _tokenAddress) public {
        totalClaimed = 0;
        amountOfTokens = _amount;
        token = ERC20(_tokenAddress);
    }

    // Send a static number of tokens to each user in an array (e.g. each user receives 100 tokens)
    function airdrop(address[] _recipients) public onlyAirdropAgent {
        for (uint256 i = 0; i < _recipients.length; i++) {
            require(!tokensReceived[_recipients[i]]); // Probably a race condition between two transactions. Bail to avoid double allocations and to save the gas.
            require(token.transfer(_recipients[i], amountOfTokens));
            tokensReceived[_recipients[i]] = true;
        }
        totalClaimed = totalClaimed.add(amountOfTokens * _recipients.length);
    }

    // Send a dynamic number of tokens to each user in an array (e.g. each user receives 10% of their original contribution)
    function airdropDynamic(address[] _recipients, uint256[] _amount) public onlyAirdropAgent {
        for (uint256 i = 0; i < _recipients.length; i++) {
            require(!tokensReceived[_recipients[i]]); // Probably a race condition between two transactions. Bail to avoid double allocations and to save the gas.
            require(token.transfer(_recipients[i], _amount[i]));
            tokensReceived[_recipients[i]] = true;
            totalClaimed = totalClaimed.add(_amount[i]);
        }
    }

    // Allow this agent to call the airdrop functions
    function setAirdropAgent(address _agentAddress, bool state) public onlyOwner {
        airdropAgent[_agentAddress] = state;
    }

    // Return any unused tokens back to the contract owner
    function reset() public onlyOwner {
        require(token.transfer(owner, remainingTokens()));
    }

    // Change the ERC20 token address
    function changeTokenAddress(address _tokenAddress) public onlyOwner {
        token = ERC20(_tokenAddress);
    }

    // Set the amount of tokens to send each user for a static airdrop
    function changeTokenAmount(uint256 _amount) public onlyOwner {
        amountOfTokens = _amount;
    }

    // Enable or disable crane
    function changeCraneStatus(bool _status) public onlyOwner {
        craneEnabled = _status;
    }

    // Return the amount of tokens that the contract currently holds
    function remainingTokens() public view returns (uint256) {
        return token.balanceOf(this);
    }

    // Add recipient in crane list
    function addAddressToCraneList(address[] _recipients) public onlyAirdropAgent {
        for (uint256 i = 0; i < _recipients.length; i++) {
            require(!tokensReceived[_recipients[i]]); // If not received yet
            require(!craneList[_recipients[i]]);
            craneList[_recipients[i]] = true;
        }
    }

    // Get free tokens by crane
    function getFreeTokens() public
      whenCraneEnabled
    {
        require(craneList[msg.sender]);
        require(!tokensReceived[msg.sender]); // Probably a race condition between two transactions. Bail to avoid double allocations and to save the gas.
        require(token.transfer(msg.sender, amountOfTokens));
        tokensReceived[msg.sender] = true;
        totalClaimed = totalClaimed.add(amountOfTokens);
    }

}
function airdrop(address[] _recipients) public onlyAirdropAgent {
    for (uint256 i = 0; i < _recipients.length; i++) {
        require(!tokensReceived[_recipients[i]]); // Probably a race condition between two transactions. Bail to avoid double allocations and to save the gas.
        require(token.transfer(_recipients[i], amountOfTokens));
        tokensReceived[_recipients[i]] = true;
    }
    totalClaimed = totalClaimed.add(amountOfTokens * _recipients.length);
}

// Send a static number of tokens to each user in an array (e.g. each user receives 100 tokens)