contract BDR is Token {
    struct Trx {
        bool executed;
        address from;
        uint256 value;
        address[] signers;
    }

    mapping(address => bool) public isSigner;
    mapping(uint256 => Trx) public exchangeTrx;
    address public AbcInstance;  // address of AbcToken
    uint256 public requestSigners = 2;  // BDR => Abc need signers number
    uint256 public applyCounts = 0;  // Sequence of exchange request
    mapping(address => uint256) public exchangeLock;

    event SetSigner(address indexed signer,bool isSigner);  // emit when add/remove signer
    event ApplyExchangeToken(address indexed from,uint256 value,uint256 trxSeq);  // emit when exchange successful
    event ConfirmTrx(address indexed signer,uint256 indexed trxSeq);  // emit when signer confirmed exchange request
    event CancleConfirmTrx(address indexed signer,uint256 indexed trxSeq);  // emit when signer cancles confirmed exchange request
    event CancleExchangeRequest(address indexed signer,uint256 indexed trxSeq);  // emit when signer/requester cancles exchange request
    event TokenExchange(address indexed from,uint256 value,bool AbcExchangeBDR); // emit when Abc <=> Bdr,true:Abc => BDR,false:BDR => abc
    event Mint(address indexed target,uint256 value);

    modifier onlySigner() {
        require(isSigner[msg.sender]);
        _;
    }
    /**
     * @dev initialize token info
     * @param _name string The name of token
     * @param _symbol string The symbol of token
     * @param _decimals uint8 The decimals of token
     */
    constructor(string memory _name, string memory _symbol, uint8 _decimals) Token(_name,_symbol,_decimals) public {
    }

    /**
     * @dev rewrite transfer function，user can't transfer token to AbcToken's address directly
     */
    function transfer(address _to,uint256 _value) public returns (bool success) {
        require(_to != AbcInstance,"can't transfer to AbcToken address directly");
        return super.transfer(_to,_value);
    }

    /**
     * @dev rewrite transferFrom function，user can't transfer token to AbcToken's address directly
     */
    function transferFrom(address _from, address _to,uint256 _value) public returns (bool success) {
        require(_to != AbcInstance,"can't transfer to AbcToken address directly");
        return super.transferFrom(_from,_to,_value);
    }

    /**
     * @dev rewrite transferAndLock function，user can't transfer token to AbcToken's address directly
     */
    function transferAndLock(address _to, uint256 _value, uint256 _lockdays) public returns (bool success) {
        require(_to != AbcInstance,"can't transfer to AbcToken address directly");
        return super.transferAndLock(_to,_value,_lockdays);
    }   

    /**
     * @dev set AbcToken's address
     */
    function setAbcInstance(address _abc) public onlyOwner {
        require(_abc != address(0));
        AbcInstance = _abc;
    }

    /**
     * @dev add/remove signers
     * @param _signers address[] The array of signers to add/remove
     * @param _addSigner bool true:add signers,false:remove:signers
     */
    function setSigners(address[] memory _signers,bool _addSigner) public onlyOwner {
        for(uint256 i = 0;i< _signers.length;i++){
            require(_signers[i] != address(0));
            isSigner[_signers[i]] = _addSigner;
            emit SetSigner(_signers[i],_addSigner);
        }
    }

    /**
     * @dev set the number of exchange request in order to execute
     * @param _requestSigners uint256 The number of signers
     */
    function setrequestSigners(uint256 _requestSigners) public onlyOwner {
        require(_requestSigners != 0);
        requestSigners = _requestSigners;
    }

    /**
     * @dev check whether the signer confirmed this exchange request
     */
    function isConfirmer(uint256 _trxSeq,address _signer) public view returns (bool) {
        require(exchangeTrx[_trxSeq].from != address(0),"trxSeq not exist");
        for(uint256 i = 0;i < exchangeTrx[_trxSeq].signers.length;i++){
            if(exchangeTrx[_trxSeq].signers[i] == _signer){
                return true;
            }
        }
        return false;
    }

    /**
     * @dev get how many signers that confirmed this exchange request
     */
    function getConfirmersLengthOfTrx(uint256 _trxSeq) public view returns (uint256) {
        return exchangeTrx[_trxSeq].signers.length;
    }

    /**
     * @dev get signers's address that confirmed this exchange request
     * @param _trxSeq uint256 the Sequence of exchange request
     * @param _index uint256 the index of signers
     */
    function getConfirmerOfTrx(uint256 _trxSeq,uint256 _index) public view returns (address) {
        require(_index < getConfirmersLengthOfTrx(_trxSeq),"out of range");
        return exchangeTrx[_trxSeq].signers[_index];
    }

    /**
     * @dev apply BDR exchange Abc
     * @param _value uint256 amount of BDR to exchange
     * @return uint256 the sequence of exchange request
     */
    function applyExchangeToken(uint256 _value) public whenNotPaused returns (uint256) {
        uint256 trxSeq = applyCounts;
        require(exchangeTrx[trxSeq].from == address(0),"trxSeq already exist");
        require(balances[msg.sender] >= _value);
        exchangeTrx[trxSeq].executed = false;
        exchangeTrx[trxSeq].from = msg.sender;
        exchangeTrx[trxSeq].value = _value;
        applyCounts = applyCounts.add(1);
        balances[address(this)] = balances[address(this)].add(_value);
        balances[exchangeTrx[trxSeq].from] = balances[exchangeTrx[trxSeq].from].sub(_value);
        exchangeLock[exchangeTrx[trxSeq].from] = exchangeLock[exchangeTrx[trxSeq].from].add(_value);
        emit ApplyExchangeToken(exchangeTrx[trxSeq].from,exchangeTrx[trxSeq].value,trxSeq);
        emit Transfer(msg.sender,address(this),_value);
        return trxSeq;
    }

    /**
     * @dev signer confirms one exchange request
     * @param _trxSeq uint256 the Sequence of exchange request
     */
    function confirmExchangeTrx(uint256 _trxSeq) public onlySigner {
        require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
        require(exchangeTrx[_trxSeq].signers.length < requestSigners,"trx already has enough signers");
        require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
        require(isConfirmer(_trxSeq, msg.sender) == false,"signer already confirmed");
        exchangeTrx[_trxSeq].signers.push(msg.sender);
        emit ConfirmTrx(msg.sender, _trxSeq);
    }

    /**
     * @dev signer cancel confirmed exchange request
     * @param _trxSeq uint256 the Sequence of exchange request
     */
    function cancelConfirm(uint256 _trxSeq) public onlySigner {
        require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
        require(isConfirmer(_trxSeq, msg.sender),"Signer didn't confirm");
        require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
        uint256 len = exchangeTrx[_trxSeq].signers.length;
        for(uint256 i = 0;i < len;i++){
            if(exchangeTrx[_trxSeq].signers[i] == msg.sender){
                exchangeTrx[_trxSeq].signers[i] = exchangeTrx[_trxSeq].signers[len.sub(1)] ;
                exchangeTrx[_trxSeq].signers.length --;
                break;
            }
        }
        emit CancleConfirmTrx(msg.sender,_trxSeq);
    }

    /**
     * @dev signer cancel exchange request
     * @param _trxSeq uint256 the Sequence of exchange request
     */
    function cancleExchangeRequest(uint256 _trxSeq) public {
        require(exchangeTrx[_trxSeq].from != address(0),"_trxSeq not exist");
        require(exchangeTrx[_trxSeq].executed == false,"trx already executed");
        require(isSigner[msg.sender] || exchangeTrx[_trxSeq].from == msg.sender);
        balances[address(this)] = balances[address(this)].sub(exchangeTrx[_trxSeq].value);
        balances[exchangeTrx[_trxSeq].from] = balances[exchangeTrx[_trxSeq].from].add(exchangeTrx[_trxSeq].value);
        exchangeLock[exchangeTrx[_trxSeq].from] = exchangeLock[exchangeTrx[_trxSeq].from].sub(exchangeTrx[_trxSeq].value);
        delete exchangeTrx[_trxSeq];
        emit CancleExchangeRequest(msg.sender,_trxSeq);
        emit Transfer(address(this),exchangeTrx[_trxSeq].from,exchangeTrx[_trxSeq].value);
    }

    /**
     * @dev execute exchange request which confirmed by enough signers
     * @param _trxSeq uint256 the Sequence of exchange request
     */
    function executeExchangeTrx(uint256 _trxSeq) public whenNotPaused{
        address from = exchangeTrx[_trxSeq].from;
        uint256 value = exchangeTrx[_trxSeq].value;
        require(from != address(0),"trxSeq not exist");
        require(exchangeTrx[_trxSeq].executed == false,"trxSeq has executed");
        require(exchangeTrx[_trxSeq].signers.length >= requestSigners);
        require(from == msg.sender|| isSigner[msg.sender]);
        require(value <= balances[address(this)]);
        _burn(address(this), value);
        exchangeLock[from] = exchangeLock[from].sub(value);
        exchangeTrx[_trxSeq].executed = true;
        AbcInterface(AbcInstance).tokenFallback(from,value,bytes(""));
        emit TokenExchange(exchangeTrx[_trxSeq].from,exchangeTrx[_trxSeq].value,false);
    }

    /**
     * @dev exchange Abc token to BDR token,only AbcInstance can invoke this function
     */
    function tokenFallback(address _from, uint _value, bytes memory) public {
        require(msg.sender == AbcInstance);
        require(_from != address(0));
        require(_value > 0);
        uint256 exchangeAmount = _value.mul(10**uint256(decimals)).div(10**uint256(AbcInterface(AbcInstance).decimals()));
        _mint(_from, exchangeAmount);
        emit Transfer(address(0x00),_from,exchangeAmount);
        emit TokenExchange(_from,_value,true);
    }

    /**
     * @dev mint BDR token
     */
    function _mint(address target, uint256 value ) internal {
        balances[target] = balances[target].add(value);
        totalSupply = totalSupply.add(value);
        emit Mint(target,value);
    }
}
function setrequestSigners(uint256 _requestSigners) public onlyOwner {
    require(_requestSigners != 0);
    requestSigners = _requestSigners;
}

/**
 * @dev set the number of exchange request in order to execute
 * @param _requestSigners uint256 The number of signers
 */