<commit_before>/**
 The MIT License (MIT)
 Copyright (c) 2017 <NAME>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 associated documentation files (the "Software"), to deal in the Software without restriction,
 including without limitation the rights to use, copy, modify, merge, publish, distribute,
 sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 is furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all copies or
 substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import UIKit
import MobileCoreServices
import PhotosUI

fileprivate final class ImagePickerControllerDelegate: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, DelegateProtocol {
    static var delegates = Set<DelegateWrapper<UIImagePickerController, ImagePickerControllerDelegate>>()
    
    fileprivate var didFinishPickingMedia: ((_ withInfo: [String: Any]) -> Void)?
    fileprivate func imagePickerController(_ picker: UIImagePickerController,
                                      didFinishPickingMediaWithInfo info: [String: Any]) {
        didFinishPickingMedia?(info)
    }
    
    fileprivate var didCancel: (() -> Void)?
    fileprivate func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        didCancel?()
    }
    
    override func responds(to aSelector: Selector!) -> Bool {
        switch aSelector {
        case #selector(ImagePickerControllerDelegate.imagePickerController(_:didFinishPickingMediaWithInfo:)):
            return didFinishPickingMedia != nil
        case #selector(ImagePickerControllerDelegate.imagePickerControllerDidCancel(_:)):
            return didCancel != nil
        default:
            return super.responds(to: aSelector)
        }
    }
}

extension UIImagePickerController {
    // MARK: Convenient Presenting
    /**
     This is a convenience initializer that allows you to setup your
     UIImagePickerController with some commonly used default settings.
     In addition, it provides a default handler for a cancelled picker,
     but you are free to provide your own `didCancel` implementation
     using the `didCancel` parameter. The only required parameter is
     the `didPick` closure, which will be called when the user picks
     a medium.
     
     * important: The picker will not be attempted to be dismissed
     after this closure is called, unless you use the
     `present(from:animation:)` method.
     
     * * * *
     #### An example of initializing with this method:
     ```swift
     let picker = UIImagePickerController(
         source: .camera,
         allow: [.image, .movie]) { [weak self] result,picker in
             myImageView.image = result.originalImage
             self?.dismiss(animated: animation.animate)
         }
     }
     ```
     
     * parameter source: The `UIImagePickerControllerSourceType` that
     UIImagePickerController expects to determine where the content
     should be obtained from. This value will be applied to the
     picker's `sourceType` property.
     * parameter allow: A convenience `OptionSet` filter based on `kUTType` Strings.
     These types will be applied to the picker's mediaTypes property.
     * parameter cameraOverlay: This is equivalent to `UIImagePickerController`'s
     `cameraOverlayView` property and will be applied as such.
     * parameter showsCameraControls: This is equivalent to `UIImagePickerController`'s
     `showsCameraControls` property and will be applied as such.
     * parameter didCancel: The closure that is called when the `didCancel` delegate
     method is called. The default is to attempt to dismiss the picker.
     * parameter didPick: The closure that is called when the
     imagePickerController(_:didFinishPickingMediaWithInfo:) is called.
     The closure conveniently wraps the Dictionary obtained from this
     delegate call in a `Result` struct. The original Dictionary can
     be found in the `rawInfo` property.
     */
    public convenience init(source: UIImagePickerControllerSourceType = .photoLibrary,
                            allow: UIImagePickerController.MediaFilter = .image,
                            cameraOverlay: UIView? = nil,
                            showsCameraControls: Bool = true,
                            didCancel: @escaping ( _ picker: UIImagePickerController) -> Void = dismissFromPresenting,
                            didPick: @escaping (_ result: UIImagePickerController.Result, _ picker: UIImagePickerController) -> Void) {
        self.init()
        sourceType = source
        /**
         From UIImagePickerController docs: "You can access this property
         only when the source type of the image picker is set to camera.
         Attempting to access this property for other source types results in
         throwing an invalidArgumentException exception"
         */
        if source == .camera {
            cameraOverlayView = cameraOverlay
            self.showsCameraControls = showsCameraControls
        }
        mediaTypes = UIImagePickerController.MediaFilter.allTypes.flatMap {
            allow.contains($0) ? $0.mediaType : nil
        }
        didFinishPickingMedia { [unowned self] in
            didPick(UIImagePickerController.Result(rawInfo: $0), self)
        }
    }
    
    public static func dismissFromPresenting(_ picker: UIImagePickerController) {
        picker.presentingViewController?.dismiss(animated: true)
    }
    
    /**
     A convenience method that will present the UIImagePickerController. It will
     also do the following as default behavior, which can be overriden at anytime:
     
     1. Default the didCancel callback to dismiss the picker.
     1. Call the didFinishPickingMedia handler if one was set previously, usually
     from the convenience initiaizer's `didPick` parameter or by calling
     the `didFinishPickingMedia(_:)` method.
     1. Dismiss the picker after calling the `didFinishPickingMedia` handler.
     
     * * * *
     #### An example of calling this method using the convenience initializer:
     ```swift
     let picker = UIImagePickerController(
         source: .photoLibrary,
         allow: .image) { result,_ in<commit_msg>Replace deprecated flatMap API with compactMap (#37)<commit_after>/**
 The MIT License (MIT)
 Copyright (c) 2017 <NAME>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 associated documentation files (the "Software"), to deal in the Software without restriction,
 including without limitation the rights to use, copy, modify, merge, publish, distribute,
 sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 is furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all copies or
 substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import UIKit
import MobileCoreServices
import PhotosUI

fileprivate final class ImagePickerControllerDelegate: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, DelegateProtocol {
    static var delegates = Set<DelegateWrapper<UIImagePickerController, ImagePickerControllerDelegate>>()
    
    fileprivate var didFinishPickingMedia: ((_ withInfo: [String: Any]) -> Void)?
    fileprivate func imagePickerController(_ picker: UIImagePickerController,
                                      didFinishPickingMediaWithInfo info: [String: Any]) {
        didFinishPickingMedia?(info)
    }
    
    fileprivate var didCancel: (() -> Void)?
    fileprivate func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        didCancel?()
    }
    
    override func responds(to aSelector: Selector!) -> Bool {
        switch aSelector {
        case #selector(ImagePickerControllerDelegate.imagePickerController(_:didFinishPickingMediaWithInfo:)):
            return didFinishPickingMedia != nil
        case #selector(ImagePickerControllerDelegate.imagePickerControllerDidCancel(_:)):
            return didCancel != nil
        default:
            return super.responds(to: aSelector)
        }
    }
}

extension UIImagePickerController {
    // MARK: Convenient Presenting
    /**
     This is a convenience initializer that allows you to setup your
     UIImagePickerController with some commonly used default settings.
     In addition, it provides a default handler for a cancelled picker,
     but you are free to provide your own `didCancel` implementation
     using the `didCancel` parameter. The only required parameter is
     the `didPick` closure, which will be called when the user picks
     a medium.
     
     * important: The picker will not be attempted to be dismissed
     after this closure is called, unless you use the
     `present(from:animation:)` method.
     
     * * * *
     #### An example of initializing with this method:
     ```swift
     let picker = UIImagePickerController(
         source: .camera,
         allow: [.image, .movie]) { [weak self] result,picker in
             myImageView.image = result.originalImage
             self?.dismiss(animated: animation.animate)
         }
     }
     ```
     
     * parameter source: The `UIImagePickerControllerSourceType` that
     UIImagePickerController expects to determine where the content
     should be obtained from. This value will be applied to the
     picker's `sourceType` property.
     * parameter allow: A convenience `OptionSet` filter based on `kUTType` Strings.
     These types will be applied to the picker's mediaTypes property.
     * parameter cameraOverlay: This is equivalent to `UIImagePickerController`'s
     `cameraOverlayView` property and will be applied as such.
     * parameter showsCameraControls: This is equivalent to `UIImagePickerController`'s
     `showsCameraControls` property and will be applied as such.
     * parameter didCancel: The closure that is called when the `didCancel` delegate
     method is called. The default is to attempt to dismiss the picker.
     * parameter didPick: The closure that is called when the
     imagePickerController(_:didFinishPickingMediaWithInfo:) is called.
     The closure conveniently wraps the Dictionary obtained from this
     delegate call in a `Result` struct. The original Dictionary can
     be found in the `rawInfo` property.
     */
    public convenience init(source: UIImagePickerControllerSourceType = .photoLibrary,
                            allow: UIImagePickerController.MediaFilter = .image,
                            cameraOverlay: UIView? = nil,
                            showsCameraControls: Bool = true,
                            didCancel: @escaping ( _ picker: UIImagePickerController) -> Void = dismissFromPresenting,
                            didPick: @escaping (_ result: UIImagePickerController.Result, _ picker: UIImagePickerController) -> Void) {
        self.init()
        sourceType = source
        /**
         From UIImagePickerController docs: "You can access this property
         only when the source type of the image picker is set to camera.
         Attempting to access this property for other source types results in
         throwing an invalidArgumentException exception"
         */
        if source == .camera {
            cameraOverlayView = cameraOverlay
            self.showsCameraControls = showsCameraControls
        }
        mediaTypes = UIImagePickerController.MediaFilter.allTypes.compactMap {
            allow.contains($0) ? $0.mediaType : nil
        }
        didFinishPickingMedia { [unowned self] in
            didPick(UIImagePickerController.Result(rawInfo: $0), self)
        }
    }
    
    public static func dismissFromPresenting(_ picker: UIImagePickerController) {
        picker.presentingViewController?.dismiss(animated: true)
    }
    
    /**
     A convenience method that will present the UIImagePickerController. It will
     also do the following as default behavior, which can be overriden at anytime:
     
     1. Default the didCancel callback to dismiss the picker.
     1. Call the didFinishPickingMedia handler if one was set previously, usually
     from the convenience initiaizer's `didPick` parameter or by calling
     the `didFinishPickingMedia(_:)` method.
     1. Dismiss the picker after calling the `didFinishPickingMedia` handler.
     
     * * * *
     #### An example of calling this method using the convenience initializer:
     ```swift
     let picker = UIImagePickerController(
         source: .photoLibrary,
         allow: .image) { result,_ in
{'fraction_non_alphanumeric': 0.05970695970695971, 'fraction_numerical': 0.0016117216117216117, 'mean_word_length': 3.028031867807613, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2885311', 'n_tokens_mistral': 3329, 'n_tokens_neox': 3185, 'n_words': 1331}