<commit_before>//
//  TWCameraView.swift
//
//  Copyright (c) 2016 <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 Foundation
import UIKit
import AVFoundation

public protocol TWCameraViewDelegate: class {
    func cameraViewDidCaptureImage(image: UIImage, cameraView: TWCameraView)
    func cameraViewDidFailToCaptureImage(error: Error, cameraView: TWCameraView)
}

public class TWCameraView: UIView {
    
    //MARK: Types
    public enum CameraType {
        case front
        case back
    }
    
    //MARK: Public vars
    public weak var delegate: TWCameraViewDelegate?
    
    public var focusPoint = CGPoint(x: 0.5, y: 0.5) {
        
        didSet {
            
            try? updateForFocusPoint()
            
        }
        
    }
    
    public var cameraType: CameraType = .back {
        
        didSet {
            
            if (self.cameraType != oldValue) {
                updateForCameraType()
            }
            
        }
        
    }
    
    public var authorizedForCapture: Bool {
        return AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) == .authorized
    }
    
    //MARK: Camera capture
    fileprivate var frontCameraDeviceInput: AVCaptureDeviceInput?
    fileprivate var backCameraDeviceInput: AVCaptureDeviceInput?
    fileprivate var captureSession: AVCaptureSession?
    fileprivate var photoOutput: AVCapturePhotoOutput?
    
    //MARK: UI
    fileprivate var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
    
    //MARK: Functions
    public override init(frame: CGRect) {
        
        super.init(frame: frame)
        
        self.backgroundColor = UIColor.black
        
        if self.authorizedForCapture {
            setupCaptureSession()
        }
        
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func layoutSubviews() {
        
        super.layoutSubviews()
        
        if let cameraPreviewLayer = self.cameraPreviewLayer {
            
            cameraPreviewLayer.frame = self.bounds
            
            //Set orientation on connection
            if (cameraPreviewLayer.connection.isVideoOrientationSupported) {
                
                switch UIDevice.current.orientation {
                case .portrait, .portraitUpsideDown:
                    cameraPreviewLayer.connection.videoOrientation = .portrait
                case .landscapeRight:
                    cameraPreviewLayer.connection.videoOrientation = .landscapeLeft
                case .landscapeLeft:
                    cameraPreviewLayer.connection.videoOrientation = .landscapeRight
                default:
                    cameraPreviewLayer.connection.videoOrientation = .portrait
                }
                
            }
            
        }
        
    }
    
    //MARK: Capture session
    
    private func setupCaptureSession() {
        
        //Camera devices
        guard let frontCameraDevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .front) else { return }
        guard let backCameraDevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back) else { return }
        
        guard let frontCameraDeviceInput = try? AVCaptureDeviceInput(device: frontCameraDevice) else { return }
        guard let backCameraDeviceInput = try? AVCaptureDeviceInput(device: backCameraDevice) else { return }
        
        self.frontCameraDeviceInput = frontCameraDeviceInput
        self.backCameraDeviceInput = backCameraDeviceInput
        
        //Capture session
        self.captureSession = AVCaptureSession()
        self.captureSession?.sessionPreset = AVCaptureSessionPresetPhoto
        updateForCameraType()
        try? updateForFocusPoint()
        
        //Photo output
        self.photoOutput = AVCapturePhotoOutput()
        self.photoOutput?.isHighResolutionCaptureEnabled = true
        self.captureSession?.addOutput(self.photoOutput!)
        
        //UI
        self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession!)
        self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
        self.cameraPreviewLayer?.frame = self.bounds
        self.layer.addSublayer(self.cameraPreviewLayer!)
        
    }
    
    private func updateForCameraType() {
        
        //Add/remove inputs from capture session as appropriate
        
        guard let captureSession = self.captureSession else { return }
        guard let frontCameraDeviceInput = self.frontCameraDeviceInput else { return }
        guard let backCameraDeviceInput = self.backCameraDeviceInput else { return }
        
        switch self.cameraType {
        case .front:
            
            if !captureSession.inputs.isEmpty {
                self.captureSession?.removeInput(backCameraDeviceInput)
            }
            
            self.captureSession?.addInput(frontCameraDeviceInput)
            
        case .back:
            
            if !captureSession.inputs.isEmpty {
                self.captureSession?.removeInput(frontCameraDeviceInput)
            }
            
            self.captureSession?.addInput(backCameraDeviceInput)
            
        }
        
    }
    
    private func updateForFocusPoint() throws {
        
        guard let frontCameraDeviceInput = self.frontCameraDeviceInput else { return }
        guard let backCameraDeviceInput = self.backCameraDeviceInput else { return }
        
        try frontCameraDeviceInput.device.lockForConfiguration()
        try backCameraDeviceInput.device.lockForConfiguration()
        
        if frontCameraDeviceInput.device.isFocusPointOfInterestSupported {
            frontCameraDeviceInput.device.focusPointOfInterest = self.focusPoint
        }
        
        if backCameraDeviceInput.device.isFocusPointOfInterestSupported {
            backCameraDeviceInput.device.focusPointOfInterest = self.focusPoint
        }
        
        frontCameraDeviceInput.device.unlockForConfiguration()
        backCameraDeviceInput.device.unlockForConfiguration()
        
    }
    
    //MARK: Public camera control functions
    
    public func startPreview(requestPermissionIfNeeded: Bool = true) {
        
        if self.authorizedForCapture {
            
            //Setup if we need to. Normally happens on init, but not if we didn't have permission to start with.
            if self.captureSession == nil {
                setupCaptureSession()
            }
            
            self.captureSession?.startRunning()
            
        }
        else if requestPermissionIfNeeded {
            
            //We don't have permission. Request, then start running.
            requestCapturePermission() { [unowned self] permissionGranted in
                
                if permissionGranted {
                    self.captureSession?.startRunning()
                }
                
            }
            
        }
        
    }
    
    public func stopPreview() {
        
        self.captureSession?.stopRunning()
        
    }
    
    public func capturePhoto(imageStabilization: Bool = true, flashMode: AVCaptureFlashMode = .auto) {
        
        guard let photoOutput = self.photoOutput else { return }
        
        let captureSettings = AVCapturePhotoSettings(format: [ AVVideoCodecKey : AVVideoCodecJPEG ])
        captureSettings.flashMode = flashMode
        captureSettings.isAutoStillImageStabilizationEnabled = imageStabilization
        captureSettings.isHighResolutionPhotoEnabled = true
        
        photoOutput.capturePhoto(with: captureSettings, delegate: self)
        
    }
    
}

