contract DaricoEcosystem is ERC1155Metadata {
    uint256 private _currentTokenID = 0;
    mapping (uint256 => address) public creators;
    mapping (uint256 => uint256) public tokenSupply;
    mapping (address => mapping (address => uint256)) private _allowances;
    
      
    address public wrappedContract;
      
    /**
    * @dev Require msg.sender to be the creator of the token id
    */
    modifier creatorOnly(uint256 _id) {
        require(creators[_id] == msg.sender, "ERC1155Tradable#creatorOnly: ONLY_CREATOR_ALLOWED");
        _;
    }
      
    constructor() public  {
        name = "Darico Ecosystem";
        symbol = "DRCX";
    }
    
    /**
    * @dev Require msg.sender to own more than 0 of the token id
    */
    modifier ownersOnly(uint256 _id) {
        require(balances[msg.sender][_id] > 0, "ERC1155Tradable#ownersOnly: ONLY_OWNERS_ALLOWED");
        _;
    }
    
     /**
    * @dev Creates a new token type and assigns _initialSupply to an address
    * NOTE: remove onlyOwner if you want third parties to create new tokens on your contract (which may change your IDs)
    * @param _initialOwner address of the first owner of the token
    * @param _initialSupply amount to supply the first owner
    * @param _uri Optional URI for this token type
    * @param _data Data to pass if receiver is contract
    * @return The newly created token ID
    */
    function create(
        address _initialOwner,
        uint256 _initialSupply,
        string calldata _uri,
        bytes calldata _data
        ) external onlyOwner returns (uint256) {
    
        uint256 _id = _getNextTokenID();
        _incrementTokenTypeId();
        creators[_id] = msg.sender;
        
        if (bytes(_uri).length > 0) {
          emit URI(_uri, _id);
        }
        
        _mint(_initialOwner, _id, _initialSupply, _data);
        tokenSupply[_id] = _initialSupply;
        return _id;
    }
      
    /**
    * @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 creatorOnly(_id) {
        _mint(_to, _id, _quantity, _data);
        tokenSupply[_id] = tokenSupply[_id].add(_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 {
        for (uint256 i = 0; i < _ids.length; i++) {
            uint256 _id = _ids[i];
            require(creators[_id] == msg.sender, "ERC1155Tradable#batchMint: ONLY_CREATOR_ALLOWED");
            uint256 quantity = _quantities[i];
            tokenSupply[_id] = tokenSupply[_id].add(quantity);
        }
        _batchMint(_to, _ids, _quantities, _data);
    }
    
    /**
    * @dev Will update the base URL of token's URI
    * @param _newBaseMetadataURI New base URL of token's URI
    */
    function setBaseMetadataURI(
        string memory _newBaseMetadataURI
        ) public onlyOwner {
        _setBaseMetadataURI(_newBaseMetadataURI);
    }
    
    /**
    * @dev Change the creator address for given tokens
    * @param _to   Address of the new creator
    * @param _ids  Array of Token IDs to change creator
    */
    function setCreator(
        address _to,
        uint256[] memory _ids
        ) public {
        require(_to != address(0), "ERC1155Tradable#setCreator: INVALID_ADDRESS.");
        for (uint256 i = 0; i < _ids.length; i++) {
          uint256 id = _ids[i];
          _setCreator(_to, id);
        }
    }
    
    /**
    * @dev Change the creator address for given token
    * @param _to   Address of the new creator
    * @param _id  Token IDs to change creator of
    */
    function _setCreator(address _to, uint256 _id) internal creatorOnly(_id) {
        creators[_id] = _to;
    }

      
    /**
    * @dev calculates the next token ID based on value of _currentTokenID
    * @return uint256 for the next token ID
    */
    function _getNextTokenID() private view returns (uint256) {
        return _currentTokenID.add(1);
    }
    
    /**
    * @dev increments the value of _currentTokenID
    */
    function _incrementTokenTypeId() private  {
        _currentTokenID++;
    }
    
    /** @notice Transfers amount amount of an _id from the _from address to the _to address specified
    * @param _from    Source address
    * @param _to      Target address
    * @param _id      ID of the token type
    * @param _amount  Transfered amount
    */
    function safeTransfer(address _from, address _to, uint256 _id, uint256 _amount, address _spender) 
        public active()
        whenActive(_from,_to,_id) 
    {
        require(msg.sender == wrappedContract, "Invalid transfer");
        require(_allowances[_from][_spender] > 0, "ERC1155#safeTransfer: INVALID_OPERATOR");
        require((msg.sender == _from) || _allowances[_from][_spender] >= _amount, "ERC1155#safeTransfer: INVALID_OPERATOR");
        require(_to != address(0), "ERC1155#safeTransferFrom: INVALID_RECIPIENT");
        // require(_amount <= balances[_from][_id]) is not necessary since checked with safemath operations
        
        _allowances[_from][_spender] =  _allowances[_from][_spender].sub(_amount);
        _safeTransferFrom(_from, _to, _id, _amount);
        // _callonERC1155Received(_from, _to, _id, _amount, gasleft(), _data);
    }
    
    /** @notice Transfers amount amount of an _id from the _from address to the _to address specified
    * @param _from    Source address
    * @param _to      Target address
    * @param _id      ID of the token type
    * @param _amount  Transfered amount
    */
    function transfer(address _from, address _to, uint256 _id, uint256 _amount)
        public 
        whenActive(_from,_to,_id)
    {
        require(msg.sender == wrappedContract, "Invalid transfer");
        require(_to != address(0), "ERC1155#safeTransferFrom: INVALID_RECIPIENT");

        _safeTransferFrom(_from, _to, _id, _amount);
    }
    
    /** @notice Set Wrapper ERC20 contarct address
    * @param _wrappedContract  Contract address
    */
    function setWrapedContract(address _wrappedContract) 
        public 
        onlyOwner 
    {
          wrappedContract = _wrappedContract; 
    }
    
    /** @notice Approve amount of tokens to spender
    * @param owner   From address
    * @param spender Spender address
    * @param amount  AMount to approve
    */  
    function approve(address owner, address spender, uint256 amount) 
        external  
    {
        require(msg.sender == wrappedContract, "Invalid approve");
        require(owner != address(0), "approve from the zero address");
        require(spender != address(0), "approve to the zero address");
    
        _allowances[owner][spender] = amount;
    }
     
    /** @notice Returns Approved amount of tokens for spender
   */  
    function allowance(address owner, address spender) 
        public view  
        returns (uint256) 
    {
        require(msg.sender == wrappedContract, "Invalid allowance");
        return _allowances[owner][spender];
    }
    
    
}
function mint(
    address _to,
    uint256 _id,
    uint256 _quantity,
    bytes memory _data
    ) public creatorOnly(_id) {
    _mint(_to, _id, _quantity, _data);
    tokenSupply[_id] = tokenSupply[_id].add(_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
 */