 //
 
 import Foundation
+import Result
+
+// MARK: - Protocol: Quote Type
 
 protocol FXQuoteType {
     var ticker: String { get }


// MARK: - FX Providers

struct Providers { }

// MARK: - Yahoo

extension Providers {

    struct Yahoo: FXProviderType {
        typealias RequestType = NSURLSessionDataTask

        let name = "Yahoo"

        func quote(ticker: String, completion: FXQuote -> Void) -> NSURLSessionDataTask {
            guard let url = NSURL(string: "http://download.finance.yahoo.com/d/quotes.csv?s=\(ticker)=X&f=nl1d1t1") else {
                fatalError("Unable to construct URL for Yahoo Finance API")
            }

            let request = NSURLRequest(URL: url)
            let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
            let task = session.dataTaskWithRequest(request) { data, response, error in
                // Result is a string like this:
                // "GBP/EUR",1.3994,"11/2/2015","4:51pm"

                // To start with, split by comma
                if let data = data, str = String(data: data, encoding: NSUTF8StringEncoding) {
                    let components = str.componentsSeparatedByString(",")
                    if components.endIndex >= 1, let rate = Double(components[1]) {
                        completion(FXQuote(ticker: ticker, rate: BankersDecimal(floatLiteral: rate), date: NSDate()))
                    }
                }
            }
            return task
        }
    }
}




 In addition to FX exchanges, a provide will have its 
 own characteristics, such as a name and fee structure.
*/
protocol FXProviderType {

    typealias RequestType
    typealias QuoteType: FXQuoteType

    /// The name of the provider.
    static var name: String { get }

    static var URLSession: NSURLSession { get }

    static func requestForBaseCurrencyCode(base: String, symbol: String) -> NSURLRequest

    static func exchangeRateFromResponseData(data: NSData) -> Result<QuoteType, FX.Error>
}

// MARK: - MoneyType

extension MoneyType where DecimalStorageType == BankersDecimal.DecimalStorageType {

    func convertWithRate<Other: MoneyType where Other.DecimalStorageType == DecimalStorageType>(rate: BankersDecimal) -> Other {
        return multiplyBy(Other(storage: rate.storage), withBehaviors: Other.DecimalNumberBehavior.decimalNumberBehaviors)
    }

    func exchange<T: FXTransactionType, Provider: FXProviderType where T.Money.DecimalStorageType == DecimalStorageType, Provider.RequestType == NSURLSessionDataTask>(completion: Result<T, FX.Error> -> Void) -> Provider.RequestType {
        let client = FXServiceProviderNetworkClient(session: Provider.URLSession)
        let request = Provider.requestForBaseCurrencyCode(Currency.code, symbol: T.Money.Currency.code)
        return client.get(request, adaptor: Provider.exchangeRateFromResponseData) { result in
            return result.map { T(money: self.convertWithRate($0.rate)) }
        }
    }
}
