contract TigeroContract is ERC721Enumerable, Ownable {

    using SafeMath for uint256;
    address admin;
    uint256 public maxTigeroPurchase = 30;
    uint256 public tigeroPrice = 0; //0 ETH
    uint256 public maxTigeros = 10000;
    bool public saleIsActive = false;
    bool public pause = true;
    mapping(uint256 => bool) public tigers;
    address tigerAddress;
    TigerCollection public tigerCollection;
    
    // Base URI
    string private m_BaseURI = "";

    constructor(
        string memory name,
        string memory symbol,
        string memory baseURI,
        address _tigerAddress
    ) ERC721(name, symbol) {
        tigerAddress = _tigerAddress;
        tigerCollection = TigerCollection(tigerAddress);
        admin = msg.sender;
        m_BaseURI = baseURI;
    }
    
    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    /**
    * Mint Tigeros
    */
    function mintTigerosByTiger(uint256[] memory tokens) public payable {
        require(tokens.length <= maxTigeroPurchase, "Exceeds max number of Tigeros in one transaction");
        require(!pause, "Pause mint");
        require(!saleIsActive, "Sale is active");
        require(totalSupply().add(tokens.length) <= maxTigeros, "Purchase would exceed max supply of Tigeros");
        require(tigeroPrice.mul(tokens.length) == msg.value, "Ether value sent is not correct");
        
        for (uint i = 0; i < tokens.length; i++) {
            //Tigers cannot be reused
            require(!tigers[tokens[i]], "This tiger has been used");
            //Verify the owner of the tiger
            require(tigerCollection.ownerOf(tokens[i]) == _msgSender(), "No permission");
            //Modify the tag of this tiger
            tigers[tokens[i]] = true;
            
            uint tokenId = totalSupply();
            _safeMint(_msgSender(), tokenId);
        }
    }
    
    /**
    * Mint Tigeros
    */
    function mintTigeros(uint numberOfTokens) public payable {
		require(numberOfTokens <= maxTigeroPurchase, "Exceeds max number of Tigeros in one transaction");
		require(!pause, "Pause mint");
        require(saleIsActive, "Sale is not active");
        require(totalSupply().add(numberOfTokens) <= maxTigeros, "Purchase would exceed max supply of Tigeros");
        require(tigeroPrice.mul(numberOfTokens) == msg.value, "Ether value sent is not correct");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint tokenId = totalSupply();
            _safeMint(_msgSender(), tokenId);
        }
    }
    
    /**
    * Withdraw all balance to the admin address
    */
    function withdraw() public onlyAdmin {
        uint256 balance = address(this).balance;
        require(balance > 0);
        payable(_msgSender()).transfer(balance);
    }
    
    //Sales switch
    function flipSaleState() public onlyAdmin {
        saleIsActive = !saleIsActive;
    }
    
    //Sales pause
    function flipPauseState() public onlyAdmin {
        pause = !pause;
    }
    
    function setAdmin(address addr) external onlyAdmin() {
        admin = addr;
    }
    
    function setMaxToken(uint256 _value) external onlyAdmin {
        require(
            _value > totalSupply() && _value <= 10_000,
            "Wrong value for max supply"
        );

        maxTigeros = _value;
    }
    
    function setPrice(uint256 _price) external onlyAdmin {
        tigeroPrice = _price;
    }

    function setMaxPurchase(uint256 _value) external onlyAdmin {
        require(_value > 0, "Invalid value");
        maxTigeroPurchase = _value;
    }

    // setBaseURI
    //  -  Metadata lives here
    function setBaseURI(string memory baseURI) external onlyAdmin() {
        m_BaseURI = baseURI;
    }

    // _baseURI
    function _baseURI() internal view override returns (string memory) {
        return m_BaseURI;
    }
    
    //All tokens under this address
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ownerTokens) {
        uint256 tokenCount = balanceOf(_owner);

        if (tokenCount == 0) {
            // Return an empty array
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            for(uint256 i=0; i<tokenCount; i++) {
                uint256 index = tokenOfOwnerByIndex(_owner,i);
                result[i] = index;
            }
            return result;
        }
    }
}
function withdraw() public onlyAdmin {
    uint256 balance = address(this).balance;
    require(balance > 0);
    payable(_msgSender()).transfer(balance);
}

/**
 * Withdraw all balance to the admin address
 */