contract ClaimWearable {
    using SafeMath for uint256;
    
    uint256 public maxSenderBalance;
    address public owner;

    event ClaimedNFT(
        address indexed _caller,
        address indexed _erc721Collection,
        string _wearable
    );
    
    constructor(uint256 _maxSenderBalance) public {
        maxSenderBalance = _maxSenderBalance;
        owner = msg.sender;
    }
    
    function changeMaxSenderBalance(uint256 _maxSenderBalance) external {
        require(msg.sender == owner, "Unauthorized sender");
        maxSenderBalance = _maxSenderBalance;
    }

     /**
     * @dev Claim an NFTs.
     * @notice Claim a `_wearableId` NFT.
     * @param _erc721Collection - collection address
     * @param _wearableId - wearable id
     */
    function claimNFT(ERC721Collection _erc721Collection, string calldata _wearableId) external payable {
        require(_erc721Collection.balanceOf(msg.sender) < maxSenderBalance, "The sender has already reached maxSenderBalance");
        require(
            canMint(_erc721Collection, _wearableId, 1),
            "The amount of wearables to issue is higher than its available supply"
        );

        _erc721Collection.issueToken(msg.sender, _wearableId);

        emit ClaimedNFT(msg.sender, address(_erc721Collection), _wearableId);
    }

    /**
    * @dev Returns whether the wearable can be minted.
    * @param _erc721Collection - collection address
    * @param _wearableId - wearable id
    * @return whether a wearable can be minted
    */
    function canMint(ERC721Collection _erc721Collection, string memory _wearableId, uint256 _amount) public view returns (bool) {
        uint256 balance = balanceOf(_erc721Collection, _wearableId);

        return balance >= _amount;
    }

    /**
     * @dev Returns a wearable's available supply .
     * Throws if the option ID does not exist. May return 0.
     * @param _erc721Collection - collection address
     * @param _wearableId - wearable id
     * @return wearable's available supply
     */
    function balanceOf(ERC721Collection _erc721Collection, string memory _wearableId) public view returns (uint256) {
        bytes32 wearableKey = _erc721Collection.getWearableKey(_wearableId);

        uint256 issued = _erc721Collection.issued(wearableKey);
        uint256 maxIssuance = _erc721Collection.maxIssuance(wearableKey);

        return maxIssuance.sub(issued);
    }
}
function claimNFT(ERC721Collection _erc721Collection, string calldata _wearableId) external payable {
    require(_erc721Collection.balanceOf(msg.sender) < maxSenderBalance, "The sender has already reached maxSenderBalance");
    require(
        canMint(_erc721Collection, _wearableId, 1),
        "The amount of wearables to issue is higher than its available supply"
    );

    _erc721Collection.issueToken(msg.sender, _wearableId);

    emit ClaimedNFT(msg.sender, address(_erc721Collection), _wearableId);
}

/**
 * @dev Claim an NFTs.
 * @notice Claim a `_wearableId` NFT.
 * @param _erc721Collection - collection address
 * @param _wearableId - wearable id
 */