contract CuriousAxolotlNFT is ERC721, Ownable {
    
    using SafeMath for uint256;
    
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    event licenseisLocked(string _licenseText);

    string public AXOLOTL_PROVENANCE = "QmcXvN9tph2HKhMCr3jrcXr1BUdiWjhdR4M2AVnxGHAvvh"; // IPFS URL WILL BE ADDED WHEN AXOLOTLs ARE ALL SOLD OUT

    bool public saleIsActive = false;
    
    mapping(uint => string) public axolotlNames;

    using Strings for uint256;

    string public LICENSE_TEXT = "MIT"; // IT IS WHAT IT SAYS
    
    bool licenseLocked = false; // TEAM CAN'T EDIT THE LICENSE AFTER THIS GETS TRUE

    uint256 public constant axolotlPrice = 20000000000000000; // 0.020 ETH

    uint public constant maxAxolotlPurchase = 20;

    // Reserve 20 Axolotls for team - Giveaways/Prizes etc
    uint public axolotlReserve = 20;

    uint256 public constant MAX_AXOLOTL = 1000;
    
    event axolotlNameChange(address _by, uint _tokenId, string _name);

    // the name and symbol for the NFT
    constructor() public ERC721("CuriousAxolotl", "AXOLOTL") {}


    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        msg.sender.transfer(balance);
    }

    function reserveAxolotls(address _to, uint256 _reserveAmount) public onlyOwner {        
        uint supply = totalSupply();
        require(_reserveAmount > 0 && _reserveAmount <= axolotlReserve, "Not enough reserve left for team");
        for (uint i = 0; i < _reserveAmount; i++) {
            _safeMint(_to, supply + i);
        }
        axolotlReserve = axolotlReserve.sub(_reserveAmount);
    }
    
    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }
    
    // Returns the license for tokens
    function tokenLicense(uint _id) public view returns(string memory) {
        require(_id < totalSupply(), "CHOOSE A AXOLOTL WITHIN RANGE");
        return LICENSE_TEXT;
    }
    
    // Locks the license to prevent further changes 
    function lockLicense() public onlyOwner {
        licenseLocked =  true;
        emit licenseisLocked(LICENSE_TEXT);
    }

    // Change the license
    function changeLicense(string memory _license) public onlyOwner {
        require(licenseLocked == false, "License already locked");
        LICENSE_TEXT = _license;
    }

    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }
    
    // Create a function to mint/create the NFT

    function mintCuriousAxolotl(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint Axolotl");
        require(numberOfTokens > 0 && numberOfTokens <= maxAxolotlPurchase, "Can only mint 20 tokens at a time");
        require(totalSupply().add(numberOfTokens) <= MAX_AXOLOTL, "Purchase would exceed max supply of Axolotls");
        require(msg.value >= axolotlPrice.mul(numberOfTokens), "Ether value sent is not correct");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_AXOLOTL) {
                _safeMint(msg.sender, mintIndex);
            }
        }

    }
    
    // GET ALL AXOLOTL OF A WALLET AS AN ARRAY OF STRINGS.
    function axolotlNamesOfOwner(address _owner) external view returns(string[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array
            return new string[](0);
        } else {
            string[] memory result = new string[](tokenCount);
            uint256 index;
            for (index = 0; index < tokenCount; index++) {
                result[index] = axolotlNames[ tokenOfOwnerByIndex(_owner, index) ] ;
            }
            return result;
        }
    }
}
// Accessing the Ownable method ensures that only the creator of the smart contract can interact with it
function mintCuriousAxolotl(uint numberOfTokens) public payable {
    require(saleIsActive, "Sale must be active to mint Axolotl");
    require(numberOfTokens > 0 && numberOfTokens <= maxAxolotlPurchase, "Can only mint 20 tokens at a time");
    require(totalSupply().add(numberOfTokens) <= MAX_AXOLOTL, "Purchase would exceed max supply of Axolotls");
    require(msg.value >= axolotlPrice.mul(numberOfTokens), "Ether value sent is not correct");
        
    for(uint i = 0; i < numberOfTokens; i++) {
        uint mintIndex = totalSupply();
        if (totalSupply() < MAX_AXOLOTL) {
            _safeMint(msg.sender, mintIndex);
        }
    }

}

// Create a function to mint/create the NFT