<commit_before>//
//  FaceCameraExtension.swift
//  MyFacePlus
//
//  Created by liqc on 2017/07/10.
//  Copyright © 2017年 RN-079. All rights reserved.
//

import AVFoundation
import UIKit

extension FaceCameraController: AVCaptureVideoDataOutputSampleBufferDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {return}
        
        ciImage = CIImage(cvImageBuffer: imageBuffer)
        if let image = self.filter.outputImage {
            filter.setValue(ciImage, forKey: kCIInputImageKey)
            ciImage = image
        }
        
        // モザイクを選択する場合.
        if viewModel.faceType == .mosaic {
            if let image = FaceManager.shared.makeMosaicFace(with: ciImage, faceObject) {ciImage = image}
        } else if viewModel.faceType == .girl {
            if let image = FaceManager.shared.makeShinFace(with: ciImage, faceObject, 1 -
                slider.value) {ciImage = image}
        }
        
        // fit screen.
        switch orientation {
        case .landscapeRight:
            connection.videoOrientation = .landscapeRight
        case .landscapeLeft:
            connection.videoOrientation = .landscapeLeft
        case .portraitUpsideDown:
            connection.videoOrientation = .portraitUpsideDown
        default:
            connection.videoOrientation = .portrait
        }
        
//        switch orientation {
//        case .portrait:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2.0)))
//        case .portraitUpsideDown:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2.0)))
//        case .landscapeRight:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(Double.pi)))
//        default:
//            break
//        }

        DispatchQueue.main.async {
            if let image = self.ciImage {
                self.previewLayer.contents = self.context.createCGImage(image, from: image.extent)
            }
            // 他の効果を選択した場合
            self.addEffective(self.viewModel.faceType)
        }
    }
    
    /**
     * FaceTypeにより、効果を追加する.
     */
    private func addEffective(_ type: FaceType) {
        switch type {
        case .barca:
            addBarcaView()
            removeSlider()
            removeGlass()
        case .girl:
            addSlider()
            removeBarcaView()
            removeGlass()
        case .glass:
            addGlass()
            removeSlider()
            removeBarcaView()
        default:
            removeBarcaView()
            removeSlider()
            removeGlass()
        }
    }
}

/**
 * face1. barca
 */
extension FaceCameraController {
    fileprivate func addBarcaView() {
        guard let faceObject = faceObject else {
            removeBarcaView()
            return
        }
        
        let faceFrame = FaceManager.shared.getFaceFrame(with: faceObject)
        if barcaView == nil, let tempView = UINib(nibName: "BarcaView", bundle: nil).instantiate(withOwner: self, options: nil).first as? BarcaView {
            barcaView = tempView
            self.view.addSubview(barcaView)
            self.view.bringSubview(toFront: collectionView)
            self.view.bringSubview(toFront: showFaceBtn)
            self.view.bringSubview(toFront: cameraBtn)
            self.view.bringSubview(toFront: closeView)
            self.view.bringSubview(toFront: switchBtn)
        }
        
        barcaView.setIconPosition(faceFrame.origin.x, faceFrame.origin.y, faceFrame.width, faceFrame.height)
        
        let recognizer = UITapGestureRecognizer()
        recognizer.rx.event.bind { [weak self] sender in
            self?.viewModel.mode.value = .normal
        }.addDisposableTo(disposeBag)
        barcaView.addGestureRecognizer(recognizer)
    }
    
    fileprivate func removeBarcaView() {
        if barcaView != nil {
            barcaView.removeFromSuperview()
            barcaView = nil
        }
    }
}

/**
 * face7. glass.
 */
extension FaceCameraController {
    fileprivate func addGlass() {
        guard let ciImage = ciImage else {return}
        let detector = CIDetector(ofType: CIDetectorTypeFace, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
        guard let faceFeatures = detector?.features(in: ciImage) else {return}
        
        var faceFeatureCount = 0
        for feature in faceFeatures {
            guard let faceFeature = feature as? CIFaceFeature else {continue}
            
            faceFeatureCount += 1
            let frame = FaceManager.shared.getFaceFrame(with: faceFeature, ciImage.extent.size)
            if glassView == nil {
                glassView = UIImageView()
                glassView.contentMode = .scaleAspectFit
                glassView.clipsToBounds = true
                glassView.image = UIImage(named: "icon_glasses")
                view.addSubview(glassView)
            }
            glassView.frame = frame
        }
        
        if faceFeatureCount == 0, glassView != nil {
            glassView.removeFromSuperview()
            glassView = nil
        }
    }
    
    fileprivate func removeGlass() {
        if glassView != nil {
            glassView.removeFromSuperview()
            glassView = nil
        }
    }
}

/**
 * face10. modify face
 */
extension FaceCameraController {
    fileprivate func addSlider() {
        slider.isHidden = false
        
//        detectFace()
    }
    
    fileprivate func removeSlider() {
        slider.isHidden = true
        
        if (tempView != nil) {
            tempView.removeFromSuperview()
            tempView = nil
        }
    }
    
