<commit_before>//
//  HomeViewController.swift
//  Eurofurence
//
//  Copyright © 2017 Eurofurence. All rights reserved.
//

import Result
import ReactiveCocoa
import ReactiveSwift
import UIKit
import Changeset

class NewsTableViewController: UITableViewController,
                               UIViewControllerPreviewingDelegate,
                               MessagesViewControllerDelegate,
                               AuthenticationStateObserver {
	@IBOutlet weak var favoritesOnlySegmentedControl: UISegmentedControl!
	@IBOutlet weak var lastSyncLabel: UILabel!

	private var announcementsViewModel: AnnouncementsViewModel = try! ViewModelResolver.container.resolve()
	private var currentEventsViewModel: CurrentEventsViewModel = try! ViewModelResolver.container.resolve()
	private var newsPreferences = UserDetailsNewsPreferences(userDefaults: UserDefaults.standard)
	private var timeService: TimeService = try! ServiceResolver.container.resolve()
	private var disposables = CompositeDisposable()
    private var loggedInUser: User?

	private var announcements: [Announcement] = []
	private var runningEvents: [Event] = []
	private var upcomingEvents: [Event] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        EurofurenceApplication.shared.add(authenticationStateObserver: self)

		favoritesOnlySegmentedControl.selectedSegmentIndex = newsPreferences.doFilterEventFavorites ? 1 : 0

		announcements = announcementsViewModel.Announcements.value
		runningEvents = currentEventsViewModel.RunningEvents.value
		upcomingEvents = currentEventsViewModel.UpcomingEvents.value

		if traitCollection.forceTouchCapability == .available {
			registerForPreviewing(with: self, sourceView: view)
		}

        tableView.estimatedRowHeight = 70
        tableView.rowHeight = UITableViewAutomaticDimension

		tableView.register(UINib(nibName: "EventCell", bundle: nil), forCellReuseIdentifier: "EventCell")
		tableView.register(UINib(nibName: "EventCell", bundle: nil), forCellReuseIdentifier: "EventCellWithoutBanner")

		tableView.register(UINib(nibName: "NewsSectionHeader", bundle: nil), forHeaderFooterViewReuseIdentifier: "NewsSectionHeader")

        self.refreshControl?.addTarget(self, action: #selector(NewsTableViewController.refresh(_:)), for: .valueChanged)

		disposables += lastSyncLabel.reactive.text <~ announcementsViewModel.TimeSinceLastSync.map({
			(timeSinceLastSync: TimeInterval) in
			if timeSinceLastSync > 0.0 {
				return "Last refreshed \(timeSinceLastSync.biggestUnitString) ago"
			}
			return "Last refreshed now"
		})

        disposables += announcementsViewModel.AnnouncementsEdits.signal.observeValues({
            [unowned self] edits in
			DispatchQueue.main.async {
				var edits = edits
				if self.announcements.count == 0 && self.announcementsViewModel.Announcements.value.count > 0 {
					edits.append(Edit<Announcement>(.deletion, value: Announcement(), destination: 0))
				} else if self.announcementsViewModel.Announcements.value.count == 0 {
					edits.append(Edit<Announcement>(.insertion, value: Announcement(), destination: 0))
				}
				self.announcements = self.announcementsViewModel.Announcements.value
				self.tableView.update(with: edits, in: 1)
            }
        })
        disposables += currentEventsViewModel.RunningEventsEdits.signal.observeValues({
            [unowned self] edits in
			DispatchQueue.main.async {
				var edits = edits
				if self.runningEvents.count == 0 && self.currentEventsViewModel.RunningEvents.value.count > 0 {
					edits.append(Edit<Event>(.deletion, value: Event(), destination: 0))
				} else if self.currentEventsViewModel.RunningEvents.value.count == 0 {
					edits.append(Edit<Event>(.insertion, value: Event(), destination: 0))
				}
				self.runningEvents = self.currentEventsViewModel.RunningEvents.value
				self.tableView.update(with: edits, in: 2)
            }
        })
        disposables += currentEventsViewModel.UpcomingEventsEdits.signal.observeValues({
			[unowned self] edits in
            DispatchQueue.main.async {
				var edits = edits
				if self.upcomingEvents.count == 0 && self.currentEventsViewModel.UpcomingEvents.value.count > 0 {
					edits.append(Edit<Event>(.deletion, value: Event(), destination: 0))
				} else if self.currentEventsViewModel.UpcomingEvents.value.count == 0 {
					edits.append(Edit<Event>(.insertion, value: Event(), destination: 0))
				}
				self.upcomingEvents = self.currentEventsViewModel.UpcomingEvents.value
				self.tableView.update(with: edits, in: 3)
            }
        })
        disposables += timeService.currentTime.signal.observeValues({
            [unowned self] value in
            DispatchQueue.main.async {
                if self.timeService.offset.value != 0.0 {
                    self.navigationItem.title = "News @ \(DateFormatters.hourMinute.string(from: value))"
                } else {
                    self.navigationItem.title = "News"
                }
            }
        })

        guard let refreshControl = refreshControl else { return }

        let refreshControlVisibilityDelegate = RefreshControlDataStoreDelegate(refreshControl: refreshControl)
        DataStoreRefreshController.shared.add(refreshControlVisibilityDelegate)
    }

	@IBAction func favoritesOnlyFilterChanged(_ sender: UISegmentedControl) {
		newsPreferences.setFilterEventFavorites(sender.selectedSegmentIndex == 1)
		timeService.tick()
	}

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // Reset the application badge because all announcements can be assumed seen
        UIApplication.shared.applicationIconBadgeNumber = 0
        UIApplication.shared.cancelAllLocalNotifications()
    }

	// TODO: Pull into super class for all refreshable ViewControllers
    /// Initiates sync with API via refreshControl
    func refresh(_ sender: AnyObject) {
		DataStoreRefreshController.shared.refreshStore()
    }

    func notifyAnnouncements(_ announcements: [Announcement]) {
        UIApplication.shared.applicationIconBadgeNumber = 0
        if UserSettings.NotifyOnAnnouncement.currentValueOrDefault() {
            for announcement in announcements {
				let notification = UILocalNotification()
				notification.alertBody = announcement.Title
				notification.timeZone = TimeZone(abbreviation: "UTC")
				notification.fireDate = announcement.ValidFromDateTimeUtc
				notification.soundName = UILocalNotificationDefaultSoundName
				notification.userInfo = ["Announcement": announcement ]
				notification.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1

				UIApplication.shared.presentLocalNotificationNow(notification)
            }
        } else if announcements.count > 0 {
            UIApplication.shared.applicationIconBadgeNumber = announcements.count
        }

        if let tabBarItem = self.navigationController?.tabBarItem, announcements.count > 0 {
            tabBarItem.badgeValue = String(announcements.count)
        }
	}

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

		if let tabBarItem = self.navigationController?.tabBarItem {
			tabBarItem.badgeValue = nil
		}
	}

	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)

		if let tabBarItem = self.navigationController?.tabBarItem {
			tabBarItem.badgeValue = nil
		}

		refreshControl?.endRefreshing()
	}

    // MARK: - Table view data source
