contract BlockchainMuseumNFT is ERC1155, AccessControl {
    using SafeMath for uint256;

    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    uint256 public constant PERCENTS_DIVIDER = 1000;
    uint256 public constant FEE_MAX_PERCENT = 300;

    string public name;
    bool public isPublic;
    uint256 public currentID;
    address public factory;
    address public owner;

    event ItemAdded(uint256 id, string uri, uint256 supply, address creator);

    mapping(uint256 => address) private _creators;
    mapping(uint256 => uint256) private _creatorFee;
    mapping(uint256 => uint256) public tokenSupply;
    mapping(uint256 => string) customUri;

    constructor() ERC1155("") {
        factory = msg.sender;
    }

    /**
		Initialize from Swap contract
	 */
    function initialize(
        string memory _name,
        string memory _uri,
        address creator,
        bool bPublic
    ) external {
        require(msg.sender == factory, "Only for factory");
        _setURI(_uri);
        name = _name;
        owner = creator;
        isPublic = bPublic;

        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        _setupRole(MINTER_ROLE, owner);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC1155, AccessControl)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    /**
		Change Collection URI
	 */
    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    /**
		Change Collection Name
	 */
    function setName(string memory newname) public onlyOwner {
        name = newname;
    }

    /**
		Make collection as Public
	 */
    function setPublic(bool bPublic) public onlyOwner {
        isPublic = bPublic;
    }

    function uri(uint256 _id) public view override returns (string memory) {
        require(_exists(_id), "ERC1155Tradable#uri: NONEXISTENT_TOKEN");
        // We have to convert string to bytes to check for existence
        bytes memory customUriBytes = bytes(customUri[_id]);
        if (customUriBytes.length > 0) {
            return customUri[_id];
        } else {
            return super.uri(_id);
        }
    }

    /**
     * @dev Returns the total quantity for a token ID
     * @param _id uint256 ID of the token to query
     * @return amount of token in existence
     */
    function totalSupply(uint256 _id) public view returns (uint256) {
        return tokenSupply[_id];
    }

    /**
     * @dev Will update the base URI for the token
     * @param _tokenId The token to update. _msgSender() must be its creator.
     * @param _newURI New URI for the token.
     */
    function setCustomURI(uint256 _tokenId, string memory _newURI)
        public
        creatorOnly(_tokenId)
    {
        customUri[_tokenId] = _newURI;
        emit URI(_newURI, _tokenId);
    }

    /**
		Create Card - Only Minters
	 */
    function addItem(
        uint256 supply,
        uint256 _fee,
        string memory _uri
    ) public returns (uint256) {
        require(
            hasRole(MINTER_ROLE, msg.sender) || isPublic,
            "Only minter can add item"
        );
        require(supply > 0, "supply can not be 0");
        require(_fee < FEE_MAX_PERCENT, "Too big creator fee");

        currentID = currentID.add(1);
        tokenSupply[currentID] = supply;

        _creators[currentID] = msg.sender;
        _creatorFee[currentID] = _fee;
        if (bytes(_uri).length > 0) {
            customUri[currentID] = _uri;
            emit URI(_uri, currentID);
        }

        if (supply > 0) {
            _mint(msg.sender, currentID, supply, "Mint");
        }

        emit ItemAdded(currentID, _uri, supply, msg.sender);
        return currentID;
    }

    function creatorOf(uint256 id) public view returns (address) {
        return _creators[id];
    }

    function creatorFee(uint256 id) public view returns (uint256) {
        return _creatorFee[id];
    }

    modifier onlyOwner() {
        require(owner == _msgSender(), "caller is not the owner");
        _;
    }

    function _exists(uint256 _id) internal view returns (bool) {
        return _creators[_id] != address(0);
    }

    /**
     * @dev Require _msgSender() to be the creator of the token id
     */
    modifier creatorOnly(uint256 _id) {
        require(
            _creators[_id] == _msgSender(),
            "ERC1155Tradable#creatorOnly: ONLY_CREATOR_ALLOWED"
        );
        _;
    }
}
function initialize(
        string memory _name,
        string memory _uri,
        address creator,
        bool bPublic
    ) external {
        require(msg.sender == factory, "Only for factory");
        _setURI(_uri);
        name = _name;
        owner = creator;
        isPublic = bPublic;

        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        _setupRole(MINTER_ROLE, owner);
    }
/**
 		Initialize from Swap contract
 	 */