contract NonFungibleCEO {
    ICigToken private cigToken;
    address public owner;
    string private metadataURI;

    constructor(string memory _uri) {
        metadataURI = _uri;
        emit BaseURI(_uri);
        _transferOwnership(msg.sender);
    }

    modifier onlyOwner {
        require(
            msg.sender == owner,
            "only admin can call this"
        );
        _;
    }
    /**
    * @dev onlyCig ensures only the cig token contract can use it
    */
    modifier onlyCig {
        require(address(cigToken) == msg.sender, 'must be called from cigtoken');
        _;
    }

    /**
    * @dev onlyCEO ensures that only the CEO can use it
    */
    modifier onlyCEO {
        require(cigToken.The_CEO() == msg.sender, 'must be called by CEO');
        _;
    }

    function baseTokenURI() public view returns (string memory) {
        return metadataURI;
    }


    /**
    * @dev renounceOwnership burns the admin key
    */
    function renounceOwnership() external onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) external  onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
    /**
    * @dev setCigToken sets the address to the cig token
    * @param _addr address to the cig token
    */
    function setCigToken(address _addr) external onlyOwner {
        cigToken = ICigToken(_addr);
    }

    /***
    * ERC721 stuff
    */
    address private holder; // the NFT owner
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event BaseURI(string);
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    function totalSupply() external pure returns (uint256) {
        return 1;
    }

    function tokenByIndex(uint256 _index) external pure returns (uint256) {
        if (_index == 0) {return 0; }
        revert("404");
    }

    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256) {
        if (_owner == holder) {
            return 0;
        }
        revert("404");
    }

    function balanceOf(address _holder) public view returns (uint256) {
        if (_holder == holder) {
            return 1;
        }
        return 0;
    }

    function name() public pure returns (string memory) {
        return "CEO of CryptoPunks";
    }

    function symbol() public pure returns (string memory) {
        return "CEO";
    }

    /**
    * @dev setBaseURI sets the baseURI value
    */
    function setBaseURI(string memory _uri) external onlyCEO {
        metadataURI = _uri;
        emit BaseURI(_uri);
    }

    function tokenURI(uint256 _tokenId) public view returns (string memory) {
        if (_tokenId != 0) revert("404");
        return string(abi.encodePacked(metadataURI, "0.json"));
    }

    function ownerOf(uint256 _tokenId) public view returns (address) {
        if (_tokenId != 0) revert("404");
        return holder;
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory data) external onlyCig {
        _transfer(_from, _to, _tokenId);
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external onlyCig {
        _transfer(_from, _to, _tokenId);
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) external onlyCig {
        _transfer(_from, _to, _tokenId);
    }

    function approve(address _approved, uint256 _tokenId) external onlyCig {
    }

    function setApprovalForAll(address _operator, bool _approved) external onlyCig {
    }

    function getApproved(uint256 _tokenId) public view returns (address) {
        return address(cigToken);
    }

    function isApprovedForAll(address _owner, address _operator) public pure returns (bool) {

        return false;
    }

    function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
        return
        interfaceId == type(IERC721).interfaceId ||
        interfaceId == type(IERC721Metadata).interfaceId ||
        interfaceId == type(IERC165).interfaceId ||
        interfaceId == type(ERC721Enumerable).interfaceId ||
        interfaceId == type(ERC721TokenReceiver).interfaceId;
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        require(_tokenId == 0, "404");
        holder = _to;
        emit Transfer(_from, _to, _tokenId);
    }

    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes memory _data) external pure returns (bytes4) {
        revert("nope");
        return bytes4(keccak256("nope"));
    }


}
/**
 * "Non fungible CEO"
 * This is a NFT that gets transferred to the address that hold the CEO title.
 * Think of it as a "title belt" in boxing.
 * The purpose is so that the NFT will show up in CEOs gallery, so that everyone will be able to see it!
 *
 * Properties:
 * - There is only 1 NFT, NFT ID is 0
 * - Only the CIG token contract has permission to transfer it
 * - Admin key only used for deployment
 *
 */
function setCigToken(address _addr) external onlyOwner {
    cigToken = ICigToken(_addr);
}

/**
 * @dev setCigToken sets the address to the cig token
 * @param _addr address to the cig token
 */