<commit_before>//
//  ScheduleViewController.swift
//  Eurofurence
//
//  Created by <NAME> on 23/04/2018.
//  Copyright © 2018 Eurofurence. All rights reserved.
//

import UIKit

class ScheduleViewController: UIViewController,
                              UISearchControllerDelegate,
                              UISearchResultsUpdating,
                              UISearchBarDelegate,
                              ScheduleScene {

    // MARK: Properties

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var daysCollectionView: UICollectionView!
    private let refreshControl = UIRefreshControl(frame: .zero)
    private lazy var navigationBarShadowDelegate = HideNavigationBarShadowForSpecificViewControllerDelegate(viewControllerToHideNavigationBarShadow: self)

    private var tableController: TableController? {
        didSet {
            tableView.dataSource = tableController
            tableView.delegate = tableController
            tableView.reloadData()
        }
    }

    private var daysController: DaysController? {
        didSet {
            daysCollectionView.dataSource = daysController
            daysCollectionView.delegate = daysController
        }
    }

    private var searchViewController: ScheduleSearchTableViewController?
    private var searchController: UISearchController?

    @IBAction func openSearch(_ sender: Any) {
        searchController?.isActive = true
    }

    // MARK: Overrides

    override func viewDidLoad() {
        super.viewDidLoad()

        definesPresentationContext = true
        searchViewController = storyboard?.instantiate(ScheduleSearchTableViewController.self)
        searchViewController?.onDidSelectSearchResultAtIndexPath = didSelectSearchResult
        searchController = UISearchController(searchResultsController: searchViewController)
        searchController?.delegate = self
        searchController?.searchBar.delegate = self
        searchController?.searchBar.scopeButtonTitles = [.allEvents, .favourites]
        searchController?.searchResultsUpdater = self

        tableView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(refreshControlDidChangeValue), for: .valueChanged)

        navigationController?.delegate = navigationBarShadowDelegate
        tableView.register(EventTableViewCell.self)
        tableView.register(Header.self, forHeaderFooterViewReuseIdentifier: Header.identifier)
        delegate?.scheduleSceneDidLoad()
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        layoutDaysCollectionView()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        layoutDaysCollectionView()
    }

    // MARK: UISearchBarDelegate

    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        switch selectedScope {
        case 0:
            delegate?.scheduleSceneDidChangeSearchScopeToAllEvents()

        default:
            delegate?.scheduleSceneDidChangeSearchScopeToFavouriteEvents()
        }
    }

    // MARK: UISearchControllerDelegate

    func presentSearchController(_ searchController: UISearchController) {
        present(searchController, animated: true)
    }

    // MARK: UISearchResultsUpdating

    func updateSearchResults(for searchController: UISearchController) {
        if let query = searchController.searchBar.text {
            delegate?.scheduleSceneDidUpdateSearchQuery(query)
        }
    }

    // MARK: EventsScene

    private var delegate: ScheduleSceneDelegate?
    func setDelegate(_ delegate: ScheduleSceneDelegate) {
        self.delegate = delegate
    }

    func setScheduleTitle(_ title: String) {
        super.title = title
    }

    func showRefreshIndicator() {
        refreshControl.beginRefreshing()
    }

    func hideRefreshIndicator() {
        refreshControl.endRefreshing()
    }

    func bind(numberOfDays: Int, using binder: ScheduleDaysBinder) {
        daysController = DaysController(numberOfDays: numberOfDays, binder: binder, onDaySelected: dayPickerDidSelectDay)
    }

    func bind(numberOfItemsPerSection: [Int], using binder: ScheduleSceneBinder) {
        tableController = TableController(numberOfItemsPerSection: numberOfItemsPerSection,
                                          binder: binder,
                                          onDidSelectRow: scheduleTableViewDidSelectRow)
    }

    func bindSearchResults(numberOfItemsPerSection: [Int], using binder: ScheduleSceneSearchResultsBinder) {
        searchViewController?.updateSearchResults(numberOfItemsPerSection: numberOfItemsPerSection, binder: binder)
    }

    func showSearchResults() {
        searchController?.searchResultsController?.view.isHidden = false
    }

    func hideSearchResults() {
        searchController?.searchResultsController?.view.isHidden = true
    }

    func selectDay(at index: Int) {
        daysCollectionView.selectItem(at: IndexPath(item: index, section: 0),
                                      animated: true,
                                      scrollPosition: .centeredHorizontally)
    }

    func deselectEvent(at indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    func deselectSearchResult(at indexPath: IndexPath) {
        searchViewController?.deselectSearchResult(at: indexPath)
    }

    // MARK: Private

    @objc private func refreshControlDidChangeValue() {
        delegate?.scheduleSceneDidPerformRefreshAction()
    }

    private func searchQueryChanged(_ query: String) {
        delegate?.scheduleSceneDidUpdateSearchQuery(query)
    }

    private func didSelectSearchResult(at indexPath: IndexPath) {
        delegate?.scheduleSceneDidSelectSearchResult(at: indexPath)
    }

    private func scheduleTableViewDidSelectRow(_ indexPath: IndexPath) {
        delegate?.scheduleSceneDidSelectEvent(at: indexPath)
    }

    private func dayPickerDidSelectDay(_ index: Int) {
        delegate?.scheduleSceneDidSelectDay(at: index)
    }

    private func layoutDaysCollectionView() {
        daysCollectionView?.collectionViewLayout.invalidateLayout()
    }

    private class Header: UITableViewHeaderFooterView, ScheduleEventGroupHeader {

        static let identifier = "Header"

        func setEventGroupTitle(_ title: String) {
            textLabel?.text = title
        }

    }

    private class TableController: NSObject, UITableViewDataSource, UITableViewDelegate {

        private let numberOfItemsPerSection: [Int]
        private let binder: ScheduleSceneBinder
        private let onDidSelectRow: (IndexPath) -> Void
<commit_msg>Reset search scene appearence on fresh presentations<commit_after>//
//  ScheduleViewController.swift
//  Eurofurence
//
//  Created by <NAME> on 23/04/2018.
//  Copyright © 2018 Eurofurence. All rights reserved.
//

import UIKit

class ScheduleViewController: UIViewController,
                              UISearchControllerDelegate,
                              UISearchResultsUpdating,
                              UISearchBarDelegate,
                              ScheduleScene {

    // MARK: Properties

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var daysCollectionView: UICollectionView!
    private let refreshControl = UIRefreshControl(frame: .zero)
    private lazy var navigationBarShadowDelegate = HideNavigationBarShadowForSpecificViewControllerDelegate(viewControllerToHideNavigationBarShadow: self)

    private var tableController: TableController? {
        didSet {
            tableView.dataSource = tableController
            tableView.delegate = tableController
            tableView.reloadData()
        }
    }

    private var daysController: DaysController? {
        didSet {
            daysCollectionView.dataSource = daysController
            daysCollectionView.delegate = daysController
        }
    }

    private var searchViewController: ScheduleSearchTableViewController?
    private var searchController: UISearchController?

    @IBAction func openSearch(_ sender: Any) {
        searchController?.isActive = true
    }

    // MARK: Overrides

    override func viewDidLoad() {
        super.viewDidLoad()

        definesPresentationContext = true
        searchViewController = storyboard?.instantiate(ScheduleSearchTableViewController.self)
        searchViewController?.onDidSelectSearchResultAtIndexPath = didSelectSearchResult
        searchController = UISearchController(searchResultsController: searchViewController)
        searchController?.delegate = self
        searchController?.searchBar.delegate = self
        searchController?.searchBar.scopeButtonTitles = [.allEvents, .favourites]
        searchController?.searchResultsUpdater = self

        tableView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(refreshControlDidChangeValue), for: .valueChanged)

        navigationController?.delegate = navigationBarShadowDelegate
        tableView.register(EventTableViewCell.self)
        tableView.register(Header.self, forHeaderFooterViewReuseIdentifier: Header.identifier)
        delegate?.scheduleSceneDidLoad()
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        layoutDaysCollectionView()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        layoutDaysCollectionView()
    }

    // MARK: UISearchBarDelegate

    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        switch selectedScope {
        case 0:
            delegate?.scheduleSceneDidChangeSearchScopeToAllEvents()

        default:
            delegate?.scheduleSceneDidChangeSearchScopeToFavouriteEvents()
        }
    }

    // MARK: UISearchControllerDelegate

    func presentSearchController(_ searchController: UISearchController) {
        resetSearchSceneForSearchingAllEvents()
        present(searchController, animated: true)
    }

    // MARK: UISearchResultsUpdating

    func updateSearchResults(for searchController: UISearchController) {
        if let query = searchController.searchBar.text {
            delegate?.scheduleSceneDidUpdateSearchQuery(query)
        }
    }

    // MARK: EventsScene

    private var delegate: ScheduleSceneDelegate?
    func setDelegate(_ delegate: ScheduleSceneDelegate) {
        self.delegate = delegate
    }

    func setScheduleTitle(_ title: String) {
        super.title = title
    }

    func showRefreshIndicator() {
        refreshControl.beginRefreshing()
    }

    func hideRefreshIndicator() {
        refreshControl.endRefreshing()
    }

    func bind(numberOfDays: Int, using binder: ScheduleDaysBinder) {
        daysController = DaysController(numberOfDays: numberOfDays, binder: binder, onDaySelected: dayPickerDidSelectDay)
    }

    func bind(numberOfItemsPerSection: [Int], using binder: ScheduleSceneBinder) {
        tableController = TableController(numberOfItemsPerSection: numberOfItemsPerSection,
                                          binder: binder,
                                          onDidSelectRow: scheduleTableViewDidSelectRow)
    }

    func bindSearchResults(numberOfItemsPerSection: [Int], using binder: ScheduleSceneSearchResultsBinder) {
        searchViewController?.updateSearchResults(numberOfItemsPerSection: numberOfItemsPerSection, binder: binder)
    }

    func showSearchResults() {
        searchController?.searchResultsController?.view.isHidden = false
    }

    func hideSearchResults() {
        searchController?.searchResultsController?.view.isHidden = true
    }

    func selectDay(at index: Int) {
        daysCollectionView.selectItem(at: IndexPath(item: index, section: 0),
                                      animated: true,
                                      scrollPosition: .centeredHorizontally)
    }

    func deselectEvent(at indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    func deselectSearchResult(at indexPath: IndexPath) {
        searchViewController?.deselectSearchResult(at: indexPath)
    }

    // MARK: Private

    @objc private func refreshControlDidChangeValue() {
        delegate?.scheduleSceneDidPerformRefreshAction()
    }

    private func searchQueryChanged(_ query: String) {
        delegate?.scheduleSceneDidUpdateSearchQuery(query)
    }

    private func didSelectSearchResult(at indexPath: IndexPath) {
        delegate?.scheduleSceneDidSelectSearchResult(at: indexPath)
    }

    private func scheduleTableViewDidSelectRow(_ indexPath: IndexPath) {
        delegate?.scheduleSceneDidSelectEvent(at: indexPath)
    }

    private func dayPickerDidSelectDay(_ index: Int) {
        delegate?.scheduleSceneDidSelectDay(at: index)
    }

    private func layoutDaysCollectionView() {
        daysCollectionView?.collectionViewLayout.invalidateLayout()
    }
    
    private func resetSearchSceneForSearchingAllEvents() {
        searchController?.searchBar.selectedScopeButtonIndex = 0
        delegate?.scheduleSceneDidChangeSearchScopeToAllEvents()
    }

    private class Header: UITableViewHeaderFooterView, ScheduleEventGroupHeader {

        static let identifier = "Header"

        func setEventGroupTitle(_ title: String) {
            textLabel?.text = title
        }

    }

    private class TableController: NSObject, UITableViewDataSource, UITableViewDelegate {

        private let numberOfItemsPerSection: [Int]
        private let binder: ScheduleSceneBinder
        private let onDidSelectRow: (IndexPath) -> Void

{'fraction_non_alphanumeric': 0.06801642769651992, 'fraction_numerical': 0.0020894877152532604, 'mean_word_length': 2.996544773970631, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2893110', 'n_tokens_mistral': 3501, 'n_tokens_neox': 3278, 'n_words': 697}