5 // Created by Hori,Masaki on 2017/02/23.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
12 fileprivate enum ShipAPI: String {
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"
23 fileprivate func dataKeys(_ apiResponse: APIResponse) -> [String] {
25 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
26 else { return ["api_data"] }
29 case .port: return ["api_data", "api_ship"]
31 case .getMemberShip3: return ["api_data", "api_ship_data"]
33 case .kousyouGetShip: return ["api_data", "api_ship"]
35 case .getMemberShipDeck: return ["api_data", "api_ship_data"]
37 case .kaisouPowerUp: return ["api_data", "api_ship"]
39 case .kaisouSlotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
41 case .getMemberShip: return ["api_data"]
45 extension MappingConfiguration {
47 func change(dataKeys: [String]) -> MappingConfiguration {
49 return MappingConfiguration(entity: self.entity,
51 primaryKeys: self.primaryKeys,
52 editorStore: self.editorStore,
53 ignoreKeys: self.ignoreKeys)
57 final class ShipMapper: JSONMapper {
59 typealias ObjectType = Ship
60 let apiResponse: APIResponse
61 let configuration: MappingConfiguration<Ship>
63 required init(_ apiResponse: APIResponse) {
65 self.apiResponse = apiResponse
66 self.configuration = MappingConfiguration(entity: Ship.entity,
67 dataKeys: dataKeys(apiResponse),
68 editorStore: ServerDataStore.oneTimeEditor(),
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"])
79 // kaisouSlotDepriveでは同時に2種類のデータが入る
80 if let api = ShipAPI(rawValue: apiResponse.api),
81 api == .kaisouSlotDeprive {
83 let conf = self.configuration.change(dataKeys: ["api_data", "api_ship_data", "api_unset_ship"])
84 ShipMapper(apiResponse, configuration: conf).commit()
88 private init(_ apiResponse: APIResponse, configuration: MappingConfiguration<Ship>) {
90 self.apiResponse = apiResponse
91 self.configuration = configuration
94 private var registerIds: [Int] = []
95 private lazy var masterShips: [MasterShip] = {
97 return ServerDataStore.default.sortedMasterShipsById()
99 private lazy var slotItems: [SlotItem] = {
101 return ServerDataStore.default.sortedSlotItemsById()
103 private var isDeleteNotExist: Bool {
105 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
109 case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
110 .kaisouPowerUp, .kaisouSlotDeprive:
118 private var store: ServerDataStore? {
120 return configuration.editorStore as? ServerDataStore
123 func beginRegister(_ ship: Ship) {
125 ship.sally_area = nil
128 func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool {
130 // 取得後破棄した装備のデータを削除するため保有IDを保存
133 guard let id = value.int
134 else { return false }
136 registerIds.append(id)
141 if key == "api_ship_id" {
143 guard let masterId = value.int
144 else { return false }
146 setMaster(masterId, to: ship)
151 if key == "api_exp" {
153 guard let exp = value[0].int
154 else { return false }
161 if key == "api_slot" {
163 setSlot(value, to: ship)
168 if key == "api_slot_ex" {
170 guard let ex = value.int
171 else { return false }
173 setExtraSlot(ex, to: ship)
181 func finishOperating() {
183 if !isDeleteNotExist { return }
185 store?.ships(exclude: registerIds).forEach { store?.delete($0) }
188 private func setMaster(_ masterId: Int, to ship: Ship) {
190 if ship.ship_id == masterId { return }
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") }
196 ship.master_ship = masterShip
197 ship.ship_id = masterId
200 private func setSlot(_ slotItems: JSON, to ship: Ship) {
202 guard let converSlotItems = slotItems.arrayObject as? [Int],
206 let newItems: [SlotItem] =
207 converSlotItems.flatMap { item in
209 if item == 0 || item == -1 { return nil }
211 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
212 let slotItem = store.object(with: found.objectID) as? SlotItem
215 let maxV = converSlotItems.last
216 if maxV != nil, maxV! < item {
219 print("item is maybe unregistered, so it is new ship's equipment.")
223 print("Can not convert to current moc object slotItem")
230 ship.equippedItem = NSOrderedSet(array: newItems)
233 private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
235 guard exSlotItem != -1,
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") }