contract CRYPTINIES is ERC721, Ownable {
    using SafeMath for uint256;
    uint public constant MAX_CRYPTINIES = 9999;
    bool public hasSaleStarted = false;
    address public constant DEVELOPER_ADDRESS = 0x16eFE37c0c557D4B1D8EB76d11E13616d2b52eAF;
    address public constant CHARITY_ADDRESS = 0x2a408eB3538e54fE60E6bb591826B16575537faF;
    uint public DEVELOPER_FEE = 5;
    uint public CHARITY_FEE = 10;
    uint constant SHARE_SUM = 100;
    
    
    // The IPFS Hash of all tokens will be added here when all of them are minted.
    string public METADATA_PROVENANCE_HASH = "";
    
    
    constructor() ERC721("CRYPTINIES","CRYPTINIES")  {
        setBaseURI("https://cryptinies.com/api/");
        
        //Token 0 goes to Cryptinies team.
        _safeMint(address(0xB2d376a5a1665c692D306c1f784CA6E96c497702), 0);
        //Token 1 goes to Developer(kodbilen.eth)
        _safeMint(address(0x16eFE37c0c557D4B1D8EB76d11E13616d2b52eAF), 1);
    }
    
    function getNFTPrice() public view returns (uint256) {
        require(hasSaleStarted == true, "Sale hasn't started yet");
        require(totalSupply() < MAX_CRYPTINIES, "Sale has already ended");


        return 40000000000000000;

    }
   
    function mintCRYPTINIES(uint256 numCryptinies) public payable{
        require(hasSaleStarted == true, "Sale hasn't started yet");
        require(totalSupply() < MAX_CRYPTINIES, "Sale has already ended");
        require(numCryptinies > 0 && numCryptinies <= 20, "You can adopt minimum 1, maximum 20 Cryptinies");
        require(totalSupply().add(numCryptinies) <= MAX_CRYPTINIES, "Exceeds MAX_CRYPTINIES");
        require(getNFTPrice().mul(numCryptinies) == msg.value, "Ether value sent is not correct");
      
        for (uint i = 0; i < numCryptinies; i++){
            uint mintIndex = totalSupply();
            _safeMint(msg.sender, mintIndex);
        }
    }

    
    
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array
            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;
        }
    }
    
    
    function setProvenanceHash(string memory _hash) public onlyOwner {
        METADATA_PROVENANCE_HASH = _hash;
    }
    
    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }
    
    function startDrop() public onlyOwner {
        hasSaleStarted = true;
    }
    
    function pauseDrop() public onlyOwner {
        hasSaleStarted = false;
    }
    
    
    
    // %10 Charity
    // %5 DevDeveloper
    // %85 Owner
    
    function withdrawAll() public payable onlyOwner {
        
        uint256 balance = address(this).balance;

        uint toDeveloper = (balance * DEVELOPER_FEE) / SHARE_SUM;
        uint toCharity = (balance * CHARITY_FEE) / SHARE_SUM;
        uint toOwner = balance - (toDeveloper + toCharity);

        payable(DEVELOPER_ADDRESS).transfer(toDeveloper);
        payable(CHARITY_ADDRESS).transfer(toCharity);
        payable(msg.sender).transfer(toOwner);
        assert(address(this).balance == 0);
    }
}
function withdrawAll() public payable onlyOwner {
        
    uint256 balance = address(this).balance;

    uint toDeveloper = (balance * DEVELOPER_FEE) / SHARE_SUM;
    uint toCharity = (balance * CHARITY_FEE) / SHARE_SUM;
    uint toOwner = balance - (toDeveloper + toCharity);

    payable(DEVELOPER_ADDRESS).transfer(toDeveloper);
    payable(CHARITY_ADDRESS).transfer(toCharity);
    payable(msg.sender).transfer(toOwner);
    assert(address(this).balance == 0);
}

// %10 Charity
// %5 DevDeveloper
// %85 Owner