                                           isDealersDenEvent: event.isDealersDen,
                                           isMainStageEvent: event.isMainStage,
                                           isPhotoshootEvent: event.isPhotoshoot)
-        }
-
-    }
-
-    private struct ScheduleEventViewModel: ScheduleEventViewModelProtocol {
-
+                }
+                
+                return ScheduleEventGroupViewModel(title: title, events: viewModels)
+            }
+        }
+        
+        func scheduleEventsDidChange(to events: [Event]) {
+            self.events = events
+            regenerateEventViewModels()
+        }
+        
+        func eventDaysDidChange(to days: [Day]) {
+            self.days = days
+            self.dayViewModels = days.map { (day) -> ScheduleDayViewModel in
+                return ScheduleDayViewModel(title: shortFormDateFormatter.dateString(from: day.date))
+            }
+        }
+        
+        func currentEventDayDidChange(to day: Day?) {
+            guard let day = day else { return }
+            schedule.restrictEvents(to: day)
+            
+            guard let idx = days.index(where: { $0.date == day.date }) else { return }
+            selectedDayIndex = idx
+        }
+        
+        func setDelegate(_ delegate: ScheduleViewModelDelegate) {
+            self.delegate = delegate
+            
+            delegate.scheduleViewModelDidUpdateDays(dayViewModels)
+            delegate.scheduleViewModelDidUpdateEvents(eventGroupViewModels)
+            delegate.scheduleViewModelDidUpdateCurrentDayIndex(to: selectedDayIndex)
+        }
+        
+        func refresh() {
+            refreshService.refreshLocalStore { (_) in }
+        }
+        
+        func showEventsForDay(at index: Int) {
+            let day = days[index]
+            schedule.restrictEvents(to: day)
+        }
+        
+        func identifierForEvent(at indexPath: IndexPath) -> EventIdentifier? {
+            return rawModelGroups[indexPath.section].events[indexPath.row].identifier
+        }
+        
+        func favouriteEvent(at indexPath: IndexPath) {
+            let event = rawModelGroups[indexPath.section].events[indexPath.item]
+            event.favourite()
+        }
+        
+        func unfavouriteEvent(at indexPath: IndexPath) {
+            let event = rawModelGroups[indexPath.section].events[indexPath.item]
+            event.unfavourite()
+        }
+        
+        func refreshServiceDidBeginRefreshing() {
+            delegate?.scheduleViewModelDidBeginRefreshing()
+        }
+        
+        func refreshServiceDidFinishRefreshing() {
+            delegate?.scheduleViewModelDidFinishRefreshing()
+        }
+        
+        func favouriteEventsDidChange(_ identifiers: [EventIdentifier]) {
+            favouriteEvents = identifiers
+            regenerateEventViewModels()
+        }
+        
+    }
+    
+    private class SearchViewModel: ScheduleSearchViewModel, EventsSearchControllerDelegate {
+        
+        private struct EventsGroupedByDate {
+            var date: Date
+            var events: [Event]
+            
+            func compare(against: EventsGroupedByDate) -> Bool {
+                return date < against.date
+            }
+        }
+        
+        private let searchController: EventsSearchController
+        private let eventsService: EventsService
+        private let shortFormDayAndTimeFormatter: ShortFormDayAndTimeFormatter
+        private let hoursDateFormatter: HoursDateFormatter
+        private var rawModelGroups = [EventsGroupedByDate]()
+        private var searchResults = [Event]()
+        private var favouriteEvents = [EventIdentifier]()
+        
+        init(searchController: EventsSearchController,
+             eventsService: EventsService,
+             shortFormDayAndTimeFormatter: ShortFormDayAndTimeFormatter,
+             hoursDateFormatter: HoursDateFormatter) {
+            self.eventsService = eventsService
+            self.searchController = searchController
+            self.hoursDateFormatter = hoursDateFormatter
+            self.shortFormDayAndTimeFormatter = shortFormDayAndTimeFormatter
+            
+            searchController.setResultsDelegate(self)
+        }
+        
+        private var delegate: ScheduleSearchViewModelDelegate?
+        func setDelegate(_ delegate: ScheduleSearchViewModelDelegate) {
+            self.delegate = delegate
+        }
+        
+        func updateSearchResults(input: String) {
+            searchController.changeSearchTerm(input)
+        }
+        
+        func identifierForEvent(at indexPath: IndexPath) -> EventIdentifier? {
+            return rawModelGroups[indexPath.section].events[indexPath.row].identifier
+        }
+        
+        func filterToFavourites() {
+            searchController.restrictResultsToFavourites()
+        }
+        
+        func filterToAllEvents() {
+            searchController.removeFavouritesEventsRestriction()
+        }
+        
+        func searchResultsDidUpdate(to results: [Event]) {
+            searchResults = results
+            regenerateViewModel()
+        }
+        
+        func favouriteEventsDidChange(_ identifiers: [EventIdentifier]) {
+            favouriteEvents = identifiers
+            regenerateViewModel()
+        }
+        
+        func favouriteEvent(at indexPath: IndexPath) {
+            let event = rawModelGroups[indexPath.section].events[indexPath.item]
+            event.favourite()
+        }
+        
+        func unfavouriteEvent(at indexPath: IndexPath) {
+            let event = rawModelGroups[indexPath.section].events[indexPath.item]
+            event.unfavourite()
+        }
+        
+        private func regenerateViewModel() {
+            let groupedByDate = Dictionary(grouping: searchResults, by: { $0.startDate })
+            rawModelGroups = groupedByDate.map(EventsGroupedByDate.init).sorted(by: { (first, second) -> Bool in
+                return first.compare(against: second)
+            })
+            
+            let eventGroupViewModels = rawModelGroups.map(makeScheduleGroupViewModel)
+            
+            delegate?.scheduleSearchResultsUpdated(eventGroupViewModels)
+        }
+        
+        private func makeScheduleGroupViewModel(_ group: EventsGroupedByDate) -> ScheduleEventGroupViewModel {
+            let title = shortFormDayAndTimeFormatter.dayAndHoursString(from: group.date)
+            let viewModels = group.events.map(makeEventViewModel)
+            
+            return ScheduleEventGroupViewModel(title: title, events: viewModels)
+        }
+        
+        private func makeEventViewModel(_ event: Event) -> EventViewModel {
+            return EventViewModel(title: event.title,
+                                  startTime: hoursDateFormatter.hoursString(from: event.startDate),
+                                  endTime: hoursDateFormatter.hoursString(from: event.endDate),
+                                  location: event.room.name,
+                                  bannerGraphicPNGData: event.bannerGraphicPNGData,
+                                  isFavourite: favouriteEvents.contains(event.identifier),
+                                  isSponsorOnly: event.isSponsorOnly,
+                                  isSuperSponsorOnly: event.isSuperSponsorOnly,
+                                  isArtShow: event.isArtShow,
+                                  isKageEvent: event.isKageEvent,
+                                  isDealersDenEvent: event.isDealersDen,
+                                  isMainStageEvent: event.isMainStage,
+                                  isPhotoshootEvent: event.isPhotoshoot)
+        }
+        
+    }
+    
+    private struct EventViewModel: ScheduleEventViewModelProtocol {
+        
         var title: String
         var startTime: String
         var endTime: String

        var isDealersDenEvent: Bool
        var isMainStageEvent: Bool
        var isPhotoshootEvent: Bool

    }

}

import Foundation

class DefaultScheduleInteractor: ScheduleInteractor, EventsServiceObserver {
    
    // MARK: Properties
    
    private let viewModel: ViewModel
    private let searchViewModel: SearchViewModel
    
    // MARK: Initialization
    
    convenience init() {
        self.init(eventsService: SharedModel.instance.services.events,
                  hoursDateFormatter: FoundationHoursDateFormatter.shared,
