<commit_before>//
//  DiscoveryWebViewHelper.swift
//  edX
//
//  Created by <NAME> on 11/9/15.
//  Copyright © 2015-2016 edX. All rights reserved.
//

import UIKit
import WebKit

fileprivate enum QueryParameterKeys {
    static let searchQuery = "search_query"
    static let subject = "subject"
}

@objc enum DiscoveryType: Int {
    case course
    case program
}

class DiscoveryWebViewHelper: NSObject {
    
    typealias Environment = OEXConfigProvider & OEXSessionProvider & OEXStylesProvider & OEXRouterProvider & OEXAnalyticsProvider & OEXSessionProvider
    fileprivate let environment: Environment?
    weak var delegate: WebViewNavigationDelegate?
    fileprivate let contentView = UIView()
    fileprivate let webView = WKWebView()
    fileprivate let searchBar = UISearchBar()
    fileprivate lazy var subjectsController: PopularSubjectsViewController = {
        let controller = PopularSubjectsViewController()
        controller.delegate = self
        return controller
    }()
    fileprivate var loadController = LoadStateViewController()
    fileprivate let discoveryType: DiscoveryType
    
    fileprivate var request: URLRequest? = nil
    var baseURL: URL?
    fileprivate let searchQuery:String?
    let bottomBar: UIView?
    private let searchBarEnabled: Bool
    private let showSubjects: Bool
    private var urlObservation: NSKeyValueObservation?
    private var subjectDiscoveryEnabled: Bool = false
    private var subjectsViewHeight: CGFloat {
        return UIDevice.current.userInterfaceIdiom == .pad ? 145 : 125
    }
    fileprivate var params: [String: String]? {
        return (webView.url as NSURL?)?.oex_queryParameters() as? [String : String]
    }
    
    convenience init(environment: Environment?, delegate: WebViewNavigationDelegate?, bottomBar: UIView?, discoveryType: DiscoveryType = .course) {
        self.init(environment: environment, delegate: delegate, bottomBar: bottomBar, showSearch: false, searchQuery: nil, showSubjects: false, discoveryType: discoveryType)
    }
    
    init(environment: Environment?, delegate: WebViewNavigationDelegate?, bottomBar: UIView?, showSearch: Bool, searchQuery: String?, showSubjects: Bool = false, discoveryType: DiscoveryType = .course) {
        self.environment = environment
        self.delegate = delegate
        self.bottomBar = bottomBar
        self.searchQuery = searchQuery
        self.showSubjects = showSubjects
        self.discoveryType = discoveryType
        let discoveryConfig = discoveryType == .program ? environment?.config.discovery.program : environment?.config.discovery.course
        searchBarEnabled = (discoveryConfig?.webview.searchEnabled ?? false) && showSearch
        super.init()
        searchBar.placeholder = discoveryType == .program ? Strings.searchProgramsPlaceholderText : Strings.searchCoursesPlaceholderText
        webView.navigationDelegate = self
        webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal
        webView.accessibilityIdentifier = discoveryType == .course ? "find-courses-webview" : "find-programs-webview"
        
        guard let container = delegate?.webViewContainingController() else { return }
        container.view.addSubview(contentView)
        contentView.snp.makeConstraints { make in
            make.edges.equalTo(container.safeEdges)
        }
        loadController.setupInController(controller: container, contentView: contentView)
        refreshView()
    }
    
