OSDN Git Service

buildEquipmentEnhancementListをSwift4.0に更新
[kcd/KCD.git] / KCD / StrengthenListViewController.swift
1 //
2 //  StrengthenListViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/25.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 private let resourceName = "EnhancementListItem2"
12 private let resourceExtension = "plist"
13
14
15 private struct FilterCategories {
16     
17     static let allType: [EquipmentType] = (1...100).flatMap { EquipmentType(rawValue: $0) }
18     static let canonType: [EquipmentType] = [.smallCaliberMainGun, .mediumCaliberMainGun,
19                                              .largeCaliberMainGun, .largeCaliberMainGunII]
20     static let torpedoType: [EquipmentType] = [.secondaryGun, .torpedo,
21                                                .antiAircraftGun, .antiSunmrinerSercher, .submarinTorpedo,
22                                                .largeSonar]
23     static let airplaneType: [EquipmentType] = [.fighter, .bomber, .attacker, .searcher,
24                                                 .airplaneSearcher, .airplaneBomber,
25                                                 .largeAirplane, .airplaneFighter,
26                                                 .landAttecker, .localFighter,
27                                                 .jetFighter, .jetBomber,
28                                                 .jetAttacker, .jetSearcher,
29                                                 .searcherII]
30     static let radarType: [EquipmentType] = [.smallRadar, .largeRadar,
31                                              .sonar, .depthCharge,
32                                              .submarineEquipment]
33     static let otherType: [EquipmentType] = {
34         return allType
35             .filter { !canonType.contains($0) }
36             .filter { !torpedoType.contains($0) }
37             .filter { !airplaneType.contains($0) }
38             .filter { !radarType.contains($0) }
39     }()
40     
41     enum FilterType: Int {
42         
43         case all = 0
44         case canon
45         case torpedo
46         case airplane
47         case radar
48         case other
49     }
50     
51     let categories: [EquipmentType]
52     
53     init(type: FilterType) {
54         
55         switch type {
56         case .all: categories = FilterCategories.allType
57         case .canon: categories = FilterCategories.canonType
58         case .torpedo: categories = FilterCategories.torpedoType
59         case .airplane: categories = FilterCategories.airplaneType
60         case .radar: categories = FilterCategories.radarType
61         case .other: categories = FilterCategories.otherType
62         }
63     }
64 }
65
66 final class StrengthenListViewController: MainTabVIewItemViewController {
67     
68     @IBOutlet weak var tableView: NSTableView!
69     
70     @objc dynamic var itemList: Any { return filteredItems as Any }
71     @objc dynamic var offsetDay: Int = 0 {
72         
73         didSet { buildList() }
74     }
75     @objc dynamic var filterType: Int = 0 {
76         
77         didSet {
78             if let t = FilterCategories.FilterType(rawValue: filterType) {
79                 
80                 showsTypes = FilterCategories(type: t).categories
81                 
82             } else {
83                 
84                 showsTypes = FilterCategories.allType
85             }
86             buildList()
87         }
88     }
89     
90     override var nibName: NSNib.Name {
91         
92         return .nibName(instanceOf: self)
93     }
94     
95     private var filteredItems: [StrengthenListItem] = [] {
96         
97         willSet { willChangeValue(forKey: #keyPath(itemList)) }
98         didSet { didChangeValue(forKey: #keyPath(itemList)) }
99     }
100     
101     private let notifier = PeriodicNotifier(hour: 0, minutes: 0)
102     private let plistDownloadNotifier = PeriodicNotifier(hour: 23, minutes: 55)
103     private let downloader = EnhancementListItemDownloader()
104     private var equipmentStrengthenList: [EnhancementListItem] = []
105     private var showsTypes: [EquipmentType] = FilterCategories.allType
106     
107     override func viewDidLoad() {
108         
109         super.viewDidLoad()
110         
111         if let url = Bundle.main.url(forResource: resourceName, withExtension: resourceExtension),
112             let data = try? Data(contentsOf: url) {
113             
114             guard let array = NSKeyedUnarchiver.unarchiveObject(with: data) as? [EnhancementListItem] else {
115                 
116                 return Logger.shared.log("\(resourceName).\(resourceExtension) not found.")
117             }
118             
119             equipmentStrengthenList = array
120             buildList()
121         }
122         
123         let nc = NotificationCenter.default
124         nc.addObserver(forName: .Periodic, object: notifier, queue: nil) { [weak self] _ in
125             
126             self?.buildList()
127         }
128         
129         nc.addObserver(forName: .Periodic, object: plistDownloadNotifier, queue: nil) { [weak self] _ in
130             
131             self?.downloadPList()
132         }
133         
134         #if DEBUG
135 //          downloadPList()
136         #else
137             downloadPList()
138         #endif
139     }
140     
141     private func weekdayFiltered() -> [EnhancementListItem] {
142         
143         if offsetDay == -1 { return allItemList() }
144         
145         let currentDay = NSCalendar.current.dateComponents([.weekday], from: Date())
146         var targetWeekday = currentDay.weekday! + offsetDay
147         if targetWeekday > 7 { targetWeekday = 1 }
148         
149         return equipmentStrengthenList.filter { $0.weekday == targetWeekday }
150     }
151     
152     private func convert(items: [EnhancementListItem]) -> [StrengthenListItem] {
153         
154         guard let item = items.first else { return [] }
155         
156         let group: StrengthenListItem = StrengthenListGroupItem(type: item.equipmentType)
157         let items: [StrengthenListItem] = items.map(StrengthenListEnhancementItem.init(item:))
158         
159         return [group] + items
160     }
161     
162     private func buildList() {
163         
164         let filtered = weekdayFiltered()
165         filteredItems = filtered
166             .map { $0.equipmentType }
167             .unique()
168             .filter { showsTypes.contains($0) }
169             .map { type in filtered.filter { $0.equipmentType == type } }
170             .flatMap(convert)
171     }
172     
173     private func downloadPList() {
174         
175         downloader.download { [weak self] items in
176             
177             guard let `self` = self else { return }
178             
179             DispatchQueue.main.async {
180                 
181                 self.equipmentStrengthenList = items
182                 self.buildList()
183             }
184         }
185     }
186     
187     private func packSecondShipName(_ items: [EnhancementListItem]) -> [String] {
188         
189         return items.flatMap { $0.secondsShipNames }.unique()
190     }
191     
192     private func allItemList() -> [EnhancementListItem] {
193         
194         return equipmentStrengthenList
195             .map { $0.identifier }
196             .unique()
197             .map { identifier in equipmentStrengthenList.filter { $0.identifier == identifier } }
198             .flatMap { $0.first?.replace(secondsShipNames: packSecondShipName($0)) }
199     }
200 }
201
202 extension StrengthenListViewController: NSTableViewDelegate {
203     
204     func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
205         
206         let item = filteredItems[row]
207         return item.cellType.makeCellWithItem(item: item, tableView: tableView, owner: nil)
208     }
209     
210     func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
211         
212         return filteredItems[row] is StrengthenListGroupItem
213     }
214     
215     func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
216         
217         let item = filteredItems[row]
218         
219         return item.cellType.estimateCellHeightForItem(item: item, tableView: tableView)
220     }
221 }
222
223 private final class EnhancementListItemDownloader: NSObject, URLSessionDownloadDelegate {
224     
225     override init() {
226         
227         super.init()
228         
229         plistDownloadQueue = OperationQueue()
230         plistDownloadQueue.name = "StrengthenListViewControllerPlistDownloadQueue"
231         plistDownloadQueue.maxConcurrentOperationCount = 1
232         plistDownloadQueue.qualityOfService = .background
233         
234         let configuration = URLSessionConfiguration.default
235         
236         plistDownloadSession = URLSession(configuration: configuration,
237                                           delegate: self,
238                                           delegateQueue: plistDownloadQueue)
239     }
240     
241     private var plistDownloadSession: URLSession!
242     private var plistDownloadQueue: OperationQueue!
243     private var plistDownloadTask: URLSessionDownloadTask?
244     private var finishOperation: (([EnhancementListItem]) -> Void)?
245     
246     func download(completeHandler: @escaping ([EnhancementListItem]) -> Void) {
247         
248         if let _ = plistDownloadTask { return }
249         
250         guard let plistURL = URL(string: "http://git.osdn.jp/view?p=kcd/KCD.git;a=blob;f=KCD/\(resourceName).\(resourceExtension);hb=HEAD") else { return }
251         
252         finishOperation = completeHandler
253         plistDownloadTask = plistDownloadSession.downloadTask(with: plistURL)
254         plistDownloadTask?.resume()
255     }
256     
257     func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
258         
259         plistDownloadTask = nil
260         
261         guard let data = try? Data(contentsOf: location, options: []) else { return }
262         guard let list = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? [EnhancementListItem] else { return }
263         
264         finishOperation?(list)
265     }
266     
267     func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
268         
269         plistDownloadTask = nil
270     }
271 }