contract Eterneum is Ownable {
    /**
    *   @dev Contract Properties
    */
    string private _name;   // Token name
    string private _symbol; // Token symbol
    uint private _price;    // Token Payable price
    uint256[] private _allTokens;    // Array with all token ids, used for enumeration
    mapping (uint256 => address) private _owners;       // Mapping from token ID to owner address
    mapping (uint256 => string) private _tokenCIDs;     // Mapping from token ID to CID

     /**
     * @dev Initializes the contract properties by setting a `name`,  a `symbol` and a price to the token collection.
     */
    constructor (string memory name_, string memory symbol_, uint price_) {
        _name = name_;
        _symbol = symbol_;
        _price = price_;
    }

    /**
     * @dev Return contract properties
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }
     function price() public view virtual returns (uint) {
        return _price;
    }

    /*
    *   @dev Change price
    */
    function changePrice(uint price_) public onlyOwner {
        _price = price_;
    }

    /**
     * @dev Initialize event and method for payable contract
     */
    event Received(address, uint);
    receive() external payable {
        emit Received(msg.sender, msg.value);
    }

    /**
    *   @dev Tranfert amount from the contract
    */
    function withdraw(uint amount) public onlyOwner() {
        address payable owner_pay = payable(owner());
        owner_pay.transfer(amount);
    }
    
    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) public view virtual returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "Owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens start existing when they are minted (`mint`),
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    /**
    *   @dev mint the tokenID
    */
    function mint(address to, uint256 tokenId, string memory tokenCid) external payable {
        require(to != address(0), "Mint to the zero address");
        require(!_exists(tokenId), "Token already minted");
        require(bytes(tokenCid).length > 0, "CID is empty");

        /* if not owner of contract, pay the price */
        if (owner() != _msgSender()) {
            require(msg.value == _price, "Value sent not match contract Price");
            address payable owner_pay = payable(owner());
            owner_pay.transfer(msg.value);
        }

        _owners[tokenId] = to;
        _tokenCIDs[tokenId] = tokenCid;
        _allTokens.push(tokenId);

        emit Transfer(address(0), to, tokenId);
    }

    /**
    *   @dev change the tokenCid - only contract Owner
    */
    function cid(uint256 tokenId, string memory tokenCid) public onlyOwner {
        require(_exists(tokenId), "Token not already minted");
        require(bytes(tokenCid).length > 0, "CID is empty");
        _tokenCIDs[tokenId] = tokenCid;
    }


     /**
     * @dev Total number of tokens.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev Return the tokenID associated with the index.
     */
    function tokenByIndex(uint256 index) public view virtual returns (uint256) {
        require(index < totalSupply(), "Global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Return the CID associated with the tokenID.
     */
    function tokenCID(uint256 tokenId) public view virtual returns (string memory) {
        require(_exists(tokenId), "CID query for nonexistent token");
        return _tokenCIDs[tokenId];
    }
   
}
function totalSupply() public view virtual returns (uint256) {
    return _allTokens.length;
}

/**
 * @dev Total number of tokens.
 */