contract CryptoFlyz is ERC721, Ownable, PaymentSplitter {

    bool public mintIsActive = true;
    uint256 public tokenPrice = 0;
    uint256 public publicTokenPrice = 42000000000000000;
    uint256 public constant maxTokens = 7025;
    uint256 public constant maxMintsPerTx = 10;
    string private _contractURI;
    uint256 public tokenCount=1;
    bool public devMintLocked = false;
    bool private initialized = false;
    bool public publicMintLocked = true;

    //Parent NFT Contract
    //mainnet address
	address public nftAddress = 0x1CB1A5e65610AEFF2551A50f76a87a7d3fB649C6;
	//rinkeby address
	//address public nftAddress = 0x70BC4cCb9bC9eF1B7E9dc465a38EEbc5d73740FB;
    nftInterface nftContract = nftInterface(nftAddress);

    constructor() public ERC721("CryptoFlyz", "FLYZ") {}

    function initializePaymentSplitter (address[] memory payees, uint256[] memory shares_) external onlyOwner {
        require (!initialized, "Payment Split Already Initialized!");
        require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
        initialized=true;
    }

    //Set Base URI
    function setBaseURI(string memory _baseURI) external onlyOwner {
        _setBaseURI(_baseURI);
    }

    function flipMintState() public onlyOwner {
        mintIsActive = !mintIsActive;
    }

    function setContractURI(string memory contractURI_) external onlyOwner {
        _contractURI = contractURI_;
    }

    function contractURI() public view returns (string memory) {
        return _contractURI;
    }

    //Private sale minting (reserved for Toadz)
    function mintWithToad(uint256 nftId) external {
        require(mintIsActive, "CryptoFlyz must be active to mint");
        require(tokenCount - 1 + 1 <= maxTokens, "Minting would exceed supply");
        require(nftContract.ownerOf(nftId) == msg.sender, "Not the owner of this Toad");
        if (nftId >= 1000000) {
            uint256 newID = SafeMath.div(nftId, 1000000);
            newID = SafeMath.add(newID, 6969);
            require(!_exists(newID), "This Toad has already been used.");
            _safeMint(msg.sender, newID);
            tokenCount++;
        } else {
            require(!_exists(nftId), "This Toad has already been used.");
            _safeMint(msg.sender, nftId);
            tokenCount++;
        }
    }

    function multiMintWithnft(uint256 [] memory nftIds) public {
        require(mintIsActive, "CryptoFlyz must be active to mint");
        for (uint i=0; i< nftIds.length; i++) {
            require(nftContract.ownerOf(nftIds[i]) == msg.sender, "Not the owner of this Toad");
            if (nftIds[i] >= 1000000) {
                uint256 newID = SafeMath.div(nftIds[i], 1000000);
                newID = SafeMath.add(newID, 6969);
                if(_exists(newID)) {
                    continue;
                } else {
                    _mint(msg.sender, newID);
                    tokenCount++;
                }
            } else {
                if(_exists(nftIds[i])) {
                    continue;
                } else {
                    _mint(msg.sender, nftIds[i]);
                    tokenCount++;
                }
            }
        }
    }

    function mintAllToadz() external {
        require(mintIsActive, "CryptoFlyz must be active to mint");
        uint256 balance = nftContract.balanceOf(msg.sender);
        uint256 [] storage lot;
        for (uint i = 0; i < balance; i++) {
            lot.push(nftContract.tokenOfOwnerByIndex(msg.sender, i));
        }
        multiMintWithnft(lot);
    }

    //Dev mint special tokens
    function mintSpecial(uint256 [] memory specialId) external onlyOwner {        
        require (!devMintLocked, "Dev Mint Permanently Locked");
        for (uint256 i = 0; i < specialId.length; i++) {
            require (specialId[i]!=0);
            _mint(msg.sender,specialId[i]);
        }
    }

    function lockDevMint() public onlyOwner {
        devMintLocked = true;
    }

    function unlockPublicMint() public onlyOwner {
        publicMintLocked = false;
    }

    function updatePublicPrice(uint256 newPrice) public onlyOwner {
        publicTokenPrice = newPrice;
    }

    function mintPublic(uint256 quantity) external payable {
        require(quantity <= maxMintsPerTx, "trying to mint too many at a time!");
        require(tokenCount - 1 + quantity <= maxTokens, "minting this many would exceed supply");
        require(msg.value >= publicTokenPrice * quantity, "not enough ether sent!");
        require(msg.sender == tx.origin, "no contracts please!");
        require(!publicMintLocked, "minting is not open to the public yet!");

        uint256 i = 0;
        for (uint256 j = 1; j < maxTokens + 1; j++) {
            if (i == quantity) {
                break;
            }
            else {
                if (!_exists(j) && i < quantity) {
                    _safeMint(msg.sender, j);
                    i++;
                    tokenCount++;
                }
            }
        }
    }
    
    function multiMintPublic(uint256 [] memory nftIds, uint256 quantity) external payable {
        require(quantity <= maxMintsPerTx, "trying to mint too many at a time!");
        require(tokenCount - 1 + quantity <= maxTokens, "minting this many would exceed supply");
        require(msg.value >= publicTokenPrice * quantity, "not enough ether sent!");
        require(msg.sender == tx.origin, "no contracts please!");
        require(!publicMintLocked, "minting is not open to the public yet!");
        for (uint i=0; i< nftIds.length; i++) {
            if (nftIds[i] >= 1000000) {
                uint256 newID = SafeMath.div(nftIds[i], 1000000);
                newID = SafeMath.add(newID, 6969);
                if(_exists(newID)) {
                    continue;
                } else {
                    _safeMint(msg.sender, newID);
                    tokenCount++;
                }
            } else {
                if(_exists(nftIds[i])) {
                    continue;
                } else {
                    _safeMint(msg.sender, nftIds[i]);
                    tokenCount++;
                }
            }
        }
    }

}
/**
 * @title CryptoFlyz contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function mintWithToad(uint256 nftId) external {
    require(mintIsActive, "CryptoFlyz must be active to mint");
    require(tokenCount - 1 + 1 <= maxTokens, "Minting would exceed supply");
    require(nftContract.ownerOf(nftId) == msg.sender, "Not the owner of this Toad");
    if (nftId >= 1000000) {
        uint256 newID = SafeMath.div(nftId, 1000000);
        newID = SafeMath.add(newID, 6969);
        require(!_exists(newID), "This Toad has already been used.");
        _safeMint(msg.sender, newID);
        tokenCount++;
    } else {
        require(!_exists(nftId), "This Toad has already been used.");
        _safeMint(msg.sender, nftId);
        tokenCount++;
    }
}

//Private sale minting (reserved for Toadz)