contract dojoWarriors is ERC721, Ownable, PaymentSplitter {
    using Counters for Counters.Counter;
    using SafeMath for uint256;

    Counters.Counter private _tokenIdCounter;
    
    //---------Variables-------------
    //  Max amount of tokens
    uint256 public maxAmntTokens;
    //  Max amount of tokens per transaction
    uint256 public maxTknPerTxs;
    //  Price per NFT
    uint256 public price;
    //  URI control
    string newURI;
    //  Sale is active
    bool public saleIsActive;
    //  URI locked
    bool public URIlocked;
    //  Mint counter per address
    mapping(address => uint) public mintCountPerAddress;
    
    constructor(address[] memory _payees, uint256[] memory _shares) ERC721("Dojo Warriors", "DOJO") PaymentSplitter(_payees, _shares) payable {
        //  Max amount of tokens
        maxAmntTokens = 8888;
        //  Max tokens per transaction
        maxTknPerTxs = 8;
        //  Price per NFT in wei
        price = 70000000000000000 wei;
        //  Deactivate sale
        saleIsActive = false;
        //  Unlock URI
        URIlocked = false;
    }
    
    //  Flip sale state
    function flipSaleState() public onlyOwner{
        saleIsActive = !saleIsActive;
    }
    
    //  Reserve NFTs, this won't cost ETH 
    function reserveNFT(uint256 reservedTokens)public onlyOwner{
        require ((reservedTokens.add(checkMintedTokens()) <= maxAmntTokens), "You are minting more NFTs than there are available, mint less tokens!");
        require (reservedTokens <= 20, "Sorry, the max amount of reserved tokens per transaction is set to 20");
        
        for (uint i=0; i<reservedTokens; i++){
            safeMint(msg.sender);
        }
    }
    
    //  Modify URI
    function changeURI(string calldata _newURI) public onlyOwner{
        require (URIlocked == false, "URI locked, you can't change it anymore");
        newURI = _newURI;
    }

    //  Lock URI
    function lockURI() public onlyOwner {
        require(URIlocked == false, "URI already locked");
        URIlocked = true;
    }
    
    //  Base URI function, this won't be callable, you will use the changeURI function instead
    function _baseURI() internal view override returns (string memory) {
        return newURI;
    }
    
    //  Base mint function, this won't be callable, you will use the mintNFT function instead
    function safeMint(address to) internal{
        _safeMint(to, _tokenIdCounter.current());
    _tokenIdCounter.increment();
    
    }
    //  Check amount of already minted NFTs
    function checkMintedTokens() public view returns(uint256) {
        return(_tokenIdCounter._value);
    }
    
    //  Function to mint tokens, this is the function that you are going to use
    //  instead of safeMint
    function mintNFT(uint256 amountTokens) public payable {
        
        //  Requires that the sale state is active
        require(saleIsActive, "Sale is not active at this moment");
        
        //  Requires that the amount of tokens user wants to mint + already minted tokens don't surpass the available tokens
        require ((amountTokens.add(checkMintedTokens()) <= maxAmntTokens), "You are minting more NFTs than there are available, mint less tokens!");
        require (amountTokens <= maxTknPerTxs, "Sorry, the max amount of tokens per transaction is set to 8");

        //  Requires the NFTs owned by the address to be less than 8, we update the mintCountPerAddress to this value
        if (balanceOf(msg.sender) < 8)  {
            mintCountPerAddress[msg.sender] = balanceOf(msg.sender);
        }
        
        //  Requires the NFT mint count of the user to be 8 NFTs or less
        require (mintCountPerAddress[msg.sender] + amountTokens <= 8, "You are not allowed to mint more than 8 NFTs, but you can buy more on secondary markets.");
        
        //  Requires the correct amount of ETH
        require (msg.value == (price.mul(amountTokens)), "Amount of Ether incorrect, try again.");
        
        //  Internal mint function
        for (uint i=0; i<amountTokens; i++){
            safeMint(msg.sender);
        }

        //  Update the mint count of the user
        mintCountPerAddress[msg.sender] += amountTokens;
    }
}
function mintNFT(uint256 amountTokens) public payable {
        
    //  Requires that the sale state is active
    require(saleIsActive, "Sale is not active at this moment");
        
    //  Requires that the amount of tokens user wants to mint + already minted tokens don't surpass the available tokens
    require ((amountTokens.add(checkMintedTokens()) <= maxAmntTokens), "You are minting more NFTs than there are available, mint less tokens!");
    require (amountTokens <= maxTknPerTxs, "Sorry, the max amount of tokens per transaction is set to 8");

    //  Requires the NFTs owned by the address to be less than 8, we update the mintCountPerAddress to this value
    if (balanceOf(msg.sender) < 8)  {
        mintCountPerAddress[msg.sender] = balanceOf(msg.sender);
    }
        
    //  Requires the NFT mint count of the user to be 8 NFTs or less
    require (mintCountPerAddress[msg.sender] + amountTokens <= 8, "You are not allowed to mint more than 8 NFTs, but you can buy more on secondary markets.");
        
    //  Requires the correct amount of ETH
    require (msg.value == (price.mul(amountTokens)), "Amount of Ether incorrect, try again.");
        
    //  Internal mint function
    for (uint i=0; i<amountTokens; i++){
        safeMint(msg.sender);
    }

    //  Update the mint count of the user
    mintCountPerAddress[msg.sender] += amountTokens;
}

//  Function to mint tokens, this is the function that you are going to use
//  instead of safeMint