contract MockSynthetixPriceSource is Ownable, ISynthetixExchangeRates {
    using SafeMath for uint256;

    mapping(bytes32 => uint256) private fixedRate;
    mapping(bytes32 => AggregatorInfo) private currencyKeyToAggregator;

    enum RateAsset {ETH, USD}

    struct AggregatorInfo {
        address aggregator;
        RateAsset rateAsset;
    }

    constructor(address _ethUsdAggregator) public {
        currencyKeyToAggregator[bytes32("ETH")] = AggregatorInfo({
            aggregator: _ethUsdAggregator,
            rateAsset: RateAsset.USD
        });
    }

    function setPriceSourcesForCurrencyKeys(
        bytes32[] calldata _currencyKeys,
        address[] calldata _aggregators,
        RateAsset[] calldata _rateAssets
    ) external onlyOwner {
        require(
            _currencyKeys.length == _aggregators.length &&
                _rateAssets.length == _aggregators.length
        );
        for (uint256 i = 0; i < _currencyKeys.length; i++) {
            currencyKeyToAggregator[_currencyKeys[i]] = AggregatorInfo({
                aggregator: _aggregators[i],
                rateAsset: _rateAssets[i]
            });
        }
    }

    function setRate(bytes32 _currencyKey, uint256 _rate) external onlyOwner {
        fixedRate[_currencyKey] = _rate;
    }

    /// @dev Calculates the rate from a currencty key against its RateAsset
    /// TODO: Use CentralizedRateProvider to randomize and make consistent with the rest
    function rateAndInvalid(bytes32 _currencyKey)
        external
        view
        override
        returns (uint256 rate_, bool isInvalid_)
    {
        uint256 storedRate = getFixedRate(_currencyKey);
        if (storedRate != 0) {
            rate_ = storedRate;
        } else {
            AggregatorInfo memory aggregatorInfo = getAggregatorFromCurrencyKey(_currencyKey);
            address aggregator = aggregatorInfo.aggregator;

            if (aggregator != address(0)) {
                uint256 decimals = MockChainlinkPriceSource(aggregator).decimals();
                rate_ = uint256(MockChainlinkPriceSource(aggregator).latestAnswer()).mul(
                    10**(uint256(18).sub(decimals))
                );

                if (aggregatorInfo.rateAsset == RateAsset.ETH) {
                    uint256 ethToUsd = uint256(
                        MockChainlinkPriceSource(
                            getAggregatorFromCurrencyKey(bytes32("ETH"))
                                .aggregator
                        )
                            .latestAnswer()
                    );
                    rate_ = rate_.mul(ethToUsd).div(10**8);
                }
            }
        }

        isInvalid_ = (rate_ == 0);
        return (rate_, isInvalid_);
    }

    ///////////////////
    // STATE GETTERS //
    ///////////////////

    function getAggregatorFromCurrencyKey(bytes32 _currencyKey)
        public
        view
        returns (AggregatorInfo memory _aggregator)
    {
        return currencyKeyToAggregator[_currencyKey];
    }

    function getFixedRate(bytes32 _currencyKey) public view returns (uint256) {
        return fixedRate[_currencyKey];
    }
}
/// @dev This price source offers two different options getting prices
/// The first one is getting a fixed rate, which can be useful for tests
/// The second approach calculates dinamically the rate making use of a chainlink price source
/// Mocks the functionality of the folllowing Synthetix contracts: { Exchanger, ExchangeRates }
function rateAndInvalid(bytes32 _currencyKey)
    external
    view
    override
    returns (uint256 rate_, bool isInvalid_)
{
    uint256 storedRate = getFixedRate(_currencyKey);
    if (storedRate != 0) {
        rate_ = storedRate;
    } else {
        AggregatorInfo memory aggregatorInfo = getAggregatorFromCurrencyKey(_currencyKey);
        address aggregator = aggregatorInfo.aggregator;

        if (aggregator != address(0)) {
            uint256 decimals = MockChainlinkPriceSource(aggregator).decimals();
            rate_ = uint256(MockChainlinkPriceSource(aggregator).latestAnswer()).mul(
                10**(uint256(18).sub(decimals))
            );

            if (aggregatorInfo.rateAsset == RateAsset.ETH) {
                uint256 ethToUsd = uint256(
                    MockChainlinkPriceSource(
                        getAggregatorFromCurrencyKey(bytes32("ETH"))
                            .aggregator
                    )
                        .latestAnswer()
                );
                rate_ = rate_.mul(ethToUsd).div(10**8);
            }
        }
    }

    isInvalid_ = (rate_ == 0);
    return (rate_, isInvalid_);
}

/// @dev Calculates the rate from a currencty key against its RateAsset
/// TODO: Use CentralizedRateProvider to randomize and make consistent with the rest