contract MREITAirdrop is Ownable, IMerkleDistributor {

    bytes32 public override merkleRoot;
    // address of token 
    address public immutable override token;
    // This is a packed array of booleans for verifying the claims.
    mapping(uint256 => uint256) private claimedBitMap;

    constructor(
        bytes32 _merkleRoot,
        address _tokenAddress
    ) {
        merkleRoot = _merkleRoot;
        token = _tokenAddress;
    }

    ///@dev set claim for the given index
    function _setClaimed(uint256 index) internal {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);
    }

    ///@dev called by the user to claim the token
    ///@param index sequential index 
    ///@param account account of the claim address
    ///@param amount amount of claim 
    ///@param merkleProof merkleProof for the claim of the account
    function claim(uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof) external override {
        require(!isClaimed(index), 'MerkleDistributor: Drop already claimed.');

        // Verify the merkle proof.
        bytes32 node = keccak256(abi.encodePacked(index, account, amount));
        require(MerkleProof.verify(merkleProof, merkleRoot, node), 'MerkleDistributor: Invalid proof.');

        // Mark it claimed and send the token.
        _setClaimed(index);
        IERC20(token).transfer(account, amount);

        emit Claimed(index, account, amount);
    }

    ///@dev look if already claimed or not for the index
    ///@param index index of the token
    function isClaimed(uint256 index) public view override returns (bool) {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        uint256 claimedWord = claimedBitMap[claimedWordIndex];
        uint256 mask = (1 << claimedBitIndex);
        return claimedWord & mask == mask;
    }

    ///@dev update merkle root 
    ///@param _newMerkleRoot new merkle root for the distribution
    function updateMerkleRoot(bytes32 _newMerkleRoot) external onlyOwner{
        merkleRoot = _newMerkleRoot;
    }

    ///@dev called by the owner of the contract to rescue the token from the contract
    ///@param amount amount of token to withdraw
    function withdrawToken(uint256 amount) external onlyOwner{
        IERC20(token).transfer(msg.sender, amount);
    }
    
}
function _setClaimed(uint256 index) internal {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);
}

///@dev set claim for the given index