2 // StrengthenListViewController.swift
5 // Created by Hori,Masaki on 2016/12/25.
6 // Copyright © 2016年 Hori,Masaki. All rights reserved.
11 fileprivate let resourceName = "EnhancementListItem2"
12 fileprivate let resourceExtension = "plist"
15 fileprivate struct FilterCategories {
16 static let allType: [EquipmentType] = (1...100).flatMap { EquipmentType(rawValue: $0) }
17 static let canonType: [EquipmentType] = [.smallCaliberMainGun, .mediumCaliberMainGun,
18 .largeCaliberMainGun, .largeCaliberMainGunII]
19 static let torpedoType: [EquipmentType] = [.secondaryGun, .torpedo,
20 .antiAircraftGun, .antiSunmrinerSercher, .submarinTorpedo,
22 static let airplaneType: [EquipmentType] = [.fighter, .bomber, .attacker, .searcher,
23 .airplaneSearcher, .airplaneBomber,
24 .largeAirplane, .airplaneFighter,
25 .landAttecker, .localFighter,
26 .jetFighter, .jetBomber,
27 .jetAttacker, .jetSearcher,
29 static let radarType: [EquipmentType] = [.smallRadar, .largeRadar,
32 static let otherType: [EquipmentType] = {
34 .filter { !canonType.contains($0) }
35 .filter { !torpedoType.contains($0) }
36 .filter { !airplaneType.contains($0) }
37 .filter { !radarType.contains($0) }
40 enum FilterType: Int {
49 let categories: [EquipmentType]
51 init(type: FilterType) {
53 case .all: categories = FilterCategories.allType
54 case .canon: categories = FilterCategories.canonType
55 case .torpedo: categories = FilterCategories.torpedoType
56 case .airplane: categories = FilterCategories.airplaneType
57 case .radar: categories = FilterCategories.radarType
58 case .other: categories = FilterCategories.otherType
63 class StrengthenListViewController: MainTabVIewItemViewController {
65 @IBOutlet weak var tableView: NSTableView!
67 dynamic var itemList: Any { return filteredItems as Any }
68 dynamic var offsetDay: Int = 0 {
69 didSet { buildList() }
71 dynamic var filterType: Int = 0 {
73 if let t = FilterCategories.FilterType(rawValue: filterType) {
74 showsTypes = FilterCategories(type: t).categories
76 showsTypes = FilterCategories.allType
81 override var nibName: String! {
82 return "StrengthenListViewController"
85 fileprivate var filteredItems: [StrengthenListItem] = [] {
86 willSet { willChangeValue(forKey: #keyPath(itemList)) }
87 didSet { didChangeValue(forKey: #keyPath(itemList)) }
90 private let notifier = PeriodicNotifier(hour: 0, minutes: 0)
91 private let plistDownloadNotifier = PeriodicNotifier(hour: 23, minutes: 55)
92 private let downloader = EnhancementListItemDownloader()
93 private var equipmentStrengthenList: [EnhancementListItem] = []
94 private var showsTypes: [EquipmentType] = FilterCategories.allType
96 override func viewDidLoad() {
99 if let url = Bundle.main.url(forResource: resourceName, withExtension: resourceExtension),
100 let data = try? Data(contentsOf: url) {
101 guard let array = NSKeyedUnarchiver.unarchiveObject(with: data) as? [EnhancementListItem]
103 print("\(resourceName).\(resourceExtension) not found.")
106 equipmentStrengthenList = array
110 let nc = NotificationCenter.default
111 nc.addObserver(forName: .Periodic, object: notifier, queue: nil) { [weak self] _ in
112 guard let `self` = self else { return }
115 nc.addObserver(forName: .Periodic, object: plistDownloadNotifier, queue: nil) { [weak self] _ in
116 guard let `self` = self else { return }
126 private func weekdayFiltered() -> [EnhancementListItem] {
127 if offsetDay == -1 { return allItemList() }
129 let currentDay = NSCalendar.current.dateComponents([.weekday], from: Date())
130 var targetWeekday = currentDay.weekday! + offsetDay
131 if targetWeekday > 7 { targetWeekday = 1 }
132 return equipmentStrengthenList.filter { $0.weekday == targetWeekday }
134 private func convert(items: [EnhancementListItem]) -> [StrengthenListItem] {
135 guard let item = items.first else { return [] }
136 let group: StrengthenListItem = StrengthenListGroupItem(type: item.equipmentType)
137 let items: [StrengthenListItem] = items.map(StrengthenListEnhancementItem.init(item:))
138 return [group] + items
140 private func buildList() {
141 let filtered = weekdayFiltered()
142 filteredItems = filtered
143 .map { $0.equipmentType }
145 .filter { showsTypes.contains($0) }
146 .map { type in filtered.filter { $0.equipmentType == type } }
149 private func downloadPList() {
150 downloader.download { [weak self] items in
151 guard let `self` = self else { return }
152 DispatchQueue.main.async {
153 self.equipmentStrengthenList = items
158 private func packSecondShipName(_ items: [EnhancementListItem]) -> [String] {
159 return items.flatMap { $0.secondsShipNames }.unique()
161 private func allItemList() -> [EnhancementListItem] {
162 return equipmentStrengthenList
163 .map { $0.identifier }
165 .map { identifier in equipmentStrengthenList.filter { $0.identifier == identifier } }
166 .flatMap { $0.first?.replace(secondsShipNames: packSecondShipName($0)) }
170 extension StrengthenListViewController: NSTableViewDelegate {
171 func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
172 let item = filteredItems[row]
173 return item.cellType.makeCellWithItem(item: item, tableView: tableView, owner: nil)
175 func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
176 return filteredItems[row] is StrengthenListGroupItem
178 func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
179 let item = filteredItems[row]
180 return item.cellType.estimateCellHeightForItem(item: item, tableView: tableView)
184 fileprivate class EnhancementListItemDownloader: NSObject, URLSessionDownloadDelegate {
188 plistDownloadQueue = OperationQueue()
189 plistDownloadQueue.name = "StrengthenListViewControllerPlistDownloadQueue"
190 plistDownloadQueue.maxConcurrentOperationCount = 1
191 plistDownloadQueue.qualityOfService = .background
192 let configuration = URLSessionConfiguration.default
193 plistDownloadSession = URLSession(configuration: configuration,
195 delegateQueue: plistDownloadQueue)
198 private var plistDownloadSession: URLSession!
199 private var plistDownloadQueue: OperationQueue!
200 private var plistDownloadTask: URLSessionDownloadTask?
201 private var finishOperation: (([EnhancementListItem]) -> Void)?
203 func download(completeHandler: @escaping ([EnhancementListItem]) -> Void) {
204 if let _ = plistDownloadTask { return }
205 // swiftlint:disable:next line_length
206 guard let plistURL = URL(string: "http://git.osdn.jp/view?p=kcd/KCD.git;a=blob;f=KCD/\(resourceName).\(resourceExtension);hb=HEAD")
209 finishOperation = completeHandler
210 plistDownloadTask = plistDownloadSession.downloadTask(with: plistURL)
211 plistDownloadTask?.resume()
214 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
215 plistDownloadTask = nil
216 guard let data = try? Data(contentsOf: location, options: []),
217 let list = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? [EnhancementListItem]
219 finishOperation?(list)
221 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
222 plistDownloadTask = nil