<commit_before>//
//  MCResourceLoader.swift
//  MCResourceLoader
//
//  Created by Baglan on 28/10/2016.
//  Copyright © 2016 Mobile Creators. All rights reserved.
//

import Foundation

class MCResource {
    var URL: URL?
    
    private var sources = [Source]()
    func add(source: Source) {
        sources.append(source)
    }
    
    private var currentSource: Source?
    private var batch = [Source]()
    private var isAccessing = false
    private var completionHandler: ((URL?, Error?) -> Void)?
    
    func beginAccessing(completionHandler: @escaping (URL?, Error?) -> Void) {
        guard !isAccessing else {
            completionHandler(nil, error(for: .AlreadyAccessing))
            return
        }
        
        guard sources.count > 0 else {
            completionHandler(nil, error(for: .NoSourcesAvailable))
            return
        }
        
        isAccessing = true
        self.completionHandler = completionHandler
        currectOperationQueue = OperationQueue.current
        
        // Copy sources to batch in reversed order
        batch.removeAll()
        batch.append(contentsOf: sources.reversed())
        
        tryNextSource()
    }
    
    func tryNextSource() {
        currentSource?.endAccessing()
        
        guard let source = batch.popLast() else {
            if let completionHandler = completionHandler {
                queue.addOperation { [unowned self] in completionHandler(nil, self.error(for: .RunOutOfSources)) }
            }
            return
        }
        
        currentSource = source
        
        source.beginAccessing { [unowned self] (url, error) in
            if let error = error {
                NSLog("[Error] \(error)")
                self.tryNextSource()
            } else {
                self.URL = source.URL
                if let completionHandler = self.completionHandler {
                    self.queue.addOperation { completionHandler(url, nil) }
                }
            }
        }
    }
    
    func endAccessing() {
        if isAccessing {
            currentSource?.endAccessing()
            isAccessing = false
        }
    }
    
    deinit {
        endAccessing()
    }
    
    // MARK: - Errors
    
    static let errorDomain = "MCResourceErrorDomain"
    enum ErrorCodes: Int {
        case AlreadyAccessing
        case NoSourcesAvailable
        case RunOutOfSources
    }
    
    static let errorDescriptions: [ErrorCodes: String] = [
        .AlreadyAccessing: "Already accessing",
        .NoSourcesAvailable: "No sources available",
        .RunOutOfSources: "All sources failed"
    ]
    
    func error(for code: ErrorCodes) -> Error {
        return NSError(
            domain: MCResource.errorDomain,
            code: code.rawValue,
            userInfo: [
                NSLocalizedDescriptionKey: MCResource.errorDescriptions[code]!
            ]
        )<commit_msg>Changed variable name from "URL" to "localURL" to avoid confusion<commit_after>//
//  MCResourceLoader.swift
//  MCResourceLoader
//
//  Created by Baglan on 28/10/2016.
//  Copyright © 2016 Mobile Creators. All rights reserved.
//

import Foundation

class MCResource {
    var localURL: URL?
    
    private var sources = [Source]()
    func add(source: Source) {
        sources.append(source)
    }
    
    private var currentSource: Source?
    private var batch = [Source]()
    private var isAccessing = false
    private var completionHandler: ((URL?, Error?) -> Void)?
    
    func beginAccessing(completionHandler: @escaping (URL?, Error?) -> Void) {
        guard !isAccessing else {
            completionHandler(nil, error(for: .AlreadyAccessing))
            return
        }
        
        guard sources.count > 0 else {
            completionHandler(nil, error(for: .NoSourcesAvailable))
            return
        }
        
        isAccessing = true
        self.completionHandler = completionHandler
        currectOperationQueue = OperationQueue.current
        
        // Copy sources to batch in reversed order
        batch.removeAll()
        batch.append(contentsOf: sources.reversed())
        
        tryNextSource()
    }
    
    func tryNextSource() {
        currentSource?.endAccessing()
        
        guard let source = batch.popLast() else {
            if let completionHandler = completionHandler {
                queue.addOperation { [unowned self] in completionHandler(nil, self.error(for: .RunOutOfSources)) }
            }
            return
        }
        
        currentSource = source
        
        source.beginAccessing { [unowned self] (url, error) in
            if let error = error {
                NSLog("[Error] \(error)")
                self.tryNextSource()
            } else {
                self.localURL = source.URL
                if let completionHandler = self.completionHandler {
                    self.queue.addOperation { completionHandler(url, nil) }
                }
            }
        }
    }
    
    func endAccessing() {
        if isAccessing {
            currentSource?.endAccessing()
            localURL = nil
            isAccessing = false
        }
    }
    
    deinit {
        endAccessing()
    }
    
    // MARK: - Errors
    
    static let errorDomain = "MCResourceErrorDomain"
    enum ErrorCodes: Int {
        case AlreadyAccessing
        case NoSourcesAvailable
        case RunOutOfSources
    }
    
    static let errorDescriptions: [ErrorCodes: String] = [
        .AlreadyAccessing: "Already accessing",
        .NoSourcesAvailable: "No sources available",
        .RunOutOfSources: "All sources failed"
    ]
    
    func error(for code: ErrorCodes) -> Error {
        return NSError(
            domain: MCResource.errorDomain,
            code: code.rawValue,
            userInfo: [
                NSLocalizedDescriptionKey: MCResource.errorDescriptions[code]!
            ]
        )
{'fraction_non_alphanumeric': 0.08505979450901129, 'fraction_numerical': 0.004379316152939195, 'mean_word_length': 1.7226043099495645, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5182227', 'n_tokens_mistral': 1585, 'n_tokens_neox': 1545, 'n_words': 383}