<commit_before>//
//  ValidatorTextField.swift
//  FormValidatorSwift
//
//  Created by <NAME> on 13/01/2016.
//  Copyright © 2016 ustwo. All rights reserved.
//

import UIKit


public class ValidatorTextField: UITextField, ValidatorControl {
    
    
    // MARK: - Properties
    
    public var shouldAllowViolation = true
    public var validateOnFocusLossOnly = false
    public let validator: Validator
    public weak var validatorDelegate: ValidatorControlDelegate?
    
    public var validatableText: String? {
        return text
    }
    
    private var validatorControlResponder: ValidatorTextFieldResponder?
    
    
    // MARK: - Initializers
    
    public convenience init(validator: Validator) {
        self.init(frame: CGRect.zero, validator: validator)
    }
    
    public init(frame: CGRect, validator: Validator) {
        self.validator = validator
        
        super.init(frame: frame)
        
        setup()
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("Not implemented.")
    }
    
    deinit {
        guard let responder = validatorControlResponder else {
            return
        }
        
        NSNotificationCenter.defaultCenter().removeObserver(responder, name: UITextFieldTextDidChangeNotification, object: self)
        NSNotificationCenter.defaultCenter().removeObserver(responder, name: UITextFieldTextDidEndEditingNotification, object: self)
    }
    
    
    // MARK: - Setup
    
    private func setup() {
        let responder = ValidatorTextFieldResponder(validatorTextField: self)
        validatorControlResponder = responder
        super.delegate = responder
        
        NSNotificationCenter.defaultCenter().addObserver(responder, selector: Selector("textFieldDidChange:"), name: UITextFieldTextDidChangeNotification, object: self)
        NSNotificationCenter.defaultCenter().addObserver(responder, selector: Selector("textFieldDidEndEditing:"), name: UITextFieldTextDidEndEditingNotification, object: self)
    }
    
    
    // MARK: - Callbacks on state change
    
    public func validatorTextFieldSuccededConditions() { }
    
    public func validatorTextFieldViolatedConditions(conditions: [Condition]) { }
    
}


internal class ValidatorTextFieldResponder: NSObject, UITextFieldDelegate {
    
    
    // MARK: - Properties
    
    var validatorTextField: ValidatorTextField
    
    weak var delegate: protocol<ValidatorControlDelegate, UITextFieldDelegate>?
    
    private var didEndEditing   = false
    private var lastIsValid     = false
    
    
    // MARK: - Initializers
    
    init(validatorTextField: ValidatorTextField) {
        self.validatorTextField = validatorTextField
    }
    
    
    // MARK: - UITextFieldDelegate
    
    @objc func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        guard let sourceText = textField.text else {
            return false
        }
        
        let originalString = NSString(string: sourceText)
        
        let futureString = originalString.stringByReplacingCharactersInRange(range, withString: string)
        let conditions = validatorTextField.validator.checkConditions(futureString)
        
        if let conditions = conditions {
            validatorTextField.validatorTextFieldViolatedConditions(conditions)
        } else {
            validatorTextField.validatorTextFieldSuccededConditions()
        }
        
        if !validatorTextField.validateOnFocusLossOnly && range.location != 0,
            let conditions = conditions
            where (!validatorTextField.shouldAllowViolation || conditions[0].shouldAllowViolation) {
                return false
        }
        
        if let result = delegate?.textField?(validatorTextField, shouldChangeCharactersInRange: range, replacementString: string) {
            return result
        }
        
