contract BaseExchangeableToken is BaseExchangeableTokenInterface, BaseFixedERC20Token {
    using SafeMath for uint;

    BaseTokenExchangeInterface public exchange;

    /// @dev Fired if token is change exchange. (extends EIP-823)
    event ExchangeChanged(address _exchange);

    /**
     * @dev Modifier to make a function callable
     *      only when the exchange contract is set.
     */
    modifier whenConfigured() {
        require(exchange != address(0));
        _;
    }

    /**
     * @dev Modifier to make a function callable
     *      only by exchange contract
     */
    modifier onlyExchange() {
        require(msg.sender == address(exchange));
        _;
    }

    // Sender interface
    /// @dev number of tokens exchanged to another tokens for each token address
    mapping(address => uint) private exchangedWith;

    /// @dev number of tokens exchanged to another tokens for each user address
    mapping(address => uint) private exchangedBy;

    // Receiver interface
    /// @dev number of tokens exchanged from another tokens for each token address
    mapping(address => uint) private exchangesReceived;

    /// @dev change exchange for this token. (extends EIP-823)
    function changeExchange(address _exchange) public onlyOwner {
        require(_exchange != address(0));
        exchange = BaseTokenExchangeInterface(_exchange);
        emit ExchangeChanged(_exchange);
    }

    // Sender interface
    /**
     * @dev exchange amount of this token to target token
     * @param _targetContract target token contract
     * @param _amount amount of tokens to exchange
     * @return (true, creditedAmount) on success.
     *          (false, 0) on:
     *              nothing =)
     *          revert on:
     *              exchangeToken in exchange contract return (false, 0)
     *              exchange address is not configured
     *              balance of tokens less then amount to exchange
     */
    function exchangeToken(address _targetContract, uint _amount) public whenConfigured returns (bool success, uint creditedAmount) {
        require(_targetContract != address(0) && _amount <= balances[msg.sender]);
        (success, creditedAmount) = exchange.exchangeToken(_targetContract, _amount);
        if (!success) {
            revert();
        }
        emit Exchange(msg.sender, _targetContract, _amount);
        return (success, creditedAmount);
    }

    /**
     * @dev exchange amount of this token to target token and transfer to specified address
     * @param _targetContract target token contract
     * @param _amount amount of tokens to exchange
     * @param _to address for transferring exchanged tokens
     * @return true on success.
     *          false on:
     *              nothing =)
     *          revert on:
     *              exchangeTokenAndSpend in exchange contract return false
     *              exchange address is not configured
     *              balance of tokens less then amount to exchange
     */
    function exchangeAndSpend(address _targetContract, uint _amount, address _to) public whenConfigured returns (bool success) {
        require(_targetContract != address(0) && _to != address(0) && _amount <= balances[msg.sender]);
        success = exchange.exchangeAndSpend(_targetContract, _amount, _to);
        if (!success) {
            revert();
        }
        emit ExchangeSpent(msg.sender, _targetContract, _to, _amount);
        return success;
    }

    /**
     * @dev send amount of this token to exchange. Must be called only from exchange contract
     * @param _targetContract target token contract
     * @param _exchanger address of user, who exchange tokens
     * @param _amount amount of tokens to exchange
     * @return true on success.
     *          false on:
     *              balance of tokens less then amount to exchange
     *          revert on:
     *              exchange address is not configured
     *              called not by configured exchange address
     */
    function __exchangerCallback(address _targetContract, address _exchanger, uint _amount) public whenConfigured onlyExchange returns (bool success) {
        require(_targetContract != address(0));
        if (_amount > balances[_exchanger]) {
            return false;
        }
        balances[_exchanger] = balances[_exchanger].sub(_amount);
        exchangedWith[_targetContract] = exchangedWith[_targetContract].add(_amount);
        exchangedBy[_exchanger] = exchangedBy[_exchanger].add(_amount);
        return true;
    }

    // Receiver interface
    /**
     * @dev receive amount of tokens from exchange. Must be called only from exchange contract
     * @param _amount amount of tokens to receive
     * @return true on success.
     *          false on:
     *              nothing =)
     *          revert on:
     *              exchange address is not configured
     *              called not by configured exchange address
     */
    function __targetExchangeCallback(uint _amount) public whenConfigured onlyExchange returns (bool success) {
        balances[tx.origin] = balances[tx.origin].add(_amount);
        exchangesReceived[tx.origin] = exchangesReceived[tx.origin].add(_amount);
        emit Exchange(tx.origin, this, _amount);
        return true;
    }

    /**
     * @dev receive amount of tokens from exchange and transfer to specified address. Must be called only from exchange contract
     * @param _amount amount of tokens to receive
     * @param _to address for transferring exchanged tokens
     * @return true on success.
     *          false on:
     *              nothing =)
     *          revert on:
     *              exchange address is not configured
     *              called not by configured exchange address
     */
    function __targetExchangeAndSpendCallback(address _to, uint _amount) public whenConfigured onlyExchange returns (bool success) {
        balances[_to] = balances[_to].add(_amount);
        exchangesReceived[_to] = exchangesReceived[_to].add(_amount);
        emit ExchangeSpent(tx.origin, this, _to, _amount);
        return true;
    }
}
/**
 * @dev ERC20 and EIP-823 (exchangeable) compliant token.
 */
function __targetExchangeCallback(uint _amount) public whenConfigured onlyExchange returns (bool success) {
    balances[tx.origin] = balances[tx.origin].add(_amount);
    exchangesReceived[tx.origin] = exchangesReceived[tx.origin].add(_amount);
    emit Exchange(tx.origin, this, _amount);
    return true;
}

/**
 * @dev receive amount of tokens from exchange. Must be called only from exchange contract
 * @param _amount amount of tokens to receive
 * @return true on success.
 *          false on:
 *              nothing =)
 *          revert on:
 *              exchange address is not configured
 *              called not by configured exchange address
 */