contract ERC1155Mintable is ERC1155, Ownable{
    using SafeMath for uint256;
    using Address for address;

    bytes4 constant private INTERFACE_SIGNATURE_URI = 0x0e89341c;
    
    // id => creators
    mapping (uint256 => address) public creators;
    mapping(uint256 => string) public tokenUris;

    // A nonce to ensure we have a unique id each time we mint.
    uint256 public nonce = 10000001000000;
    
    
    constructor (string memory name_, string memory symbol_, string memory uri_) ERC1155(name_, symbol_, uri_) {
        
    }

    modifier creatorOnly(uint256 _id) {
        require(creators[_id] == msg.sender);
        _;
    }

    function supportsInterface(bytes4 _interfaceId) override
    public
    view
    returns (bool) {
        if (_interfaceId == INTERFACE_SIGNATURE_URI) {
            return true;
        } else {
            return super.supportsInterface(_interfaceId);
        }
    }

    // Creates a new token type and assings _initialSupply to minter
    function create(uint256 _initialSupply, string calldata _uri) external onlyOwner returns(uint256 _id) {
        
        _id = ++nonce;
        creators[_id] = msg.sender;
        _balances[_id][msg.sender] = _initialSupply;
        tokenUris[_id] = _uri;
        _totalSupply += _initialSupply;

        // Transfer event with mint semantic
        emit TransferSingle(msg.sender, address(0x0), msg.sender, _id, _initialSupply);

        if (bytes(_uri).length > 0)
            emit URI(_uri, _id);
    }

    // Batch mint tokens. Assign directly to _to[].
    function mint(uint256 _id, address[] calldata _to, uint256[] calldata _quantities) external onlyOwner{
        require(msg.sender == creators[_id]);
        for (uint256 i = 0; i < _to.length; ++i) {

            address to = _to[i];
            uint256 quantity = _quantities[i];

            // Grant the items to the caller
            _balances[_id][to] = quantity.add(_balances[_id][to]);

            // Emit the Transfer/Mint event.
            // the 0x0 source address implies a mint
            // It will also provide the circulating supply info.
            emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);

            if (to.isContract()) {
                super._doSafeTransferAcceptanceCheck(msg.sender, msg.sender, to, _id, quantity, '');
            }
        }
    }
    
    //mint tokens. Assign directly to _to[].
    function mintSingle(uint256 _id, address _to, uint256 _quantities) external onlyOwner {
        require(msg.sender == creators[_id]);
        // Grant the items to the caller
        _balances[_id][_to] = _quantities.add(_balances[_id][_to]);

        // Emit the Transfer/Mint event.
        // the 0x0 source address implies a mint
        // It will also provide the circulating supply info.
        emit TransferSingle(msg.sender, address(0x0), _to, _id, _quantities);

        if (_to.isContract()) {
            super._doSafeTransferAcceptanceCheck(msg.sender, msg.sender, _to, _id, _quantities, '');
        }
    }

    function setURI(string calldata _uri, uint256 _id) external onlyOwner {
        require(msg.sender == creators[_id]);
        tokenUris[_id] = _uri;
        emit URI(_uri, _id);
    }
    
    function tokenURI(uint256 _id) public view returns (string memory _uri) {
        return tokenUris[_id];
    }
   
    function uri(uint256 _id) public view override returns (string memory) {
        return tokenUris[_id];
    }

    function burn(address account, uint256 id, uint256 value) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burn(account, id, value);
    }

    function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burnBatch(account, ids, values);
    }
}
/**
 @dev Mintable form of ERC1155
 Shows how easy it is to mint new items.
 */
function create(uint256 _initialSupply, string calldata _uri) external onlyOwner returns(uint256 _id) {
        
    _id = ++nonce;
    creators[_id] = msg.sender;
    _balances[_id][msg.sender] = _initialSupply;
    tokenUris[_id] = _uri;
    _totalSupply += _initialSupply;

    // Transfer event with mint semantic
    emit TransferSingle(msg.sender, address(0x0), msg.sender, _id, _initialSupply);

    if (bytes(_uri).length > 0)
        emit URI(_uri, _id);
}

// Creates a new token type and assings _initialSupply to minter