    @objc func refreshView() {
        guard let container = delegate?.webViewContainingController() else { return }
        contentView.subviews.forEach { $0.removeFromSuperview() }
        let isUserLoggedIn = environment?.session.currentUser != nil

        subjectDiscoveryEnabled = (environment?.config.discovery.course.webview.subjectFilterEnabled ?? false) && isUserLoggedIn && showSubjects && discoveryType == .course

        var topConstraintItem: ConstraintItem = contentView.snp.top
        if searchBarEnabled {
            searchBar.delegate = self
            contentView.addSubview(searchBar)

            searchBar.snp.makeConstraints{ make in
                make.leading.equalTo(contentView)
                make.trailing.equalTo(contentView)
                make.top.equalTo(contentView)
            }
            topConstraintItem = searchBar.snp.bottom
        }

        if subjectDiscoveryEnabled {
            container.addChildViewController(subjectsController)
            contentView.addSubview(subjectsController.view)
            subjectsController.didMove(toParentViewController: container)
            subjectsController.view.snp.makeConstraints { make in
                make.leading.equalTo(contentView).offset(StandardHorizontalMargin)
                make.trailing.equalTo(contentView)
                make.top.equalTo(topConstraintItem)
                make.height.equalTo(subjectsViewHeight)
            }

            topConstraintItem = subjectsController.view.snp.bottom
        }

        contentView.addSubview(webView)
        if let bar = bottomBar, !isUserLoggedIn {
            contentView.addSubview(bar)
            bar.snp.makeConstraints { make in
                make.leading.equalTo(contentView)
                make.trailing.equalTo(contentView)
                make.bottom.equalTo(contentView)
            }
        }

        webView.snp.makeConstraints { make in
            make.leading.equalTo(contentView)
            make.trailing.equalTo(contentView)
            make.bottom.equalTo(contentView)
            make.top.equalTo(topConstraintItem)
        }

        addObserver()
    }
    
    private func addObserver() {
        if subjectDiscoveryEnabled {
            // Add observation.
            urlObservation = webView.observe(\.url, changeHandler: { [weak self] (webView, change) in
                self?.updateSubjectsVisibility()
            })
        }

        NotificationCenter.default.oex_addObserver(observer: self, name: NOTIFICATION_DYNAMIC_TEXT_TYPE_UPDATE) { (_, observer, _) in
            observer.reload()
        }
    }

