contract ERC1155OwnerCreate is Ownable, ERC1155 {
    using StringConcate for string;

    mapping(uint256 => uint256) public tokenSupply;
    mapping(uint256 => string) public customUri;

    // Contract name
    string public name;
    // Contract symbol
    string public symbol;


    constructor(
        string memory _name,
        string memory _symbol,
        string memory _uri
    ) ERC1155(_uri) {
        name = _name;
        symbol = _symbol;
    }

    function exists(uint256 _id) public view virtual returns (bool) {
        return tokenSupply[_id] > 0;
    }

    function uri(uint256 _id)
        public
        view
        virtual
        override
        returns (string memory)
    {
        require(exists(_id), "ERC1155#uri: NONEXISTENT_TOKEN");
        bytes memory customUriBytes = bytes(customUri[_id]);
        if (customUriBytes.length > 0) {
            return customUri[_id];
        } else {
            return
                StringConcate.strConcat(
                    super.uri(0),
                    StringConcate.uint2str(_id)
                );
        }
    }

    function setURI(string memory newuri) public virtual onlyOwner {
        _setURI(newuri);
    }

    function setCustomURI(uint256 _tokenId, string memory _newURI)
        public
        virtual
        onlyOwner
    {
        customUri[_tokenId] = _newURI;
        emit URI(_newURI, _tokenId);
    }

    function create(
        address _initialOwner,
        uint256 _id,
        uint256 _initialSupply,
        string memory _uri,
        bytes memory _data
    ) public virtual onlyOwner returns (uint256) {
        require(!exists(_id), "token _id already exists");

        if (bytes(_uri).length > 0) {
            customUri[_id] = _uri;
            emit URI(_uri, _id);
        }

        _mint(_initialOwner, _id, _initialSupply, _data);
        tokenSupply[_id] = _initialSupply;
        return _id;
    }

    function createBatch(
        address[] calldata _owners,
        uint256[] calldata _ids,
        uint256[] calldata _initialSupplies,
        bytes calldata _data) external virtual onlyOwner {
          require(_owners.length == _ids.length && _owners.length == _initialSupplies.length, "ERC1155: lengths mismatch");
          for (uint256 i = 0; i < _owners.length; i++){
             _mint(_owners[i], _ids[i], _initialSupplies[i], _data);
             tokenSupply[_ids[i]] = _initialSupplies[i];
          }
        }

    /**
     * @dev Mints some amount of tokens to an address
     * @param _to          Address of the future owner of the token
     * @param _id          Token ID to mint
     * @param _quantity    Amount of tokens to mint
     * @param _data        Data to pass if receiver is contract
     */
    function mint(
        address _to,
        uint256 _id,
        uint256 _quantity,
        bytes memory _data
    ) public virtual onlyOwner{
        _mint(_to, _id, _quantity, _data);
        tokenSupply[_id] += _quantity;
    }

    /**
     * @dev Mint tokens for each id in _ids
     * @param _to          The address to mint tokens to
     * @param _ids         Array of ids to mint
     * @param _quantities  Array of amounts of tokens to mint per id
     * @param _data        Data to pass if receiver is contract
     */
    function batchMint(
        address _to,
        uint256[] memory _ids,
        uint256[] memory _quantities,
        bytes memory _data
    ) public virtual onlyOwner{
        require(_ids.length == _quantities.length, "ERC1155: _ids and _quantities length mismatch");
        for (uint256 i = 0; i < _ids.length; i++) {
            uint256 _id = _ids[i];
            uint256 quantity = _quantities[i];
            tokenSupply[_id] += quantity;
        }
        _mintBatch(_to, _ids, _quantities, _data);
    }

    function burn(uint256 _id, uint256 _quantity) public virtual {
      _burn(_msgSender(), _id, _quantity);
    }

    function burnBatch(uint256[] calldata _ids, uint256[] calldata _quantities) public virtual {
      _burnBatch(_msgSender(), _ids, _quantities);
    }
}
function mint(
    address _to,
    uint256 _id,
    uint256 _quantity,
    bytes memory _data
) public virtual onlyOwner{
    _mint(_to, _id, _quantity, _data);
    tokenSupply[_id] += _quantity;
}

/**
 * @dev Mints some amount of tokens to an address
 * @param _to          Address of the future owner of the token
 * @param _id          Token ID to mint
 * @param _quantity    Amount of tokens to mint
 * @param _data        Data to pass if receiver is contract
 */