5 // Created by Hori,Masaki on 2017/02/23.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
12 final class ShipMapper: JSONMapper {
14 private static let ignoreKeys = ["api_gomes", "api_gomes2", "api_broken", "api_powup",
15 "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
16 "api_slotnum", "api_stype", "api_name", "api_yomi",
17 "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
18 "api_taik", "api_houg", "api_houm", "api_tyku",
19 "api_ndock_item", "api_star",
20 "api_ndock_time_str", "api_member_id",
21 "api_fuel_max", "api_bull_max"]
23 let apiResponse: APIResponse
24 let configuration: MappingConfiguration<Ship>
26 required init(_ apiResponse: APIResponse) {
28 self.apiResponse = apiResponse
29 self.configuration = MappingConfiguration(entity: Ship.entity,
30 dataKeys: ShipMapper.dataKeys(apiResponse),
31 editorStore: ServerDataStore.oneTimeEditor(),
32 ignoreKeys: ShipMapper.ignoreKeys)
35 // slotDepriveの時に2種類のデータが来るため
36 init(forSlotDepriveUnset apiResponse: APIResponse) {
38 self.apiResponse = apiResponse
39 self.configuration = MappingConfiguration(entity: Ship.entity,
40 dataKeys: ["api_data", "api_ship_data", "api_unset_ship"],
41 editorStore: ServerDataStore.oneTimeEditor(),
42 ignoreKeys: ShipMapper.ignoreKeys)
45 private class func dataKeys(_ apiResponse: APIResponse) -> [String] {
47 switch apiResponse.api.endpoint {
49 case .port, .getShip, .powerup: return ["api_data", "api_ship"]
51 case .ship3, .shipDeck: return ["api_data", "api_ship_data"]
53 case .slotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
55 case .ship, .ship2: return ["api_data"]
57 default: return Logger.shared.log("Missing API: \(apiResponse.api)", value: ["api_data"])
61 private var registerIds: [Int] = []
62 private lazy var masterShips: [MasterShip] = {
64 guard let store = configuration.editorStore as? ServerDataStore else { return [] }
66 return store.sortedMasterShipsById()
69 private lazy var slotItems: [SlotItem] = {
71 guard let store = configuration.editorStore as? ServerDataStore else { return [] }
73 return store.sortedSlotItemsById()
76 private var needsDeleteUnregisteredShip: Bool {
78 switch apiResponse.api.endpoint {
79 case .ship3, .getShip, .shipDeck, .powerup, .slotDeprive:
83 // 特殊任務のクリア時にship2がapi_shipid付きでリクエストされ、その艦娘のデータしかない時があるため
84 return !apiResponse.parameter["api_shipid"].valid
91 private var store: ServerDataStore? {
93 return configuration.editorStore as? ServerDataStore
96 func beginRegister(_ ship: Ship) {
101 func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool {
103 // 取得後破棄した装備のデータを削除するため保有IDを保存
106 guard let id = value.int else { return false }
108 registerIds.append(id)
113 if key == "api_ship_id" {
115 guard let masterId = value.int else { return false }
117 if ship.ship_id == masterId { return true }
119 setMaster(masterId, to: ship)
124 if key == "api_exp" {
126 guard let exp = value[0].int else { return false }
128 if ship.exp == exp { return true }
135 if key == "api_slot" {
137 setSlot(value, to: ship)
142 if key == "api_slot_ex" {
144 guard let ex = value.int else {
150 if ship.slot_ex == ex { return true }
152 setExtraSlot(ex, to: ship)
162 func finishOperating() {
164 if !needsDeleteUnregisteredShip { return }
166 store?.ships(exclude: registerIds).forEach { store?.delete($0) }
169 private func setMaster(_ masterId: Int, to ship: Ship) {
171 guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
172 let masterShip = store?.exchange(mShip) else {
174 return Logger.shared.log("Can not convert to current moc object masterShip")
177 ship.master_ship = masterShip
178 ship.ship_id = masterId
181 private func setSlot(_ slotItems: JSON, to ship: Ship) {
183 guard let convertedSlotItems = slotItems.arrayObject as? [Int] else { return }
184 guard let store = store else { return }
186 let newItems: [SlotItem] = convertedSlotItems
187 .filter { $0 != 0 && $0 != -1 }
190 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
191 let slotItem = store.exchange(found) else {
193 let maxV = convertedSlotItems.last
194 if maxV != nil, maxV! < item {
196 Debug.print("item is maybe unregistered, so it is new ship's equipment.")
199 Logger.shared.log("Can not convert to current moc object slotItem")
206 ship.equippedItem = NSOrderedSet(array: newItems)
209 private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
211 guard exSlotItem != -1, exSlotItem != 0 else {
215 guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
216 let ex = store?.exchange(found) else {
218 return Logger.shared.log("Can not convert to current moc object")