// Contract: KanamitCore
// Target function: function _transfer(
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = 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) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

abstract contract IERC721 {
    // Required methods
    function totalSupply() public view virtual returns (uint256 total);

    function balanceOf(address _owner)
        public
        view
        virtual
        returns (uint256 balance);

    function ownerOf(uint256 _tokenId)
        external
        view
        virtual
        returns (address owner);

    function approve(address _to, uint256 _tokenId) external virtual;

    function transfer(address _to, uint256 _tokenId) external virtual;

    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external virtual;

    // Events
    event Transfer(address from, address to, uint256 tokenId);
    event Approval(address owner, address approved, uint256 tokenId);

    // Optional
    // function name() public view returns (string name);
    // function symbol() public view returns (string symbol);
    // function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds);
    // function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl);

    // ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
    function supportsInterface(bytes4 _interfaceID)
        external
        view
        virtual
        returns (bool);
}

contract KanamitCore is IERC721, Ownable {
    /*** EVENTS ***/
    event Create(address owner, uint256 AssetId, uint256 hashUri, string uri);
    event Transfer(address from, address to, uint256 tokenId);

    struct Asset {
        uint256 hashUri;
    }

    /*** STORAGE ***/
    Asset[] assets;
    mapping(uint256 => address) private AssetIndexToOwner; // map<assetId , addrOwner>
    mapping(address => uint256) private OwnerAssetCount; // map<addrOwner, uintCount>
    mapping(address => mapping(uint256 => uint256)) private OwnerAssets; // map<addrOwner, map<hashUri, assetId> >
    mapping(uint256 => address) private AssetIndexToApproved; //map<assetId, addrApproved>
    mapping(uint256 => uint256) private mapUriAssetId; //map<hashUri, AssetId>

    constructor() public {
        //初始化第一个元素；addressOwner 为address(0)， uri为空字符""，对应的AssetId为0；
        uint256 hashUri = uint256(keccak256(abi.encodePacked("")));
        Asset memory currAsset = Asset({hashUri: hashUri});
        assets.push(currAsset);
    }