<commit_msg>Remove unused function from NewsTableViewController<commit_after>//
//  HomeViewController.swift
//  Eurofurence
//
//  Copyright © 2017 Eurofurence. All rights reserved.
//

import Result
import ReactiveCocoa
import ReactiveSwift
import UIKit
import Changeset

class NewsTableViewController: UITableViewController,
                               UIViewControllerPreviewingDelegate,
                               MessagesViewControllerDelegate,
                               AuthenticationStateObserver {
	@IBOutlet weak var favoritesOnlySegmentedControl: UISegmentedControl!
	@IBOutlet weak var lastSyncLabel: UILabel!

	private var announcementsViewModel: AnnouncementsViewModel = try! ViewModelResolver.container.resolve()
	private var currentEventsViewModel: CurrentEventsViewModel = try! ViewModelResolver.container.resolve()
	private var newsPreferences = UserDetailsNewsPreferences(userDefaults: UserDefaults.standard)
	private var timeService: TimeService = try! ServiceResolver.container.resolve()
	private var disposables = CompositeDisposable()
    private var loggedInUser: User?

	private var announcements: [Announcement] = []
	private var runningEvents: [Event] = []
	private var upcomingEvents: [Event] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        EurofurenceApplication.shared.add(authenticationStateObserver: self)

		favoritesOnlySegmentedControl.selectedSegmentIndex = newsPreferences.doFilterEventFavorites ? 1 : 0

		announcements = announcementsViewModel.Announcements.value
		runningEvents = currentEventsViewModel.RunningEvents.value
		upcomingEvents = currentEventsViewModel.UpcomingEvents.value

		if traitCollection.forceTouchCapability == .available {
			registerForPreviewing(with: self, sourceView: view)
		}

        tableView.estimatedRowHeight = 70
        tableView.rowHeight = UITableViewAutomaticDimension

		tableView.register(UINib(nibName: "EventCell", bundle: nil), forCellReuseIdentifier: "EventCell")
		tableView.register(UINib(nibName: "EventCell", bundle: nil), forCellReuseIdentifier: "EventCellWithoutBanner")

		tableView.register(UINib(nibName: "NewsSectionHeader", bundle: nil), forHeaderFooterViewReuseIdentifier: "NewsSectionHeader")

        self.refreshControl?.addTarget(self, action: #selector(NewsTableViewController.refresh(_:)), for: .valueChanged)

		disposables += lastSyncLabel.reactive.text <~ announcementsViewModel.TimeSinceLastSync.map({
			(timeSinceLastSync: TimeInterval) in
			if timeSinceLastSync > 0.0 {
				return "Last refreshed \(timeSinceLastSync.biggestUnitString) ago"
			}
			return "Last refreshed now"
		})

        disposables += announcementsViewModel.AnnouncementsEdits.signal.observeValues({
            [unowned self] edits in
			DispatchQueue.main.async {
				var edits = edits
				if self.announcements.count == 0 && self.announcementsViewModel.Announcements.value.count > 0 {
					edits.append(Edit<Announcement>(.deletion, value: Announcement(), destination: 0))
				} else if self.announcementsViewModel.Announcements.value.count == 0 {
					edits.append(Edit<Announcement>(.insertion, value: Announcement(), destination: 0))
				}
				self.announcements = self.announcementsViewModel.Announcements.value
				self.tableView.update(with: edits, in: 1)
            }
        })
        disposables += currentEventsViewModel.RunningEventsEdits.signal.observeValues({
            [unowned self] edits in
			DispatchQueue.main.async {
				var edits = edits
				if self.runningEvents.count == 0 && self.currentEventsViewModel.RunningEvents.value.count > 0 {
					edits.append(Edit<Event>(.deletion, value: Event(), destination: 0))
				} else if self.currentEventsViewModel.RunningEvents.value.count == 0 {
					edits.append(Edit<Event>(.insertion, value: Event(), destination: 0))
				}
				self.runningEvents = self.currentEventsViewModel.RunningEvents.value
				self.tableView.update(with: edits, in: 2)
            }
        })
        disposables += currentEventsViewModel.UpcomingEventsEdits.signal.observeValues({
			[unowned self] edits in
            DispatchQueue.main.async {
				var edits = edits
				if self.upcomingEvents.count == 0 && self.currentEventsViewModel.UpcomingEvents.value.count > 0 {
					edits.append(Edit<Event>(.deletion, value: Event(), destination: 0))
				} else if self.currentEventsViewModel.UpcomingEvents.value.count == 0 {
					edits.append(Edit<Event>(.insertion, value: Event(), destination: 0))
				}
				self.upcomingEvents = self.currentEventsViewModel.UpcomingEvents.value
				self.tableView.update(with: edits, in: 3)
            }
        })
        disposables += timeService.currentTime.signal.observeValues({
            [unowned self] value in
            DispatchQueue.main.async {
                if self.timeService.offset.value != 0.0 {
                    self.navigationItem.title = "News @ \(DateFormatters.hourMinute.string(from: value))"
                } else {
                    self.navigationItem.title = "News"
                }
            }
        })

        guard let refreshControl = refreshControl else { return }

        let refreshControlVisibilityDelegate = RefreshControlDataStoreDelegate(refreshControl: refreshControl)
        DataStoreRefreshController.shared.add(refreshControlVisibilityDelegate)
    }

	@IBAction func favoritesOnlyFilterChanged(_ sender: UISegmentedControl) {
		newsPreferences.setFilterEventFavorites(sender.selectedSegmentIndex == 1)
		timeService.tick()
	}

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // Reset the application badge because all announcements can be assumed seen
        UIApplication.shared.applicationIconBadgeNumber = 0
        UIApplication.shared.cancelAllLocalNotifications()
    }

	// TODO: Pull into super class for all refreshable ViewControllers
    /// Initiates sync with API via refreshControl
    func refresh(_ sender: AnyObject) {
		DataStoreRefreshController.shared.refreshStore()
    }

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

		if let tabBarItem = self.navigationController?.tabBarItem {
			tabBarItem.badgeValue = nil
		}
	}

	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)

		if let tabBarItem = self.navigationController?.tabBarItem {
			tabBarItem.badgeValue = nil
		}

		refreshControl?.endRefreshing()
	}

    // MARK: - Table view data source

{'fraction_non_alphanumeric': 0.08845738942826321, 'fraction_numerical': 0.004890327220424308, 'mean_word_length': 3.7107046070460705, 'pattern_counts': {'":': 1, '<': 17, '<?xml version=': 0, '>': 25, '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': '6540473', 'n_tokens_mistral': 4177, 'n_tokens_neox': 3670, 'n_words': 761}