    private func detectFace() {
        guard let ciImage = ciImage else {return}<commit_msg>adjust remove glass view's timing<commit_after>//
//  FaceCameraExtension.swift
//  MyFacePlus
//
//  Created by liqc on 2017/07/10.
//  Copyright © 2017年 RN-079. All rights reserved.
//

import AVFoundation
import UIKit

extension FaceCameraController: AVCaptureVideoDataOutputSampleBufferDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {return}
        
        ciImage = CIImage(cvImageBuffer: imageBuffer)
        if let image = self.filter.outputImage {
            filter.setValue(ciImage, forKey: kCIInputImageKey)
            ciImage = image
        }
        
        // モザイクを選択する場合.
        if viewModel.faceType == .mosaic {
            if let image = FaceManager.shared.makeMosaicFace(with: ciImage, faceObject) {ciImage = image}
        } else if viewModel.faceType == .girl {
            if let image = FaceManager.shared.makeShinFace(with: ciImage, faceObject, 1 -
                slider.value) {ciImage = image}
        }
        
        // fit screen.
        switch orientation {
        case .landscapeRight:
            connection.videoOrientation = .landscapeRight
        case .landscapeLeft:
            connection.videoOrientation = .landscapeLeft
        case .portraitUpsideDown:
            connection.videoOrientation = .portraitUpsideDown
        default:
            connection.videoOrientation = .portrait
        }
        
//        switch orientation {
//        case .portrait:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2.0)))
//        case .portraitUpsideDown:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2.0)))
//        case .landscapeRight:
//            ciImage = ciImage?.applying(CGAffineTransform(rotationAngle: CGFloat(Double.pi)))
//        default:
//            break
//        }

        DispatchQueue.main.async {
            if let image = self.ciImage {
                self.previewLayer.contents = self.context.createCGImage(image, from: image.extent)
            }
            // 他の効果を選択した場合
            self.addEffective(self.viewModel.faceType)
        }
    }
    
    /**
     * FaceTypeにより、効果を追加する.
     */
    private func addEffective(_ type: FaceType) {
        switch type {
        case .barca:
            addBarcaView()
            removeSlider()
            removeGlass()
        case .girl:
            addSlider()
            removeBarcaView()
            removeGlass()
        case .glass:
            addGlass()
            removeSlider()
            removeBarcaView()
        default:
            removeBarcaView()
            removeSlider()
            removeGlass()
        }
    }
}

/**
 * face1. barca
 */
extension FaceCameraController {
    fileprivate func addBarcaView() {
        guard let faceObject = faceObject else {
            removeBarcaView()
            return
        }
        
        let faceFrame = FaceManager.shared.getFaceFrame(with: faceObject)
        if barcaView == nil, let tempView = UINib(nibName: "BarcaView", bundle: nil).instantiate(withOwner: self, options: nil).first as? BarcaView {
            barcaView = tempView
            self.view.addSubview(barcaView)
            self.view.bringSubview(toFront: collectionView)
            self.view.bringSubview(toFront: showFaceBtn)
            self.view.bringSubview(toFront: cameraBtn)
            self.view.bringSubview(toFront: closeView)
            self.view.bringSubview(toFront: switchBtn)
        }
        
        barcaView.setIconPosition(faceFrame.origin.x, faceFrame.origin.y, faceFrame.width, faceFrame.height)
        
        let recognizer = UITapGestureRecognizer()
        recognizer.rx.event.bind { [weak self] sender in
            self?.viewModel.mode.value = .normal
        }.addDisposableTo(disposeBag)
        barcaView.addGestureRecognizer(recognizer)
    }
    
    fileprivate func removeBarcaView() {
        if barcaView != nil {
            barcaView.removeFromSuperview()
            barcaView = nil
        }
    }
}

/**
 * face7. glass.
 */
extension FaceCameraController {
    fileprivate func addGlass() {
        guard let ciImage = ciImage else {return}
        let detector = CIDetector(ofType: CIDetectorTypeFace, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
        guard let faceFeatures = detector?.features(in: ciImage) else {return}
        
        var faceFeatureCount = 0
        for feature in faceFeatures {
            guard let faceFeature = feature as? CIFaceFeature else {continue}
            
            faceFeatureCount += 1
            let frame = FaceManager.shared.getFaceFrame(with: faceFeature, ciImage.extent.size)
            if glassView == nil {
                print("11111")
                glassView = UIImageView()
                glassView.contentMode = .scaleAspectFit
                glassView.clipsToBounds = true
                glassView.image = UIImage(named: "icon_glasses")
                view.addSubview(glassView)
            }
            glassView.frame = frame
        }
        
        if faceFeatureCount == 0 && glassView != nil {
            print("2222")
            glassView.removeFromSuperview()
            glassView = nil
        }
        
//        if faceFeatureCount == 0, glassView != nil {
//            glassView.removeFromSuperview()
//            glassView = nil
//        }
    }
    
    fileprivate func removeGlass() {
        if glassView != nil {
            glassView.removeFromSuperview()
            glassView = nil
        }
    }
}

/**
 * face10. modify face
 */
extension FaceCameraController {
    fileprivate func addSlider() {
        slider.isHidden = false
        
//        detectFace()
    }
    
    fileprivate func removeSlider() {
        slider.isHidden = true
        
        if (tempView != nil) {
            tempView.removeFromSuperview()
            tempView = nil
        }
    }
    
    private func detectFace() {
        guard let ciImage = ciImage else {return}
{'fraction_non_alphanumeric': 0.08829095696535835, 'fraction_numerical': 0.005266189418250637, 'mean_word_length': 1.873965476471979, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '803712', 'n_tokens_mistral': 3449, 'n_tokens_neox': 3368, 'n_words': 689}