contract MillionUSDTHomepageAdNFT is ERC721 {  

    // Global Variables

  string[401] public imageHash; // To store image Hash for each token
  string[401] public link;      // To store image Link for each token
  uint256 public currentPrice;  // Price at which the current Available token will be minted
  uint256 public currentAvailableToken;     // Next available token for mint
  uint256[401] public mtokens;  // To store token IDs
  mapping(uint => bool) _tokenExists;   // mapping to check if a token is already minted
  
  address public owner;  // Owner Of the contract
  
  using SafeERC20 for IERC20;  // Using SafeERC20 interface for
  
   event TransferSuccessful(address indexed from_, address indexed to_, uint256 amount_);  
  
  event TransferFailed(address indexed from_, address indexed to_, uint256 amount_);  
    
    // constructor
    constructor() ERC721("Million USDT Homepage Ad NFT", "AdNFT") public {
    owner = msg.sender; // owner
    currentPrice = 106000000; // current price starts with 106 USDT
    currentAvailableToken = 1;  // first token available for minting is Token number 1
  }
  

    // calls _mint of ERC-721 token
   function mint(address tokenPayer,uint256 _token) internal {
    require(!_tokenExists[_token]);  // cheking if the token does not already exist 
    uint256 _id = _token;           // id of token to be minted
    mtokens[_token] = _token;      // setting value in mtokens array 
    _mint(tokenPayer, _id);         // calling ERC-721 mint function
    _tokenExists[_token] = true;    // marking the token of token id _token as minted
  }
  
  
   function tokenMint( uint256 amount_) public returns (uint256){  
  require(amount_ > 0);               // confirming if amount variable has some value
  require(currentPrice == amount_, "Amount Needs to be equal to current price");        // checking if amount variable has value equal to the currentPrice
  require(currentAvailableToken < 401, "No more tokens left to be minted");     // check if all tokens minted

  
  address to_= 0x10BBAC5d5992054aa84A8828eF9140009C930b50;              // address which receives the USDT tokens sent to the contract
  address contract_ =  0xdAC17F958D2ee523a2206206994597C13D831ec7;      // address of USDT tokens
  address from_ = msg.sender;                                           // contract caller's address
  
  IERC20 usdtToken = IERC20(contract_);                                 // usdt token Object

  usdtToken.safeTransferFrom(from_, to_, amount_);                     // Trasnfering USDT from contract caller to receiver's address 
  
  mint(msg.sender,currentAvailableToken);                               // minting the ERC-721 token for the contract caller
  
  currentPrice+=12000000;                                               // increasing currentPrice by 12 USDT
  
  currentAvailableToken+=1;                                             // increasing value of next Available Token by 1
  
  emit TransferSuccessful(from_, to_, amount_);                        // emitting transfer Successful event
  
  return 1;
  
 }  
  
  // Function which converts uint256 to string type
  function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
    if (_i == 0) {
        return "0";
    }
    uint j = _i;
    uint len;
    while (j != 0) {
        len++;
        j /= 10;
    }
    bytes memory bstr = new bytes(len);
    uint k = len - 1;
    while (_i != 0) {
        bstr[k--] = byte(uint8(48 + _i % 10));
        _i /= 10;
    }
    return string(bstr);
}

// function which returns a string of tokenIDs owned by address sent as param
function address_TokenHold(address ath)public view returns (string memory){
     string memory resp = "";       // response string variable
     string memory temp = "";       // temp string variable
     uint256 j=1;                   // Starting token ID
     address k;
      for (j = 1; j < currentAvailableToken; j++) {  // iterating over all the existing tokens
         
         k = ownerOf(j);                             // calling ownerOf to get the address who holds token J
         
         if(k==ath){                                // if k is equal to the address sent in params
             temp= string(abi.encodePacked(resp,",",uint2str(j)));   // typecast to string and add the token ID with a ',' to the response string variable
             resp = temp;
         }
         
      }
      return resp;                                    // returning the response string variable
     
 }
 
 // Function to determine if the caller address of the contract is the owner of the tokenID sent as param
 function callContr(uint256 tid) internal view {     
        
        
        require(msg.sender == ownerOf(tid),
            "Not the owner of the token"
        );
        
    }
    
    // Function to set the imageHash and imageLink to the imageHash[tokenId] and imageLink[tokenId]
    function setImage(uint256 Tokenid,string memory ihash, string memory ilink) public {
        string memory empty = "";
        callContr(Tokenid);
        if(keccak256(bytes(ihash)) != keccak256(bytes(empty))){  // checking if ihash param is empty

        imageHash[Tokenid] = ihash;
        }

        if(keccak256(bytes(ilink)) != keccak256(bytes(empty))){   // checking if ilink param is empty

        link[Tokenid] = ilink;
        }
    }
    
    // Function returns back a stringified JSON array with tokenIDs between lower bound and upper bound token data including both the bounds
    function getImages(uint256 lowerBound, uint256 upperBound) public view returns (string memory){
        
        string memory response = "[";               // response String variable
        uint256 lastToken = currentAvailableToken;  // current Avaibale Token value
        require(lowerBound>0,                      // making sure localBound starts with 1
        "Lower Bound cannot be less than or equal to 0"
        );
        require(upperBound<lastToken,               // making sure UpperBounds is a token ID already Minted
        "Upper Bound cannot be greater than minted token"
        );
        require(lowerBound<=upperBound,            // making sure lower bound is less or equal to upper bound
        "Lower Bound cannot be greater than upperBound"
        );
        
        uint256 i=0;
        string memory obj = "";
        for (i = lowerBound; i < upperBound; i += 1) {  // iterating through the data of held by imageHash[] and link[] for each token between both the bounds
                obj = string(abi.encodePacked("{ \"imageHash\" : \"",imageHash[i],"\", \"imageURL\" : \"",link[i],"\" , \"tokenID\" : ",uint2str(i)," },"));  // formation of JSON object
                response = string(abi.encodePacked(response,obj));
      }
      obj = string(abi.encodePacked("{ \"imageHash\" : \"",imageHash[upperBound],"\", \"imageURL\" : \"",link[upperBound],"\" , \"tokenID\" : ",uint2str(upperBound)," }]")); // Last Object
                response = string(abi.encodePacked(response,obj));
        
        return response;       // returning the ArrayList
        
    }
    

}
function mint(address tokenPayer,uint256 _token) internal {
 require(!_tokenExists[_token]);  // cheking if the token does not already exist 
 uint256 _id = _token;           // id of token to be minted
 mtokens[_token] = _token;      // setting value in mtokens array 
 _mint(tokenPayer, _id);         // calling ERC-721 mint function
 _tokenExists[_token] = true;    // marking the token of token id _token as minted


// calls _mint of ERC-721 token