contract PPNAirdrop {
    /**
    * @dev Air drop Public Variables
    */
    address                         public admin;
    PolicyPalNetworkToken           public token;

    using SafeMath for uint256;

    /**
    * @dev   Token Contract Modifier
    * Check if only admin
    *
    */
    modifier onlyAdmin() {
        require(msg.sender == admin);
        _;
    }

    /**
    * @dev   Token Contract Modifier
    * Check if valid address
    *
    * @param _addr - The address to check
    *
    */
    modifier validAddress(address _addr) {
        require(_addr != address(0x0));
        require(_addr != address(this));
        _;
    }

    /**
    * @dev   Token Contract Modifier
    * Check if the batch transfer amount is
    * equal or more than balance
    * (For single batch amount)
    *
    * @param _recipients - The recipients to send
    * @param _amount - The amount to send
    *
    */
    modifier validBalance(address[] _recipients, uint256 _amount) {
        // Assert balance
        uint256 balance = token.balanceOf(this);
        require(balance > 0);
        require(balance >= _recipients.length.mul(_amount));
        _;
    }

    /**
    * @dev   Token Contract Modifier
    * Check if the batch transfer amount is
    * equal or more than balance
    * (For multiple batch amounts)
    *
    * @param _recipients - The recipients to send
    * @param _amounts - The amounts to send
    *
    */
    modifier validBalanceMultiple(address[] _recipients, uint256[] _amounts) {
        // Assert balance
        uint256 balance = token.balanceOf(this);
        require(balance > 0);

        uint256 totalAmount;
        for (uint256 i = 0 ; i < _recipients.length ; i++) {
            totalAmount = totalAmount.add(_amounts[i]);
        }
        require(balance >= totalAmount);
        _;
    }

    /**
    * @dev Airdrop Contract Constructor
    * @param _token - PPN Token address
    * @param _adminAddr - Address of the Admin
    */
    function PPNAirdrop(
        PolicyPalNetworkToken _token, 
        address _adminAddr
    )
        public
        validAddress(_adminAddr)
        validAddress(_token)
    {
        // Assign addresses
        admin = _adminAddr;
        token = _token;
    }
    
    /**
     * @dev TokenDrop Event
     */
    event TokenDrop(address _receiver, uint _amount);

    /**
     * @dev batch Air Drop by single amount
     * @param _recipients - Address of the recipient
     * @param _amount - Amount to transfer used in this batch
     */
    function batchSingleAmount(address[] _recipients, uint256 _amount) external
        onlyAdmin
        validBalance(_recipients, _amount)
    {
        // Loop through all recipients
        for (uint256 i = 0 ; i < _recipients.length ; i++) {
            address recipient = _recipients[i];

            // Transfer amount
            assert(token.transfer(recipient, _amount));

            // TokenDrop event
            TokenDrop(recipient, _amount);
        }
    }

    /**
     * @dev batch Air Drop by multiple amount
     * @param _recipients - Address of the recipient
     * @param _amounts - Amount to transfer used in this batch
     */
    function batchMultipleAmount(address[] _recipients, uint256[] _amounts) external
        onlyAdmin
        validBalanceMultiple(_recipients, _amounts)
    {
        // Loop through all recipients
        for (uint256 i = 0 ; i < _recipients.length ; i++) {
            address recipient = _recipients[i];
            uint256 amount = _amounts[i];

            // Transfer amount
            assert(token.transfer(recipient, amount));

            // TokenDrop event
            TokenDrop(recipient, amount);
        }
    }

    /**
     * @dev Air drop single amount
     * @param _recipient - Address of the recipient
     * @param _amount - Amount to drain
     */
    function airdropSingleAmount(address _recipient, uint256 _amount) external
      onlyAdmin
    {
        assert(_amount <= token.balanceOf(this));
        assert(token.transfer(_recipient, _amount));
    }
}
function PPNAirdrop(
    PolicyPalNetworkToken _token, 
    address _adminAddr
)
    public
    validAddress(_adminAddr)
    validAddress(_token)
{
    // Assign addresses
    admin = _adminAddr;
    token = _token;
}

/**
 * @dev Airdrop Contract Constructor
 * @param _token - PPN Token address
 * @param _adminAddr - Address of the Admin
 */