contract StickFighter is ERC721Enumerable, Ownable {
    using Strings for uint256;
    event Mint(address indexed sender, uint256 startWith, uint256 times);

    //supply counters total max supply = totalcount - 1
    uint256 public totalMints;
    uint256 public totalCount = 10001;
   
    //Max mints per batch
    uint256 public maxBatch = 10;

    //Token price of each token converted to WEI
    uint256 public price = 0.05 * 10 ** 18;

    //Token price of each token in the pre sale converted to WEI
    //The presale is reserved for the OG holders
    uint256 public presalePrice = 0.0 ether;

    //String for the baseURI
    string public baseURI;

    //Booleans for the sale and the presale
    bool private saleActive;
    bool private presaleActive;

    //List of addresses that have a number of reserved tokens for presale
    mapping (address => uint16) public presaleAddresses;
    
    //constructor args
    constructor(string memory name_, string memory symbol_, string memory baseURI_) ERC721(name_, symbol_) {
        baseURI = baseURI_;
    }

    //basic functions.
    function _baseURI() internal view virtual override returns (string memory){
        return baseURI;
    }
    function setBaseURI(string memory _newURI) public onlyOwner {
        baseURI = _newURI;
    }

    //Returns a tokenURI of a specific token
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token.");

        string memory baseURI2 = _baseURI();
        return bytes(baseURI2).length > 0
            ? string(abi.encodePacked(baseURI2, tokenId.toString(), ".json")) : '.json';
    }

    //Function to activate or deactivate the sale
    function setSaleActive(bool _start) public onlyOwner {
        saleActive = _start;
    }

    //Function to activate or deactivate the presale
    function setPresaleActive(bool _start) public onlyOwner {
        presaleActive = _start;
    }


    function tokensOfOwner(address owner)
        public
        view
        returns (uint256[] memory)
    {
        uint256 count = balanceOf(owner);
        uint256[] memory ids = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            ids[i] = tokenOfOwnerByIndex(owner, i);
        }
        return ids;
    }
    
    //Exclusive Presale mint for the OG's || Moet nog testen of het goe dgaat met de total suplly
    function mintPresaleToken(uint16 _amount) public payable {
        require( presaleActive,                  "Presale is not active" );
        uint16 reservedAmt = presaleAddresses[msg.sender];
        require( reservedAmt > 0,                "No tokens reserved for your address" );
        require( _amount < reservedAmt,         "max reserved token supply reached!" );
        require( totalMints + _amount < totalCount, "Cannot mint more than max supply" );
        require( msg.value == presalePrice * _amount,   "Wrong amount of ETH sent" );
        presaleAddresses[msg.sender] = reservedAmt - _amount;
        for(uint16 i; i < _amount; i++){
            _safeMint( msg.sender, 1 + totalMints++);
        }
    }

    //Mint function
    function mint(uint16 _amount) public payable {
        require( saleActive,"Sale is not active" );
        require( _amount < maxBatch, "You can only Mint 10 tokens at once" );
        require( totalMints + _amount < totalCount,"Cannot mint more than max supply" );
        require( msg.value == price * _amount,"Wrong amount of ETH sent" );
        for(uint16 i; i < _amount; i++){
            _safeMint( msg.sender, 1+ totalMints++);
        }
    }

    //Set reserved presale spots for OG's
    function setPresaleReservedAddresses(address[] memory _a, uint16[] memory _amount) public onlyOwner {
        uint16 length = uint16(_a.length);
        for(uint16 i; i < length; i++){
            presaleAddresses[_a[i]] = _amount[i];
        }
    }
}
function setPresaleActive(bool _start) public onlyOwner {
    presaleActive = _start;
}

//Function to activate or deactivate the presale