<commit_before>//
//  Main.swift
//  MKHSequence
//
//  Created by <NAME> on 11/26/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

import UIKit

//===

public
class Sequence
{
    // MARK: Nested types and aliases
    
    public
    typealias Task = (previousResult: Any?) -> Any?
    
    public
    typealias CompletionHandler = (previousResult: Any?) -> Void
    
    public
    typealias FailureHandler = (error: NSError?) -> Void
    
    // MARK: Properties - Private
    
    private
    var name: String?
    
    private
    var tasks: [Task] = []
    
    private
    var onComplete: CompletionHandler?
    
    private
    var onFailure: FailureHandler?
    
    private
    var isCancelled = false
    
    // MARK: Properties - Public
    
    public
    static
    var defaultTargetQueue = NSOperationQueue()
    
    public
    var targetQueue: NSOperationQueue!
    
    // MARK: Init
    
    init(name: String? = nil)
    {
        self.name = name
        
        //===
        
        targetQueue = Sequence.defaultTargetQueue
    }
    
    // MARK: Methods - Private
    
    private func executeNext(previousResult: Any? = nil)
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        if self.tasks.count != 0
        {
            // regular block
            
            if let queue = self.targetQueue
            {
                let task = tasks.removeFirst()
                
                //===
                
                queue.addOperationWithBlock({ () -> Void in
                    
                    let result = task(previousResult: previousResult)
                    
                    //===
                    
                    NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                        
                        if !self.isCancelled
                        {
                            // return
                            
                            if let error = result as? NSError
                            {
                                // lets return error and stop execution
                                
                                if let failureHandler = self.onFailure
                                {
                                    failureHandler(error: error);
                                }
                            }
                            else
                            {
                                // continue execution
                                
                                self.executeNext(result)
                            }
                        }
                    })
                })
            }
        }
        else
        {
            // completion block
            
            if let completionHandler = self.onComplete
            {
                completionHandler(previousResult: previousResult);
            }
        }
    }
    
    // MARK: Methods - Public
    
    public func add(task: Task) -> Self
    {
        tasks.append(task)
        
        //===
        
        return self
    }
    
    public func onFailure(failureHandler: FailureHandler) -> Self
    {
        onFailure = failureHandler
        
        //===
        
        return self
    }
    
    public func finally(completionHandler: CompletionHandler) -> Self
    {
        onComplete = completionHandler
        
        //===
        
        start()
        
        //===
        
        return self
    }
    
    public func start() -> Self
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if self.tasks.count != 0
        {
            self.executeNext()
        }
        
        //===
        
        return self
    }
    
    public func cancel()
    {
        isCancelled = true
    }
}<commit_msg>Many improvements to Sequence impleentation<commit_after>//
//  Main.swift
//  MKHSequence
//
//  Created by <NAME> on 11/26/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

import UIKit

//===

public
class Sequence
{
    // MARK: Properties - Private
    
    private
    var name: String?
    
    private
    var tasks: [Task] = []
    
    private
    var onComplete: CompletionHandler?
    
    private
    var onFailure: FailureHandler?
    
    private
    var isCancelled: Bool // calculated helper property
    {
        return status == .Cancelled
    }
    
    private
    var targetTaskIndex = 0
    
    // MARK: Nested types and aliases
    
    public
    typealias Task = (previousResult: Any?) -> Any?
    
    public
    typealias CompletionHandler = (previousResult: Any?) -> Void
    
    public
    typealias FailureHandler = (error: NSError) -> Void
    
    // MARK: Properties - Public
    
    public
    static
    var defaultTargetQueue = NSOperationQueue()
    
    public
    var targetQueue: NSOperationQueue!
    
    public
    enum Status: String
    {
        case
            Pending,
            Processing,
            Failed,
            Completed,
            Cancelled
    }
    
    public private(set)
    var status: Status = .Pending
    
    // MARK: Init
    
    public
    init(name: String? = nil)
    {
        self.name = name
        
        //===
        
        targetQueue = Sequence.defaultTargetQueue
    }
    
    // MARK: Methods - Private
    
    private
    func shouldProceed() -> Bool
    {
        return (targetTaskIndex < self.tasks.count)
    }
    
    private
    func executeNext(previousResult: Any? = nil)
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if
            shouldProceed()
        {
            // regular block
            
            let task = tasks[targetTaskIndex]
            
            //===
            
            targetQueue
                .addOperationWithBlock({ () -> Void in
                    
                    let result = task(previousResult: previousResult)
                    
                    //===
                    
                    NSOperationQueue.mainQueue()
                        .addOperationWithBlock({ () -> Void in
                            
                            if !self.isCancelled
                            {
                                if let error = result as? NSError
                                {
                                    // the task that has been just executed,
                                    // indicated failure by returning NSError,
                                    // lets report error and stop execution
                                    
                                    self.reportFailure(error)
                                }
                                else
                                {
                                    // everything seems to be good,
                                    // lets continue execution
                                    
                                    self.proceed(result)
                                }
                            }
                        })
                })
        }
        else
        {
            executeCompletion(previousResult)
        }
    }
    
    private
    func reportFailure(error: NSError)
    {
        status = .Failed
        
        //===
        
        if let failureHandler = self.onFailure
        {
            failureHandler(error: error);
        }
    }
    
    private
    func proceed(previousResult: Any? = nil)
    {
        targetTaskIndex += 1
        
        //===
        
        executeNext(previousResult)
    }
    
    private
    func executeCompletion(lastResult: Any? = nil)
    {
        status = .Completed
        
        //===
        
        if
            let completionHandler = self.onComplete
        {
            completionHandler(previousResult: lastResult);
        }
    }
    
    private
    func reset() -> Bool
    {
        var result = false
        
        //===
        
        switch status
        {
            case .Failed, .Completed, .Cancelled:
                
                targetTaskIndex = 0
                status = .Pending
                
                //===
                
                result = true
                
            default:
                break // ignore
        }
        
        //===
        
        return result
    }
    
    // MARK: Methods - Public
    
    public
    func add(task: Task) -> Self
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if status == .Pending
        {
            tasks.append(task)
        }
        
        //===
        
        return self
    }
    
    public
    func onFailure(failureHandler: FailureHandler) -> Self
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if status == .Pending
        {
            onFailure = failureHandler
        }
        
        //===
        
        return self
    }
    
    public
    func finally(completionHandler: CompletionHandler) -> Self
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if status == .Pending
        {
            onComplete = completionHandler
            
            //===
            
            start()
        }
        
        //===
        
        return self
    }
    
    public
    func start() -> Self
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if status == .Pending
        {
            status = .Processing
            
            //===
            
            executeNext()
        }
        
        //===
        
        return self
    }
    
    public
    func cancel()
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        switch status
        {
            case .Pending, .Processing:
                status = .Cancelled
            
            default:
                break // ignore
        }
    }
    
    public
    func executeAgain() // (after: NSTimeInterval = 0)
    {
        // NOTE: this mehtod is supposed to be called on main queue
        
        //===
        
        if reset()
        {
            start()
        }
    }
}
{'fraction_non_alphanumeric': 0.07553475935828877, 'fraction_numerical': 0.002482811306340718, 'mean_word_length': 0.8496997527375486, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3997858', 'n_tokens_mistral': 2592, 'n_tokens_neox': 2466, 'n_words': 616}