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

    string public HoSProvenance = ""; // IPFS URL WILL BE ADDED WHEN ALL SOLD OUT

    uint256 public constant shadowPrice = 80000000000000000; // 0.08 ETH PRICE PER

    uint public constant maxShadowPerPurchase = 20;

    uint256 public constant maxShadows = 2500;

    address public ownerAddress1 = 0x0dAe751fA68C0b1c077F00005Fe3Ef730eA4491C;

    address public ownerAddress2 = 0xd111702372502E41f4fF235EC210e5010c266636;

    address public ownerAddress3 = 0x29864E60135E96Ab9D2495c0BFff5d54CF35F9e0;

    address public ownerAddress4 = 0xfaf8f24601e7744468CEC3E5Ec3587E148Acb024;

    address public ownerAddress5 = 0xdcd14a1325b1fd98A275b195A60a01FDF4a10803;

    bool public saleIsActive = false;

    constructor() ERC721("House of Shadows", "HOS") { }
    
    function withdraw() external {
        require(
            msg.sender == ownerAddress1 || 
            msg.sender == ownerAddress2 || 
            msg.sender == ownerAddress3 || 
            msg.sender == ownerAddress4 || 
            msg.sender == ownerAddress5,
             "No permission");
        uint balance = address(this).balance;
        _withdraw(ownerAddress1, balance.mul(20).div(100));
        _withdraw(ownerAddress2, balance.mul(20).div(100));
        _withdraw(ownerAddress3, balance.mul(20).div(100));
        _withdraw(ownerAddress4, balance.mul(20).div(100));
        _withdraw(ownerAddress5, address(this).balance);
    }
    
    function _withdraw(address _address, uint256 _amount) private {
        (bool success, ) = _address.call{value: _amount}("");
        require(success, "Transfer failed.");
    }

    function setProvenanceHash(string memory provenanceHash) public onlyOwner {
        HoSProvenance = provenanceHash;
    }

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


    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }
    
    // Get the tokens of the owner
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array if he/she doesnt own any
            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 mintShadow(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint Shadows");
        require(numberOfTokens > 0 && numberOfTokens <= maxShadowPerPurchase, "Can only mint 20 tokens at a time.");
        require(totalSupply().add(numberOfTokens) <= maxShadows, "Purchase would exceed max supply of Shadows");
        require(msg.value >= shadowPrice.mul(numberOfTokens), "Ether value sent is not correct.");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < maxShadows) {
                _safeMint(msg.sender, mintIndex);
            }
        }

    }
}
function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
    uint256 tokenCount = balanceOf(_owner);
    if (tokenCount == 0) {
        // Return an empty array if he/she doesnt own any
        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;
    }
}

// Get the tokens of the owner