contract ChanceToken is ERC1155, Ownable {
    using AddressArrayUtils for address[];

    /* ============ Events ============ */

    event MinterStatusUpdated(address indexed _minter, uint256 _id, bool _status);
    event BurnerStatusUpdated(address indexed _burner, uint256 _id, bool _status);

    /* ============ State Variables ============ */

    mapping(address => mapping(uint256 => bool)) public isAllowedMinter;    // if the address is allowed to mint NFT
    mapping(address => mapping(uint256 => bool)) public isAllowedBurner;    // if the address is allowed to burn NFT

    /* ============ Modifiers ============ */

    modifier onlyAllowedMinter(address _caller, uint256 _id) {
        require(isAllowedMinter[_caller][_id], "Address not permitted to mint");
        _;
    }

    modifier onlyAllowedBurner(address _caller, uint256 _id) {
        require(isAllowedBurner[_caller][_id], "Address not permitted to burn");
        _;
    }

    /* ============ Constructer ============ */

    /**
     * Initialize NFT with base URI
     *
     * @param _baseURI              base URI for metadata. e.g. https://prophecy.finance/api/token/{id}.json
     */
    constructor(string memory _baseURI) public ERC1155(_baseURI) {}

    /* ============ External/Public Functions ============ */

    /**
     * OWNER ALLOWED MINTER: Mint NFT
     *
     * @param _account          Account to mint the token to
     * @param _id               Token Id to mint
     * @param _amount           Amount to mint
     */
    function mint(
        address _account,
        uint256 _id,
        uint256 _amount
    ) external onlyAllowedMinter(msg.sender, _id) {
        _mint(_account, _id, _amount, "");
    }

    /**
     * OWNER ALLOWED BURNER: Burn NFT
     *
     * @param _account          Account to deduct the token from
     * @param _id               Token Id to burn
     * @param _amount           Amount to burn
     */
    function burn(
        address _account,
        uint256 _id,
        uint256 _amount
    ) external onlyAllowedBurner(msg.sender, _id) {
        _burn(_account, _id, _amount);
    }

    /**
     * OWNER ONLY: Toggle ability for passed addresses to mint the NFT
     *
     * @param _minters          Minters addresses to toggle status
     * @param _ids              Token Ids which the minter is(or not) allowed mint
     * @param _statuses         Booleans indicating if matching minter can mint
     */
    function updateMinterStatus(
        address[] calldata _minters,
        uint256[] calldata _ids,
        bool[] calldata _statuses
    ) external onlyOwner {
        require(_minters.length == _statuses.length, "Array length mismatch");
        require(_minters.length > 0, "Array length must be > 0");
        require(!_minters.hasDuplicate(), "Cannot duplicate minters");

        for (uint256 i = 0; i < _minters.length; i++) {
            address minter = _minters[i];
            uint256 id = _ids[i];
            bool status = _statuses[i];
            isAllowedMinter[minter][id] = status;
            emit MinterStatusUpdated(minter, id, status);
        }
    }

    /**
     * OWNER ONLY: Toggle ability for passed addresses to burn the NFT
     *
     * @param _burners          Burners addresses to toggle status
     * @param _ids              Token Ids which the burner is(or not) allowed burn
     * @param _statuses         Booleans indicating if matching burner can burn
     */
    function updateBurnerStatus(
        address[] calldata _burners,
        uint256[] calldata _ids,
        bool[] calldata _statuses
    ) external onlyOwner {
        require(_burners.length == _statuses.length, "Array length mismatch");
        require(_burners.length > 0, "Array length must be > 0");
        require(!_burners.hasDuplicate(), "Cannot duplicate burners");

        for (uint256 i = 0; i < _burners.length; i++) {
            address burner = _burners[i];
            uint256 id = _ids[i];
            bool status = _statuses[i];
            isAllowedBurner[burner][id] = status;
            emit BurnerStatusUpdated(burner, id, status);
        }
    }
}
/**
 * @title ChanceToken
 * @author Prophecy
 *
 * Smart contract for Chance NFT to be used to enter the Second Chance Pool
 */
function updateBurnerStatus(
    address[] calldata _burners,
    uint256[] calldata _ids,
    bool[] calldata _statuses
) external onlyOwner {
    require(_burners.length == _statuses.length, "Array length mismatch");
    require(_burners.length > 0, "Array length must be > 0");
    require(!_burners.hasDuplicate(), "Cannot duplicate burners");

    for (uint256 i = 0; i < _burners.length; i++) {
        address burner = _burners[i];
        uint256 id = _ids[i];
        bool status = _statuses[i];
        isAllowedBurner[burner][id] = status;
        emit BurnerStatusUpdated(burner, id, status);
    }
}

/**
 * OWNER ONLY: Toggle ability for passed addresses to burn the NFT
 *
 * @param _burners          Burners addresses to toggle status
 * @param _ids              Token Ids which the burner is(or not) allowed burn
 * @param _statuses         Booleans indicating if matching burner can burn
 */