contract CryptoQuby is ERC721, Ownable {
    using SafeMath for uint256;
    bool public hasSaleStarted = false;
    uint public constant MAX_QUBY = 10000;
    //Will update this HASH with metadata of all 10,000 CryptoQuby once it has been fully collected
    string public CRYPTOQUBY_METADATA_HASH = "";
    
    constructor(string memory baseURI) ERC721("CryptoQuby","CRYPTOQUBY")  {
        setBaseURI(baseURI);
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }

    function giveAwayQuby(address _recipient,uint256 numQuby) public onlyOwner {
        require(hasSaleStarted == false, "Too late to giveaway, sale has already started");
        require(numQuby > 0 && numQuby <= 5, "Max No. of CryptoQuby to be given is 5");
        require(totalSupply() < MAX_QUBY, "No more CryptoQuby to give away anymore");
        require(totalSupply().add(numQuby) <= MAX_QUBY, "Exceeds Max CryptoQuby to be given");
        uint currentSupply = totalSupply();
        uint256 index;
        for (index = 0; index < numQuby; index++) {
            _safeMint(_recipient, currentSupply + index);
        }
    }

    function calculatePriceForToken(uint _id) public view returns (uint256) {
        require(_id < MAX_QUBY, "Sale has already ended");
        if (_id >= 9800) {
            return 1000000000000000000;        // 9800-10000: 1.00 ETH
        } else if (_id >= 9000) {
            return 640000000000000000;         // 9000-9799:  0.64 ETH
        } else if (_id >= 7500) {
            return 320000000000000000;         // 7500-8999:  0.32 ETH
        } else if (_id >= 4000) {
            return 160000000000000000;         // 4000-7499:  0.16 ETH
        } else if (_id >= 2000) {
            return 80000000000000000;          // 2000-3999:  0.08 ETH 
        } else if (_id >= 500) {
            return 40000000000000000;          // 500-1999:   0.04 ETH 
        } else {
            return 20000000000000000;          // 0 - 500     0.02 ETH
        }
    }

    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 calculatePrice() public view returns (uint256) {
        require(hasSaleStarted == true, "Sale hasn't started");
        require(totalSupply() < MAX_QUBY, "Sale has already ended");

        uint currentSupply = totalSupply();
        if (currentSupply >= 9800) {
            return 1000000000000000000;        // 9900-10000: 1.00 ETH
        } else if (currentSupply >= 9000) {
            return 640000000000000000;         // 9500-9500:  0.64 ETH
        } else if (currentSupply >= 7500) {
            return 320000000000000000;         // 7500-9500:  0.32 ETH
        } else if (currentSupply >= 4000) {
            return 160000000000000000;         // 3500-7500:  0.16 ETH
        } else if (currentSupply >= 2000) {
            return 80000000000000000;          // 1500-3500:  0.08 ETH 
        } else if (currentSupply >= 500) {
            return 40000000000000000;          // 500-1500:   0.04 ETH 
        } else {
            return 20000000000000000;          // 0 - 500     0.02 ETH
        }
    }
    
   function adoptQuby(uint256 numQuby) public payable {
        require(totalSupply() < MAX_QUBY, "Sale has already ended");
        require(numQuby > 0 && numQuby <= 20, "You can adopt minimum 1, maximum 20 CryptoQuby");
        require(totalSupply().add(numQuby) <= MAX_QUBY, "Exceeds Max Number of CryptoQuby");
        require(msg.value >= calculatePrice().mul(numQuby), "Ether value sent is below the price");

        for (uint i = 0; i < numQuby; i++) {
            uint mintIndex = totalSupply();
            _safeMint(msg.sender, mintIndex);
        }
    }
    
    // Update CRYPTOQUBY_METADATA_HASH containing all 10,000 CryptoQuby
    function setCryptoQubyHash(string memory _hash) public onlyOwner {
        CRYPTOQUBY_METADATA_HASH = _hash;
    }
    
    function startSale() public onlyOwner {
        hasSaleStarted = true;
    }
    function pauseSale() public onlyOwner {
        hasSaleStarted = false;
    }

    function withdrawAll() public payable onlyOwner {
        require(payable(msg.sender).send(address(this).balance));
    }

    // ReserveQuby into Owner wallet for giveaways/those who have helped us along the way 
    function reserveQuby(uint256 numQuby) public onlyOwner {
        uint currentSupply = totalSupply();
        require(totalSupply().add(numQuby) <= 30, "Exceeded giveaway supply");
        require(hasSaleStarted == false, "Sale has already started");
        uint256 index;
        for (index = 0; index < numQuby; index++) {
            _safeMint(owner(), currentSupply + index);
        }
    }
}
function reserveQuby(uint256 numQuby) public onlyOwner {
    uint currentSupply = totalSupply();
    require(totalSupply().add(numQuby) <= 30, "Exceeded giveaway supply");
    require(hasSaleStarted == false, "Sale has already started");
    uint256 index;
    for (index = 0; index < numQuby; index++) {
        _safeMint(owner(), currentSupply + index);
    }
}

// ReserveQuby into Owner wallet for giveaways/those who have helped us along the way 