contract NiftyBuilderInstance is ERC721, ERC721Burnable {
    using Counters for Counters.Counter;

    string public creator;
  
    string public _baseTokenURI;

    uint immutable public id;
    uint immutable public countType;

    mapping (uint => uint) public _numNiftyPermitted;
    mapping (uint => Counters.Counter) public _numNiftyMinted;

    address public dateTimeContract;

    string[2] private artifact_1 = ["Qman8rCRYmLQnm3iBH5VwhMfHJkz7e7g9TQopSyrwtbCes", //Day
                                    "QmQwSqEohMXeP9QxzrzWeEwtdWPnxH6WjnpXkfyPPMEK2o"];//Night

    string private artifact_2 = "QmVdE84ZJxT66j8nEEVFKvwBKXsyYYihHawHmCqsLF9qMv"; //Love for the Low

    string[3] private artifact_3 = ["QmcsKgicSRsCVNu4NcFZu1PgjhvWZMm34ASTUh5QivvSn4", //Day 0 (Peace)
                                    "QmV1U5fKdLgnYmz8wVnLXxPJAovjEYeUaqCi4ZNxueavts", //Day 1 (Air)
                                    "Qmf9NSo6C9Ufwyz23JH9LS3kfKXAN5FUYpKTDPyYJDsax9"];//Day 2 (Spark)

    constructor(address _dateTimeContract,
                address masterBuilderContract, 
                address niftyRegistryContract) ERC721("Coming of Age", "JAG", masterBuilderContract, niftyRegistryContract) {

        dateTimeContract = _dateTimeContract;

        id = 1;
        countType = 3;
        creator = "LOGIK";

        _setNiftyTypeName(1, "Breffis Day n' Night");
        _numNiftyPermitted[1] = 1;

        _setNiftyTypeName(2, "Love for the Low");
        _numNiftyPermitted[2] = 5;
        
        _setNiftyTypeName(3, "FreeDOOM Rocket");
        _numNiftyPermitted[3] = 10;

        _setBaseURIParent("https://api.niftygateway.com/juliangilliam/");
    }

    /**
     * Configurable address for DateTime.
     */ 
    function setDateTimeContract(address _dateTimeContract) onlyValidSender public {
        dateTimeContract = _dateTimeContract;
    }


    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return super.supportsInterface(interfaceId);
    }


    function _setBaseURIParent(string memory newBaseURI) internal {
        _baseTokenURI = newBaseURI;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _baseTokenURI;
    }

    /**
     * @dev Allow owner to change nifty name.
     */
    function setNiftyName(uint nifty_type, string memory nifty_name) onlyValidSender public {
        _setNiftyTypeName(nifty_type, nifty_name);
    }
   
    function setNiftyIPFSHash(uint nifty_type, string memory ipfs_hash) onlyValidSender public {
        _setTokenIPFSHashNiftyType(nifty_type, ipfs_hash);
    }
    
    function isGiftNiftyPermitted(uint nifty_type) private view returns (bool) {
        if (_numNiftyMinted[nifty_type].current() >= _numNiftyPermitted[nifty_type]) {
            return false;
        }
        return true;
    }

    function giftNifty(address collector_address, uint nifty_type) onlyValidSender public {
        require(isGiftNiftyPermitted(nifty_type) == true, "NiftyBuilderInstance: Nifty sold out!");
        BuilderMasterAPI bm = BuilderMasterAPI(masterBuilderContract);
       
        _numNiftyMinted[nifty_type].increment();
        uint specificTokenId = _numNiftyMinted[nifty_type].current();
        uint tokenId = bm.encodeTokenId(id, nifty_type, specificTokenId);
       
        _mint(collector_address, tokenId);
    }

    /**
     * @dev Loop through array and create nifties.
     */
    function massMintNFTs(address collector_address, uint num_to_mint, uint nifty_type) onlyValidSender public {
        for (uint i = 0; i < num_to_mint; i++) {
            giftNifty(collector_address, nifty_type);
        }
    }

    function tokenIPFSHash(uint256 tokenId) external view override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: IPFS hash query for nonexistent token");

        BuilderMasterAPI bm = BuilderMasterAPI(masterBuilderContract);
        uint nifty = bm.getNiftyTypeId(tokenId);

        if(nifty == 2){
            return artifact_2;
        }
        DateTimeAPI dateTime = DateTimeAPI(dateTimeContract);
        if(nifty == 1){
            uint hour = dateTime.getHour(block.timestamp);
            if(hour >= 12){
                return artifact_1[1];
            }
            return artifact_1[0];
        }
        uint day = dateTime.getDay(block.timestamp);
        uint index = day % artifact_3.length;
        return artifact_3[index];
    }
}
function setDateTimeContract(address _dateTimeContract) onlyValidSender public {
    dateTimeContract = _dateTimeContract;
}

/**
 * Configurable address for DateTime.
 */