OSDN Git Service

staticプロパティをインスタンスプロパティに変更
[kcd/KCD.git] / KCD / ShipDetailViewController.swift
1 //
2 //  ShipDetailViewController.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 enum ShipDetailViewType {
12     
13     case full
14     
15     case medium
16     
17     case minimum
18 }
19
20 private func nibNameFor(_ type: ShipDetailViewType) -> NSNib.Name {
21     
22     switch type {
23         
24     case .full: return ShipDetailViewController.nibName
25         
26     case .medium: return NSNib.Name("MediumShipViewController")
27         
28     case .minimum: return NSNib.Name("MediumShipViewController")
29         
30     }
31 }
32
33 final class ShipDetailViewController: NSViewController {
34     
35     let type: ShipDetailViewType
36     @objc let managedObjectContext = ServerDataStore.default.context
37     
38     init?(type: ShipDetailViewType) {
39         
40         self.type = type
41         
42         super.init(nibName: nibNameFor(type), bundle: nil)
43         
44         NotificationCenter.default
45             .addObserver(forName: .DidUpdateGuardEscape, object: nil, queue: nil) { [weak self] _ in
46                 
47                 self?.guardEscaped = self?.ship?.guardEscaped ?? false
48         }
49     }
50     
51     required init?(coder: NSCoder) {
52         
53         fatalError("not implemented")
54     }
55     
56     deinit {
57         
58         damageView.unbind(NSBindingName(#keyPath(DamageView.damageType)))
59         [slot00Field, slot01Field, slot02Field, slot03Field, slot04Field]
60             .forEach { $0?.unbind(NSBindingName(#keyPath(SlotItemLevelView.slotItemID))) }
61     }
62     
63     @IBOutlet private weak var supply: SuppliesView!
64     @IBOutlet private weak var guardEscapedView: GuardEscapedView!
65     @IBOutlet private weak var damageView: DamageView!
66     @IBOutlet private weak var slot00Field: SlotItemLevelView!
67     @IBOutlet private weak var slot01Field: SlotItemLevelView!
68     @IBOutlet private weak var slot02Field: SlotItemLevelView!
69     @IBOutlet private weak var slot03Field: SlotItemLevelView!
70     @IBOutlet private weak var slot04Field: SlotItemLevelView!
71     
72     var observer: ShipSlotObserver?
73     
74     @objc dynamic var guardEscaped: Bool = false {
75         
76         didSet {
77             
78             guardEscapedView.isHidden = !guardEscaped
79         }
80     }
81     
82     @objc dynamic var ship: Ship? {
83         
84         didSet {
85             
86             defer {
87                 
88                 didChangeSlot0()
89                 didChangeSlot1()
90                 didChangeSlot2()
91                 didChangeSlot3()
92                 didChangeSlot4()
93             }
94             
95             supply.ship = ship
96             
97             observer = ship.map { ship in
98                 
99                 let observer  = ShipSlotObserver(ship: ship)
100                 observer.delegate = self
101                 
102                 return observer
103             }
104             
105             // slot の lv, alv の反映のため
106             let fields = [slot00Field, slot01Field, slot02Field, slot03Field, slot04Field]
107             fields.forEach { $0?.unbind(NSBindingName(#keyPath(SlotItemLevelView.slotItemID))) }
108             
109             damageView.unbind(NSBindingName(#keyPath(DamageView.damageType)))
110             
111             if let ship = ship {
112                 
113                 zip(fields, [#keyPath(Ship.slot_0), #keyPath(Ship.slot_1), #keyPath(Ship.slot_2), #keyPath(Ship.slot_3), #keyPath(Ship.slot_4)])
114                     .forEach { feild, keyPath in
115                         
116                         feild?.bind(NSBindingName(#keyPath(SlotItemLevelView.slotItemID)), to: ship, withKeyPath: keyPath)
117                 }
118                 
119                 damageView.bind(NSBindingName(#keyPath(DamageView.damageType)), to: ship, withKeyPath: #keyPath(Ship.status))
120                 
121             } else {
122                 
123                 fields.forEach { $0?.slotItemID = nil }
124                 
125                 damageView.damageType = 0
126             }
127         }
128     }
129     
130     override func viewDidLoad() {
131         
132         super.viewDidLoad()
133         
134         damageView.setFrameOrigin(.zero)
135         view.addSubview(damageView)
136         
137         guardEscapedView.setFrameOrigin(.zero)
138         view.addSubview(guardEscapedView)
139         switch type {
140             
141         case .medium, .minimum:
142             guardEscapedView.controlSize = .mini
143             
144         default: break
145             
146         }
147         
148     }
149 }
150
151 extension ShipDetailViewController: ShipSlotObserverDelegate {
152     
153     func didChangeSlot0() {
154         
155         notifyChangeValue(forKey: #keyPath(planeString0))
156         notifyChangeValue(forKey: #keyPath(planeString0Color))
157     }
158     
159     func didChangeSlot1() {
160         
161         notifyChangeValue(forKey: #keyPath(planeString1))
162         notifyChangeValue(forKey: #keyPath(planeString1Color))
163     }
164     
165     func didChangeSlot2() {
166         
167         notifyChangeValue(forKey: #keyPath(planeString2))
168         notifyChangeValue(forKey: #keyPath(planeString2Color))
169     }
170     
171     func didChangeSlot3() {
172         
173         notifyChangeValue(forKey: #keyPath(planeString3))
174         notifyChangeValue(forKey: #keyPath(planeString3Color))
175     }
176     
177     func didChangeSlot4() {
178         
179         notifyChangeValue(forKey: #keyPath(planeString4))
180         notifyChangeValue(forKey: #keyPath(planeString4Color))
181     }
182 }
183
184 private let allPlaneTypes: [EquipmentType] =
185     [.fighter, .bomber, .attacker, .searcher,
186      .airplaneSearcher, .airplaneBomber,
187      .autoGyro, .antiSunmrinerSercher,
188      .largeAirplane, .airplaneFighter,
189      .jetFighter, .jetBomber, .jetAttacker, .jetSearcher
190 ]
191 extension ShipDetailViewController {
192     
193     // MARK: - Plane count strings
194     private enum PlaneState {
195         
196         case cannotEquip
197         
198         case notEquip(Int)  // current count
199         
200         case equiped(Int, Int)  // current count and max
201     }
202     
203     private func planState(_ index: Int) -> PlaneState {
204         
205         guard let ship = ship else {
206             
207             return .cannotEquip
208         }
209         
210         let itemId = ship.slotItemId(index)
211         let maxCount = ship.slotItemMax(index)
212         
213         if maxCount == 0 {
214             
215             return .cannotEquip
216         }
217         if itemId == -1 {
218             
219             return .notEquip(maxCount)
220         }
221         
222         if let item = ship.slotItem(index),
223             let eqType = EquipmentType(rawValue: item.master_slotItem.type_2),
224             allPlaneTypes.contains(eqType) {
225             
226             return .equiped(ship.slotItemCount(index), maxCount)
227         }
228         
229         return .notEquip(maxCount)
230     }
231     
232     private func planeString(_ index: Int) -> String? {
233         
234         switch planState(index) {
235             
236         case .cannotEquip: return nil
237             
238         case .notEquip(let max): return "\(max)"
239             
240         case .equiped(let count, let max): return "\(count)/\(max)"
241             
242         }
243     }
244     
245     @objc dynamic var planeString0: String? { return planeString(0) }
246     @objc dynamic var planeString1: String? { return planeString(1) }
247     @objc dynamic var planeString2: String? { return planeString(2) }
248     @objc dynamic var planeString3: String? { return planeString(3) }
249     @objc dynamic var planeString4: String? { return planeString(4) }
250     
251     // MARK: - Plane count string color
252     private func planeStringColor(_ index: Int) -> NSColor {
253         
254         switch planState(index) {
255             
256         case .cannotEquip: return NSColor.controlTextColor
257             
258         case .notEquip: return NSColor.disabledControlTextColor
259             
260         case .equiped: return NSColor.controlTextColor
261             
262         }
263     }
264     
265     @objc dynamic var planeString0Color: NSColor { return planeStringColor(0) }
266     @objc dynamic var planeString1Color: NSColor { return planeStringColor(1) }
267     @objc dynamic var planeString2Color: NSColor { return planeStringColor(2) }
268     @objc dynamic var planeString3Color: NSColor { return planeStringColor(3) }
269     @objc dynamic var planeString4Color: NSColor { return planeStringColor(4) }
270 }
271
272 extension ShipDetailViewController: NibLoadable {}