OSDN Git Service

コード整形
[kcd/KCD.git] / KCD / ShipMapper.swift
1 //
2 //  ShipMapper.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/02/23.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10 import SwiftyJSON
11
12 fileprivate enum ShipAPI: String {
13     
14     case getMemberShip = "/kcsapi/api_get_member/ship"
15     case port = "/kcsapi/api_port/port"
16     case getMemberShip3 = "/kcsapi/api_get_member/ship3"
17     case kousyouGetShip = "/kcsapi/api_req_kousyou/getship"
18     case getMemberShipDeck = "/kcsapi/api_get_member/ship_deck"
19     case kaisouPowerUp = "/kcsapi/api_req_kaisou/powerup"
20     case kaisouSlotDeprive = "/kcsapi/api_req_kaisou/slot_deprive"
21 }
22
23 fileprivate func dataKeys(_ apiResponse: APIResponse) -> [String] {
24     
25     guard let shipApi = ShipAPI(rawValue: apiResponse.api)
26         else { return ["api_data"] }
27     
28     switch shipApi {
29     case .port: return ["api_data", "api_ship"]
30         
31     case .getMemberShip3: return ["api_data", "api_ship_data"]
32         
33     case .kousyouGetShip: return ["api_data", "api_ship"]
34         
35     case .getMemberShipDeck: return ["api_data", "api_ship_data"]
36         
37     case .kaisouPowerUp: return ["api_data", "api_ship"]
38         
39     case .kaisouSlotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
40         
41     case .getMemberShip: return ["api_data"]
42     }
43 }
44
45 extension MappingConfiguration {
46     
47     func change(dataKeys: [String]) -> MappingConfiguration {
48         
49         return MappingConfiguration(entity: self.entity,
50                                     dataKeys: dataKeys,
51                                     primaryKeys: self.primaryKeys,
52                                     editorStore: self.editorStore,
53                                     ignoreKeys: self.ignoreKeys)
54     }
55 }
56
57 final class ShipMapper: JSONMapper {
58     
59     typealias ObjectType = Ship
60     let apiResponse: APIResponse
61     let configuration: MappingConfiguration<Ship>
62     
63     required init(_ apiResponse: APIResponse) {
64         
65         self.apiResponse = apiResponse
66         self.configuration = MappingConfiguration(entity: Ship.entity,
67                                                   dataKeys: dataKeys(apiResponse),
68                                                   editorStore: ServerDataStore.oneTimeEditor(),
69                                                   ignoreKeys:
70             ["api_gomes", "api_gomes2", "api_broken", "api_powup",
71              "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
72              "api_slotnum", "api_stype", "api_name", "api_yomi",
73              "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
74              "api_taik", "api_houg", "api_houm", "api_tyku",
75              "api_ndock_item", "api_star",
76              "api_ndock_time_str", "api_member_id",
77              "api_fuel_max", "api_bull_max"])
78         
79         // kaisouSlotDepriveでは同時に2種類のデータが入る
80         if let api = ShipAPI(rawValue: apiResponse.api),
81             api == .kaisouSlotDeprive {
82             
83             let conf = self.configuration.change(dataKeys: ["api_data", "api_ship_data", "api_unset_ship"])
84             ShipMapper(apiResponse, configuration: conf).commit()
85         }
86     }
87     
88     private init(_ apiResponse: APIResponse, configuration: MappingConfiguration<Ship>) {
89         
90         self.apiResponse = apiResponse
91         self.configuration = configuration
92     }
93     
94     private var registerIds: [Int] = []
95     private lazy var masterShips: [MasterShip] = {
96         
97         return ServerDataStore.default.sortedMasterShipsById()
98     }()
99     private lazy var slotItems: [SlotItem] = {
100         
101         return ServerDataStore.default.sortedSlotItemsById()
102     }()
103     private var isDeleteNotExist: Bool {
104         
105         guard let shipApi = ShipAPI(rawValue: apiResponse.api)
106             else { return true }
107         
108         switch shipApi {
109         case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
110              .kaisouPowerUp, .kaisouSlotDeprive:
111             return false
112             
113         default:
114             return true
115         }
116     }
117     
118     private var store: ServerDataStore? {
119         
120         return configuration.editorStore as? ServerDataStore
121     }
122     
123     func beginRegister(_ ship: Ship) {
124         
125         ship.sally_area = nil
126     }
127     
128     func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool {
129         
130         // 取得後破棄した装備のデータを削除するため保有IDを保存
131         if key == "api_id" {
132             
133             guard let id = value.int
134                 else { return false }
135             
136             registerIds.append(id)
137             
138             return false
139         }
140         
141         if key == "api_ship_id" {
142             
143             guard let masterId = value.int
144                 else { return false }
145             
146             setMaster(masterId, to: ship)
147             
148             return true
149         }
150         
151         if key == "api_exp" {
152             
153             guard let exp = value[0].int
154                 else { return false }
155             
156             ship.exp = exp
157             
158             return true
159         }
160         
161         if key == "api_slot" {
162             
163             setSlot(value, to: ship)
164             
165             return false
166         }
167         
168         if key == "api_slot_ex" {
169             
170             guard let ex = value.int
171                 else { return false }
172             
173             setExtraSlot(ex, to: ship)
174             
175             return false
176         }
177         
178         return false
179     }
180     
181     func finishOperating() {
182         
183         if !isDeleteNotExist { return }
184         
185         store?.ships(exclude: registerIds).forEach { store?.delete($0) }
186     }
187     
188     private func setMaster(_ masterId: Int, to ship: Ship) {
189         
190         if ship.ship_id == masterId { return }
191         
192         guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
193             let masterShip = store?.object(with: mShip.objectID) as? MasterShip
194             else { return print("Can not convert to current moc object masterShip") }
195         
196         ship.master_ship = masterShip
197         ship.ship_id = masterId
198     }
199     
200     private func setSlot(_ slotItems: JSON, to ship: Ship) {
201         
202         guard let converSlotItems = slotItems.arrayObject as? [Int],
203             let store = store
204             else { return }
205         
206         let newItems: [SlotItem] =
207             converSlotItems.flatMap { item in
208                 
209                 if item == 0 || item == -1 { return nil }
210                 
211                 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
212                     let slotItem = store.object(with: found.objectID) as? SlotItem
213                     else {
214                         
215                         let maxV = converSlotItems.last
216                         if maxV != nil, maxV! < item {
217                             
218                             #if DEBUG
219                                 print("item is maybe unregistered, so it is new ship's equipment.")
220                             #endif
221                             return nil
222                         }
223                         print("Can not convert to current moc object slotItem")
224                         return nil
225                 }
226                 
227                 return slotItem
228         }
229         
230         ship.equippedItem = NSOrderedSet(array: newItems)
231     }
232     
233     private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
234         
235         guard exSlotItem != -1,
236             exSlotItem != 0
237             else { return }
238         
239         guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
240             let ex = store?.object(with: found.objectID) as? SlotItem
241             else { return print("Can not convert to current moc object") }
242         
243         ship.extraItem = ex
244     }
245 }