    private func reload() {<commit_msg>Feedback changes<commit_after>//
//  DiscoveryWebViewHelper.swift
//  edX
//
//  Created by <NAME> on 11/9/15.
//  Copyright © 2015-2016 edX. All rights reserved.
//

import UIKit
import WebKit

fileprivate enum QueryParameterKeys {
    static let searchQuery = "search_query"
    static let subject = "subject"
}

@objc enum DiscoveryType: Int {
    case course
    case program
}

class DiscoveryWebViewHelper: NSObject {
    
    typealias Environment = OEXConfigProvider & OEXSessionProvider & OEXStylesProvider & OEXRouterProvider & OEXAnalyticsProvider & OEXSessionProvider
    fileprivate let environment: Environment?
    weak var delegate: WebViewNavigationDelegate?
    fileprivate let contentView = UIView()
    fileprivate let webView = WKWebView()
    fileprivate let searchBar = UISearchBar()
    fileprivate lazy var subjectsController: PopularSubjectsViewController = {
        let controller = PopularSubjectsViewController()
        controller.delegate = self
        return controller
    }()
    fileprivate var loadController = LoadStateViewController()
    fileprivate let discoveryType: DiscoveryType
    
    fileprivate var request: URLRequest? = nil
    var baseURL: URL?
    fileprivate let searchQuery:String?
    let bottomBar: UIView?
    private let searchBarEnabled: Bool
    private let showSubjects: Bool
    private var urlObservation: NSKeyValueObservation?
    private var subjectDiscoveryEnabled: Bool = false
    private var subjectsViewHeight: CGFloat {
        return UIDevice.current.userInterfaceIdiom == .pad ? 145 : 125
    }
    fileprivate var params: [String: String]? {
        return (webView.url as NSURL?)?.oex_queryParameters() as? [String : String]
    }
    
    convenience init(environment: Environment?, delegate: WebViewNavigationDelegate?, bottomBar: UIView?, discoveryType: DiscoveryType = .course) {
        self.init(environment: environment, delegate: delegate, bottomBar: bottomBar, showSearch: false, searchQuery: nil, showSubjects: false, discoveryType: discoveryType)
    }
    
    init(environment: Environment?, delegate: WebViewNavigationDelegate?, bottomBar: UIView?, showSearch: Bool, searchQuery: String?, showSubjects: Bool = false, discoveryType: DiscoveryType = .course) {
        self.environment = environment
        self.delegate = delegate
        self.bottomBar = bottomBar
        self.searchQuery = searchQuery
        self.showSubjects = showSubjects
        self.discoveryType = discoveryType
        let discoveryConfig = discoveryType == .program ? environment?.config.discovery.program : environment?.config.discovery.course
        searchBarEnabled = (discoveryConfig?.webview.searchEnabled ?? false) && showSearch
        super.init()
        searchBar.placeholder = discoveryType == .program ? Strings.searchProgramsPlaceholderText : Strings.searchCoursesPlaceholderText
        webView.navigationDelegate = self
        webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal
        webView.accessibilityIdentifier = discoveryType == .course ? "find-courses-webview" : "find-programs-webview"
        
        guard let container = delegate?.webViewContainingController() else { return }
        container.view.addSubview(contentView)
        contentView.snp.makeConstraints { make in
            make.edges.equalTo(container.safeEdges)
        }
        loadController.setupInController(controller: container, contentView: contentView)
        refreshView()
    }
    
    @objc func refreshView() {
        guard let container = delegate?.webViewContainingController() else { return }
        contentView.subviews.forEach { $0.removeFromSuperview() }
        let isUserLoggedIn = environment?.session.currentUser != nil

        subjectDiscoveryEnabled = (environment?.config.discovery.course.webview.subjectFilterEnabled ?? false) && isUserLoggedIn && showSubjects && discoveryType == .course

        var topConstraintItem: ConstraintItem = contentView.snp.top
        if searchBarEnabled {
            searchBar.delegate = self
            contentView.addSubview(searchBar)

            searchBar.snp.makeConstraints{ make in
                make.leading.equalTo(contentView)
                make.trailing.equalTo(contentView)
                make.top.equalTo(contentView)
            }
            topConstraintItem = searchBar.snp.bottom
        }

        if subjectDiscoveryEnabled {
            container.addChildViewController(subjectsController)
            contentView.addSubview(subjectsController.view)
            subjectsController.didMove(toParentViewController: container)
            subjectsController.view.snp.makeConstraints { make in
                make.leading.equalTo(contentView).offset(StandardHorizontalMargin)
                make.trailing.equalTo(contentView)
                make.top.equalTo(topConstraintItem)
                make.height.equalTo(subjectsViewHeight)
            }

            topConstraintItem = subjectsController.view.snp.bottom
        }

        contentView.addSubview(webView)
        if let bar = bottomBar, !isUserLoggedIn {
            contentView.addSubview(bar)
            bar.snp.makeConstraints { make in
                make.leading.equalTo(contentView)
                make.trailing.equalTo(contentView)
                make.bottom.equalTo(contentView)
            }
        }

        webView.snp.makeConstraints { make in
            make.leading.equalTo(contentView)
            make.trailing.equalTo(contentView)
            make.bottom.equalTo(contentView)
            make.top.equalTo(topConstraintItem)
        }

        addObserver()
    }
    
    private func addObserver() {
        // Add URL change oberver on webview, so URL change of webview can be tracked and handled.
        urlObservation = webView.observe(\.url, changeHandler: { [weak self] (webView, change) in
            self?.handleURLChangeNotification()
        })
        
        NotificationCenter.default.oex_addObserver(observer: self, name: NOTIFICATION_DYNAMIC_TEXT_TYPE_UPDATE) { (_, observer, _) in
            observer.reload()
        }
    }
    
    private func handleURLChangeNotification() {
        switch discoveryType {
        case .course:
            if subjectDiscoveryEnabled {
                updateSubjectsVisibility()
            }
            break
        case .program:
            if !URLHasSearchFilter {
                searchBar.text = nil
            }
        }
    }
    
    private var URLHasSearchFilter: Bool {
        guard let URL = webView.url?.absoluteString else { return false }
        
        return URL.contains(find: QueryParameterKeys.searchQuery)
    }

    private func reload() {
{'fraction_non_alphanumeric': 0.07807010695604653, 'fraction_numerical': 0.0031228042782418613, 'mean_word_length': 2.757700205338809, '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': '954927', 'n_tokens_mistral': 3346, 'n_tokens_neox': 3229, 'n_words': 714}