        return true
    }
    
    func textFieldDidChange(notification: NSNotification) {
        defer {
            // Inform delegate about changes
            delegate?.validatorControlDidChange(validatorTextField)
        }
        
        // Only validate if violations are allowed
        //  Validate according to `validateOnFocusLossOnly` while editing first time or after focus loss
        guard validatorTextField.shouldAllowViolation &&
            (!validatorTextField.validateOnFocusLossOnly || (validatorTextField.validateOnFocusLossOnly && didEndEditing)) else {
            return
        }
        
        let conditions = validatorTextField.validator.checkConditions(validatorTextField.text)
        let isValid = conditions == nil
        if lastIsValid != isValid {
            lastIsValid = isValid
            
            // Inform the text field about valid state change
            if isValid {
                validatorTextField.validatorTextFieldSuccededConditions()
            } else {
                validatorTextField.validatorTextFieldViolatedConditions(conditions!)
            }
            
            // Inform delegate about valid state change
            delegate?.validatorControl(validatorTextField, changedValidState: isValid)
            
            if !isValid {
                // Inform delegatate about violation
                delegate?.validatorControl(validatorTextField, violatedConditions: conditions!)
            }
        }
    }
    
    @objc func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldBeginEditing?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldDidBeginEditing(textField: UITextField) {
        delegate?.textFieldDidBeginEditing?(validatorTextField)
    }
    
    @objc func textFieldShouldEndEditing(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldEndEditing?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldDidEndEditing(textField: UITextField) {
        didEndEditing = true
        
        textFieldDidChange(NSNotification())
        
        delegate?.textFieldDidEndEditing?(validatorTextField)
    }
    
    @objc func textFieldShouldClear(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldClear?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldShouldReturn(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldReturn?(validatorTextField) {
            return result
        }
        
        return true
    }
    
}<commit_msg>Fix inappropriate use of NSNotification constructor causing crash<commit_after>//
//  ValidatorTextField.swift
//  FormValidatorSwift
//
//  Created by <NAME> on 13/01/2016.
//  Copyright © 2016 ustwo. All rights reserved.
//

import UIKit


public class ValidatorTextField: UITextField, ValidatorControl {
    
    
    // MARK: - Properties
    
    public var shouldAllowViolation = true
    public var validateOnFocusLossOnly = false
    public let validator: Validator
    public weak var validatorDelegate: ValidatorControlDelegate?
    
    public var validatableText: String? {
        return text
    }
    
    private var validatorControlResponder: ValidatorTextFieldResponder?
    
    
    // MARK: - Initializers
    
    public convenience init(validator: Validator) {
        self.init(frame: CGRect.zero, validator: validator)
    }
    
    public init(frame: CGRect, validator: Validator) {
        self.validator = validator
        
        super.init(frame: frame)
        
        setup()
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("Not implemented.")
    }
    
    deinit {
        guard let responder = validatorControlResponder else {
            return
        }
        
        NSNotificationCenter.defaultCenter().removeObserver(responder, name: UITextFieldTextDidChangeNotification, object: self)
        NSNotificationCenter.defaultCenter().removeObserver(responder, name: UITextFieldTextDidEndEditingNotification, object: self)
    }
    
    
    // MARK: - Setup
    
    private func setup() {
        let responder = ValidatorTextFieldResponder(validatorTextField: self)
        validatorControlResponder = responder
        super.delegate = responder
        
        NSNotificationCenter.defaultCenter().addObserver(responder, selector: Selector("textFieldDidChange:"), name: UITextFieldTextDidChangeNotification, object: self)
        NSNotificationCenter.defaultCenter().addObserver(responder, selector: Selector("textFieldDidEndEditing:"), name: UITextFieldTextDidEndEditingNotification, object: self)
    }
    
    
    // MARK: - Callbacks on state change
    
    public func validatorTextFieldSuccededConditions() { }
    
    public func validatorTextFieldViolatedConditions(conditions: [Condition]) { }
    
}


internal class ValidatorTextFieldResponder: NSObject, UITextFieldDelegate {
    
    
    // MARK: - Properties
    
    var validatorTextField: ValidatorTextField
    
    weak var delegate: protocol<ValidatorControlDelegate, UITextFieldDelegate>?
    
    private var didEndEditing   = false
    private var lastIsValid     = false
    
    
    // MARK: - Initializers
    
    init(validatorTextField: ValidatorTextField) {
        self.validatorTextField = validatorTextField
    }
    
    
    // MARK: - UITextFieldDelegate
    
    @objc func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        guard let sourceText = textField.text else {
            return false
        }
        
        let originalString = NSString(string: sourceText)
        
        let futureString = originalString.stringByReplacingCharactersInRange(range, withString: string)
        let conditions = validatorTextField.validator.checkConditions(futureString)
        
        if let conditions = conditions {
            validatorTextField.validatorTextFieldViolatedConditions(conditions)
        } else {
            validatorTextField.validatorTextFieldSuccededConditions()
        }
        
        if !validatorTextField.validateOnFocusLossOnly && range.location != 0,
            let conditions = conditions
            where (!validatorTextField.shouldAllowViolation || conditions[0].shouldAllowViolation) {
                return false
        }
        
        if let result = delegate?.textField?(validatorTextField, shouldChangeCharactersInRange: range, replacementString: string) {
            return result
        }
        
        return true
    }
    
    func textFieldDidChange(notification: NSNotification?) {
        defer {
            // Inform delegate about changes
            delegate?.validatorControlDidChange(validatorTextField)
        }
        
        // Only validate if violations are allowed
        //  Validate according to `validateOnFocusLossOnly` while editing first time or after focus loss
        guard validatorTextField.shouldAllowViolation &&
            (!validatorTextField.validateOnFocusLossOnly || (validatorTextField.validateOnFocusLossOnly && didEndEditing)) else {
            return
        }
        
        let conditions = validatorTextField.validator.checkConditions(validatorTextField.text)
        let isValid = conditions == nil
        if lastIsValid != isValid {
            lastIsValid = isValid
            
            // Inform the text field about valid state change
            if isValid {
                validatorTextField.validatorTextFieldSuccededConditions()
            } else {
                validatorTextField.validatorTextFieldViolatedConditions(conditions!)
            }
            
            // Inform delegate about valid state change
            delegate?.validatorControl(validatorTextField, changedValidState: isValid)
            
            if !isValid {
                // Inform delegatate about violation
                delegate?.validatorControl(validatorTextField, violatedConditions: conditions!)
            }
        }
    }
    
    @objc func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldBeginEditing?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldDidBeginEditing(textField: UITextField) {
        delegate?.textFieldDidBeginEditing?(validatorTextField)
    }
    
    @objc func textFieldShouldEndEditing(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldEndEditing?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldDidEndEditing(textField: UITextField) {
        didEndEditing = true
        
        textFieldDidChange(nil)
        
        delegate?.textFieldDidEndEditing?(validatorTextField)
    }
    
    @objc func textFieldShouldClear(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldClear?(validatorTextField) {
            return result
        }
        
        return true
    }
    
    @objc func textFieldShouldReturn(textField: UITextField) -> Bool {
        if let result = delegate?.textFieldShouldReturn?(validatorTextField) {
            return result
        }
        
        return true
    }
    
}
{'fraction_non_alphanumeric': 0.06698670605612998, 'fraction_numerical': 0.00206794682422452, 'mean_word_length': 2.3633879781420766, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, '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': '1201681', 'n_tokens_mistral': 3418, 'n_tokens_neox': 3364, 'n_words': 743}