OSDN Git Service

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]
115                 else {
116                     print("\(resourceName).\(resourceExtension) not found.")
117                     return
118             }
119             
120             equipmentStrengthenList = array
121             buildList()
122         }
123         
124         let nc = NotificationCenter.default
125         nc.addObserver(forName: .Periodic, object: notifier, queue: nil) { [weak self] _ in
126             
127             guard let `self` = self else { return }
128             
129             self.buildList()
130         }
131         
132         nc.addObserver(forName: .Periodic, object: plistDownloadNotifier, queue: nil) { [weak self] _ in
133             
134             guard let `self` = self else { return }
135             
136             self.downloadPList()
137         }
138         
139         #if DEBUG
140 //          downloadPList()
141         #else
142             downloadPList()
143         #endif
144     }
145     
146     private func weekdayFiltered() -> [EnhancementListItem] {
147         
148         if offsetDay == -1 { return allItemList() }
149         
150         let currentDay = NSCalendar.current.dateComponents([.weekday], from: Date())
151         var targetWeekday = currentDay.weekday! + offsetDay
152         if targetWeekday > 7 { targetWeekday = 1 }
153         
154         return equipmentStrengthenList.filter { $0.weekday == targetWeekday }
155     }
156     
157     private func convert(items: [EnhancementListItem]) -> [StrengthenListItem] {
158         
159         guard let item = items.first
160             else { return [] }
161         
162         let group: StrengthenListItem = StrengthenListGroupItem(type: item.equipmentType)
163         let items: [StrengthenListItem] = items.map(StrengthenListEnhancementItem.init(item:))
164         
165         return [group] + items
166     }
167     
168     private func buildList() {
169         
170         let filtered = weekdayFiltered()
171         filteredItems = filtered
172             .map { $0.equipmentType }
173             .unique()
174             .filter { showsTypes.contains($0) }
175             .map { type in filtered.filter { $0.equipmentType == type } }
176             .flatMap(convert)
177     }
178     
179     private func downloadPList() {
180         
181         downloader.download { [weak self] items in
182             
183             guard let `self` = self else { return }
184             
185             DispatchQueue.main.async {
186                 
187                 self.equipmentStrengthenList = items
188                 self.buildList()
189             }
190         }
191     }
192     
193     private func packSecondShipName(_ items: [EnhancementListItem]) -> [String] {
194         
195         return items.flatMap { $0.secondsShipNames }.unique()
196     }
197     
198     private func allItemList() -> [EnhancementListItem] {
199         
200         return equipmentStrengthenList
201             .map { $0.identifier }
202             .unique()
203             .map { identifier in equipmentStrengthenList.filter { $0.identifier == identifier } }
204             .flatMap { $0.first?.replace(secondsShipNames: packSecondShipName($0)) }
205     }
206 }
207
208 extension StrengthenListViewController: NSTableViewDelegate {
209     
210     func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
211         
212         let item = filteredItems[row]
213         return item.cellType.makeCellWithItem(item: item, tableView: tableView, owner: nil)
214     }
215     
216     func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
217         
218         return filteredItems[row] is StrengthenListGroupItem
219     }
220     
221     func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
222         
223         let item = filteredItems[row]
224         
225         return item.cellType.estimateCellHeightForItem(item: item, tableView: tableView)
226     }
227 }
228
229 private final class EnhancementListItemDownloader: NSObject, URLSessionDownloadDelegate {
230     
231     override init() {
232         
233         super.init()
234         
235         plistDownloadQueue = OperationQueue()
236         plistDownloadQueue.name = "StrengthenListViewControllerPlistDownloadQueue"
237         plistDownloadQueue.maxConcurrentOperationCount = 1
238         plistDownloadQueue.qualityOfService = .background
239         
240         let configuration = URLSessionConfiguration.default
241         
242         plistDownloadSession = URLSession(configuration: configuration,
243                                           delegate: self,
244                                           delegateQueue: plistDownloadQueue)
245     }
246     
247     private var plistDownloadSession: URLSession!
248     private var plistDownloadQueue: OperationQueue!
249     private var plistDownloadTask: URLSessionDownloadTask?
250     private var finishOperation: (([EnhancementListItem]) -> Void)?
251     
252     func download(completeHandler: @escaping ([EnhancementListItem]) -> Void) {
253         
254         if let _ = plistDownloadTask { return }
255         
256         guard let plistURL = URL(string: "http://git.osdn.jp/view?p=kcd/KCD.git;a=blob;f=KCD/\(resourceName).\(resourceExtension);hb=HEAD")
257             else { return }
258         
259         finishOperation = completeHandler
260         plistDownloadTask = plistDownloadSession.downloadTask(with: plistURL)
261         plistDownloadTask?.resume()
262     }
263     
264     func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
265         
266         plistDownloadTask = nil
267         
268         guard let data = try? Data(contentsOf: location, options: []),
269             let list = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? [EnhancementListItem]
270             else { return }
271         
272         finishOperation?(list)
273     }
274     
275     func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
276         
277         plistDownloadTask = nil
278     }
279 }