contract TestUniswapBridge is
    IUniswapExchangeFactory,
    TestEventsRaiser,
    UniswapBridge
{
    TestToken public wethToken;
    // Token address to TestToken instance.
    mapping (address => TestToken) private _testTokens;
    // Token address to TestExchange instance.
    mapping (address => TestExchange) private _testExchanges;

    constructor() public {
        wethToken = new TestToken();
        _testTokens[address(wethToken)] = wethToken;
    }

    /// @dev Sets the balance of this contract for an existing token.
    ///      The wei attached will be the balance.
    function setTokenBalance(address tokenAddress)
        external
        payable
    {
        TestToken token = _testTokens[tokenAddress];
        token.deposit.value(msg.value)();
    }

    /// @dev Sets the revert reason for an existing token.
    function setTokenRevertReason(address tokenAddress, string calldata revertReason)
        external
    {
        TestToken token = _testTokens[tokenAddress];
        token.setRevertReason(revertReason);
    }

    /// @dev Create a token and exchange (if they don't exist) for a new token
    ///      and sets the exchange revert and fill behavior. The wei attached
    ///      will be the fill amount for the exchange.
    /// @param tokenAddress The token address. If zero, one will be created.
    /// @param revertReason The revert reason for exchange operations.
    function createTokenAndExchange(
        address tokenAddress,
        string calldata revertReason
    )
        external
        payable
        returns (TestToken token, TestExchange exchange)
    {
        token = TestToken(tokenAddress);
        if (tokenAddress == address(0)) {
            token = new TestToken();
        }
        _testTokens[address(token)] = token;
        exchange = _testExchanges[address(token)];
        if (address(exchange) == address(0)) {
            _testExchanges[address(token)] = exchange = new TestExchange(address(token));
        }
        exchange.setFillBehavior.value(msg.value)(revertReason);
        return (token, exchange);
    }

    /// @dev `IUniswapExchangeFactory.getExchange`
    function getExchange(address tokenAddress)
        external
        view
        returns (IUniswapExchange)
    {
        return IUniswapExchange(_testExchanges[tokenAddress]);
    }

    // @dev Use `wethToken`.
    function getWethContract()
        public
        view
        returns (IEtherToken)
    {
        return IEtherToken(address(wethToken));
    }

    // @dev This contract will double as the Uniswap contract.
    function getUniswapExchangeFactoryContract()
        public
        view
        returns (IUniswapExchangeFactory)
    {
        return IUniswapExchangeFactory(address(this));
    }
}
/// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory.
function getUniswapExchangeFactoryContract()
    public
    view
    returns (IUniswapExchangeFactory)
{
    return IUniswapExchangeFactory(address(this));
}

// @dev This contract will double as the Uniswap contract.