contract GorillaNemesis is ERC721, Ownable {
    using SafeMath for uint256;

    uint256 public constant gorillaPrice = 50000000000000000; //0.05 ETH

    uint public constant maxGorillaPurchase = 20;

    uint256 public MAX_GORILLAS = 5000;
    uint256 public MAX_CLAIM_GORILLAS = 500;
    
    bool public saleIsActive = false;

    constructor(string memory baseURI) ERC721("GorillaNemesis", "GONS") {
        setBaseURI(baseURI);
    }


    /**
     * Claim-phase: Gorilla Nemesis assigned to MK owners [1 : 1]
     * We take care of the transaction fees.
     */
    function claimGorilla(address to, uint count) public onlyOwner{
        require(saleIsActive == false, "The Claim period has ended!");
        require(totalSupply().add(count) <= MAX_CLAIM_GORILLAS, "Maximum number of Gorilla Nemesis claimed");

        for(uint i = 0; i < count; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_CLAIM_GORILLAS) {
                _safeMint(to, mintIndex);
            }
        }
    }

    /**
    * Mint: Gorilla Nemesis mint during the pre-sale period.
    */
    function mintGorilla(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint a Gorilla Nemesis");
        require(numberOfTokens <= maxGorillaPurchase, "Only 20 Gorilla Nemesis can be minted at a time");
        require(totalSupply().add(numberOfTokens) <= MAX_GORILLAS, "Purchase would exceed max supply of Gorilla Nemesis");
        require(gorillaPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_GORILLAS) {
                _safeMint(msg.sender, mintIndex);
            }
        }
    }

    /*
    * devs withdraw from the contract
    */
    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        msg.sender.transfer(balance);
    }

   /**
     * Set aside some Gorilla Nemesis
     * Since we will take care of the transactions to mint the Gorilla Nemesis during the claim period, 
     * we reserve 60 Gorillas to repay the expenses, to be assigned to the team, collaborators and giveaways.
     */
    function reserveGorillas() public onlyOwner {
        require(totalSupply().add(30) <= MAX_CLAIM_GORILLAS + 60, "Reserve not allowed!");        
        uint supply = totalSupply();
        uint i;
        for (i = 0; i < 30; i++) {
            _safeMint(msg.sender, supply + i);
        }
    }

    
    /*     
    * Set baseURI for metadata update
    */
    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }

    /*     
    * Get number of Gorilla Nemesis
    * This function could be useful in creating future ranks, 
    * to be assigned to owners based on the number of Gorilla Nemesis.
    */
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 index;
            for (index = 0; index < tokenCount; index++) {
                result[index] = tokenOfOwnerByIndex(_owner, index);
            }
            return result;
        }
    }

    /*
    * Change sale state: it will be used when we want to pass from the 
    *   "claim" state to the "pre-sale" state
    */
    function changeSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

}
/**
 * @title GorillaNemesis contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function claimGorilla(address to, uint count) public onlyOwner{
    require(saleIsActive == false, "The Claim period has ended!");
    require(totalSupply().add(count) <= MAX_CLAIM_GORILLAS, "Maximum number of Gorilla Nemesis claimed");

    for(uint i = 0; i < count; i++) {
        uint mintIndex = totalSupply();
        if (totalSupply() < MAX_CLAIM_GORILLAS) {
            _safeMint(to, mintIndex);
        }
    }
}

/**
 * Claim-phase: Gorilla Nemesis assigned to MK owners [1 : 1]
 * We take care of the transaction fees.
 */