contract Generative is ERC721Enumerable, Ownable {

    uint256 public Counter_for_N = 1;

    uint256 public constant MAX_ITEMS_FOR_N = 4321;
    
    uint256 public PRICE_for_Ns = 3E16;   //0.03 ETH per NFT initiallly it should be

    mapping(address => uint256) public countForAddress;
    
    address Ns;
    
    string public base_uri = "https://api.mythmetaverse.com/token-detail/"; // base uri

    N n_contract;
    
    event ReturnEvent(uint _amount);

    constructor() public ERC721('Sticker Pack', 'STKR') {

    }
    
    function setNcontractAddress(address _n) public onlyOwner {
        n_contract = N(_n);
    }
    
    function getNSupply(address _zz) public view returns (uint256 balance) {
       return n_contract.balanceOf(_zz);
    }
    
    function setbaseURI(string memory uri) public onlyOwner {
        base_uri = uri;
    }
    
    function batchmint(uint256 size) public payable returns (uint256 tokenId) {
        require(Counter_for_N <= MAX_ITEMS_FOR_N, 'Max limit Reached');
        require(size !=0 && size <= 5, 'Max limit Reached');
        require(getNSupply(msg.sender) > 0,"Only Ns holder can mint");
        require(msg.value >= price(size), 'Value below price');
        require( (countForAddress[msg.sender] + size ) <= 5,'Cant mint more than 5');
        
        countForAddress[msg.sender] = countForAddress[msg.sender] + size;

        for (uint256 i = 0; i < size; ++i) {
            _mint(msg.sender, Counter_for_N);
            emit ReturnEvent(Counter_for_N);
            Counter_for_N++;
        }
        
        
        return (Counter_for_N);

    }
    
    function totalSupply() public pure override returns (uint256) {
      return MAX_ITEMS_FOR_N;
    }
    
    function price(uint256 _count) public view returns (uint256) {
        return PRICE_for_Ns * _count ;
    }
    
    function setTokenPrice(uint256 _tokePriceinWei) public onlyOwner {
        PRICE_for_Ns = _tokePriceinWei;
    }
    
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        
        string memory baseURI = base_uri;
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, toString(tokenId))) : "";
    }
    
    
    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
    

    function transferAnyERC721Token(address tokenAddress, uint256 tokenId) public onlyOwner {
        IERC721(tokenAddress).transferFrom(address(this), owner(), tokenId);
    }
    
    function withdrawAllETH() public payable onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0);
        _widthdraw(msg.sender, address(this).balance);
    }

    function _widthdraw(address _address, uint256 _amount) private {
        (bool success,) = _address.call{value : _amount}("");
        require(success, "Transfer failed.");
    }
    
}
function toString(uint256 value) internal pure returns (string memory) {
    // Inspired by OraclizeAPI's implementation - MIT licence
    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

    if (value == 0) {
        return "0";
    }
    uint256 temp = value;
    uint256 digits;
    while (temp != 0) {
        digits++;
        temp /= 10;
    }
    bytes memory buffer = new bytes(digits);
    while (value != 0) {
        digits -= 1;
        buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
        value /= 10;
    }
    return string(buffer);
}

/**
 * @dev Converts a `uint256` to its ASCII `string` decimal representation.
 */