//MARK:- Permissions<commit_msg>Fix for flash mode crash<commit_after>//
//  TWCameraView.swift
//
//  Copyright (c) 2016 <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 Foundation
import UIKit
import AVFoundation

public protocol TWCameraViewDelegate: class {
    func cameraViewDidCaptureImage(image: UIImage, cameraView: TWCameraView)
    func cameraViewDidFailToCaptureImage(error: Error, cameraView: TWCameraView)
}

public class TWCameraView: UIView {
    
    //MARK: Types
    public enum CameraType {
        case front
        case back
    }
    
    //MARK: Public vars
    public weak var delegate: TWCameraViewDelegate?
    
    public var focusPoint = CGPoint(x: 0.5, y: 0.5) {
        
        didSet {
            
            try? updateForFocusPoint()
            
        }
        
    }
    
    public var cameraType: CameraType = .back {
        
        didSet {
            
            if (self.cameraType != oldValue) {
                updateForCameraType()
            }
            
        }
        
    }
    
    public var authorizedForCapture: Bool {
        return AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) == .authorized
    }
    
    //MARK: Camera capture
    fileprivate var frontCameraDeviceInput: AVCaptureDeviceInput?
    fileprivate var backCameraDeviceInput: AVCaptureDeviceInput?
    fileprivate var captureSession: AVCaptureSession?
    fileprivate var photoOutput: AVCapturePhotoOutput?
    
    //MARK: UI
    fileprivate var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
    
    //MARK: Functions
    public override init(frame: CGRect) {
        
        super.init(frame: frame)
        
        self.backgroundColor = UIColor.black
        
        if self.authorizedForCapture {
            setupCaptureSession()
        }
        
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func layoutSubviews() {
        
        super.layoutSubviews()
        
        if let cameraPreviewLayer = self.cameraPreviewLayer {
            
            cameraPreviewLayer.frame = self.bounds
            
            //Set orientation on connection
            if (cameraPreviewLayer.connection.isVideoOrientationSupported) {
                
                switch UIDevice.current.orientation {
                case .portrait, .portraitUpsideDown:
                    cameraPreviewLayer.connection.videoOrientation = .portrait
                case .landscapeRight:
                    cameraPreviewLayer.connection.videoOrientation = .landscapeLeft
                case .landscapeLeft:
                    cameraPreviewLayer.connection.videoOrientation = .landscapeRight
                default:
                    cameraPreviewLayer.connection.videoOrientation = .portrait
                }
                
            }
            
        }
        
    }
    
    //MARK: Capture session
    
    private func setupCaptureSession() {
        
        //Camera devices
        guard let frontCameraDevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .front) else { return }
        guard let backCameraDevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back) else { return }
        
        guard let frontCameraDeviceInput = try? AVCaptureDeviceInput(device: frontCameraDevice) else { return }
        guard let backCameraDeviceInput = try? AVCaptureDeviceInput(device: backCameraDevice) else { return }
        
        self.frontCameraDeviceInput = frontCameraDeviceInput
        self.backCameraDeviceInput = backCameraDeviceInput
        
        //Capture session
        self.captureSession = AVCaptureSession()
        self.captureSession?.sessionPreset = AVCaptureSessionPresetPhoto
        updateForCameraType()
        try? updateForFocusPoint()
        
        //Photo output
        self.photoOutput = AVCapturePhotoOutput()
        self.photoOutput?.isHighResolutionCaptureEnabled = true
        self.captureSession?.addOutput(self.photoOutput!)
        
        //UI
        self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession!)
        self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
        self.cameraPreviewLayer?.frame = self.bounds
        self.layer.addSublayer(self.cameraPreviewLayer!)
        
    }
    
    private func updateForCameraType() {
        
        //Add/remove inputs from capture session as appropriate
        
        guard let captureSession = self.captureSession else { return }
        guard let frontCameraDeviceInput = self.frontCameraDeviceInput else { return }
        guard let backCameraDeviceInput = self.backCameraDeviceInput else { return }
        
        switch self.cameraType {
        case .front:
            
            if !captureSession.inputs.isEmpty {
                self.captureSession?.removeInput(backCameraDeviceInput)
            }
            
            self.captureSession?.addInput(frontCameraDeviceInput)
            
        case .back:
            
            if !captureSession.inputs.isEmpty {
                self.captureSession?.removeInput(frontCameraDeviceInput)
            }
            
            self.captureSession?.addInput(backCameraDeviceInput)
            
        }
        
    }
    
    private func updateForFocusPoint() throws {
        
        guard let frontCameraDeviceInput = self.frontCameraDeviceInput else { return }
        guard let backCameraDeviceInput = self.backCameraDeviceInput else { return }
        
        try frontCameraDeviceInput.device.lockForConfiguration()
        try backCameraDeviceInput.device.lockForConfiguration()
        
        if frontCameraDeviceInput.device.isFocusPointOfInterestSupported {
            frontCameraDeviceInput.device.focusPointOfInterest = self.focusPoint
        }
        
        if backCameraDeviceInput.device.isFocusPointOfInterestSupported {
            backCameraDeviceInput.device.focusPointOfInterest = self.focusPoint
        }
        
        frontCameraDeviceInput.device.unlockForConfiguration()
        backCameraDeviceInput.device.unlockForConfiguration()
        
    }
    
    //MARK: Public camera control functions
    
    public func startPreview(requestPermissionIfNeeded: Bool = true) {
        
        if self.authorizedForCapture {
            
            //Setup if we need to. Normally happens on init, but not if we didn't have permission to start with.
            if self.captureSession == nil {
                setupCaptureSession()
            }
            
            self.captureSession?.startRunning()
            
        }
        else if requestPermissionIfNeeded {
            
            //We don't have permission. Request, then start running.
            requestCapturePermission() { [unowned self] permissionGranted in
                
                if permissionGranted {
                    self.captureSession?.startRunning()
                }
                
            }
            
        }
        
    }
    
    public func stopPreview() {
        
        self.captureSession?.stopRunning()
        
    }
    
    public func capturePhoto(imageStabilization: Bool = true, flashMode: AVCaptureFlashMode = .auto) {
        
        guard let photoOutput = self.photoOutput else { return }
        
        let captureSettings = AVCapturePhotoSettings(format: [ AVVideoCodecKey : AVVideoCodecJPEG ])
        
        if let position = self.backCameraDeviceInput?.device.position, position == .back {
            captureSettings.flashMode = flashMode
        }
        
        captureSettings.isAutoStillImageStabilizationEnabled = imageStabilization
        captureSettings.isHighResolutionPhotoEnabled = true
        
        photoOutput.capturePhoto(with: captureSettings, delegate: self)
        
    }
    
}

//MARK:- Permissions
{'fraction_non_alphanumeric': 0.06281937347256165, 'fraction_numerical': 0.0008886914019106865, 'mean_word_length': 2.0730500085338797, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '101357', 'n_tokens_mistral': 4384, 'n_tokens_neox': 4333, 'n_words': 1123}