5 // Created by Hori,Masaki on 2017/02/23.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
11 fileprivate enum ShipAPI: String {
12 case getMemberShip = "/kcsapi/api_get_member/ship"
13 case port = "/kcsapi/api_port/port"
14 case getMemberShip3 = "/kcsapi/api_get_member/ship3"
15 case kousyouGetShip = "/kcsapi/api_req_kousyou/getship"
16 case getMemberShipDeck = "/kcsapi/api_get_member/ship_deck"
17 case kaisouPowerUp = "/kcsapi/api_req_kaisou/powerup"
18 case kaisouSlotDeprive = "/kcsapi/api_req_kaisou/slot_deprive"
21 fileprivate func dataKey(_ apiResponse: APIResponse) -> String {
22 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
23 else { return "api_data" }
25 case .port: return "api_data.api_ship"
26 case .getMemberShip3: return "api_data.api_ship_data"
27 case .kousyouGetShip: return "api_data.api_ship"
28 case .getMemberShipDeck: return "api_data.api_ship_data"
29 case .kaisouPowerUp: return "api_data.api_ship"
30 case .kaisouSlotDeprive: return "api_data.api_ship_data.api_set_ship"
31 case .getMemberShip: return "api_data"
35 extension MappingConfiguration {
36 func change(dataKey: String) -> MappingConfiguration {
37 return MappingConfiguration(entity: self.entity,
39 primaryKey: self.primaryKey,
40 compositPrimaryKeys: self.compositPrimaryKeys,
41 editorStore: self.editorStore,
42 ignoreKeys: self.ignoreKeys)
46 class ShipMapper: JSONMapper {
47 let apiResponse: APIResponse
48 let configuration: MappingConfiguration
50 required init(_ apiResponse: APIResponse) {
51 self.apiResponse = apiResponse
52 self.configuration = MappingConfiguration(entity: .ship,
53 dataKey: dataKey(apiResponse),
54 editorStore: ServerDataStore.oneTimeEditor(),
56 ["api_gomes", "api_gomes2", "api_broken", "api_powup",
57 "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
58 "api_slotnum", "api_stype", "api_name", "api_yomi",
59 "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
60 "api_taik", "api_houg", "api_houm", "api_tyku",
61 "api_ndock_item", "api_star",
62 "api_ndock_time_str", "api_member_id",
63 "api_fuel_max", "api_bull_max"])
65 // kaisouSlotDepriveでは同時に2種類のデータが入る
66 if let api = ShipAPI(rawValue: apiResponse.api),
67 api == .kaisouSlotDeprive {
68 let conf = self.configuration.change(dataKey: "api_data.api_ship_data.api_unset_ship")
69 ShipMapper(apiResponse, configuration: conf).commit()
72 private init(_ apiResponse: APIResponse, configuration: MappingConfiguration) {
73 self.apiResponse = apiResponse
74 self.configuration = configuration
77 private var registerIds: [Int] = []
78 private lazy var masterShips: [KCMasterShipObject] = {
79 return ServerDataStore.default.sortedMasterShipsById()
81 private lazy var slotItems: [KCSlotItemObject] = {
82 return ServerDataStore.default.sortedSlotItemsById()
84 private var isDeleteNotExist: Bool {
85 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
88 case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
89 .kaisouPowerUp, .kaisouSlotDeprive:
95 private var store: ServerDataStore? {
96 return configuration.editorStore as? ServerDataStore
99 func beginRegister(_ object: NSManagedObject) {
100 guard let ship = object as? KCShipObject
102 ship.sally_area = nil
104 func handleExtraValue(_ value: Any, forKey key: String, to object: NSManagedObject) -> Bool {
105 guard let ship = object as? KCShipObject
106 else { return false }
108 // 取得後破棄した装備のデータを削除するため保有IDを保存
110 guard let id = value as? Int
111 else { return false }
112 registerIds.append(id)
116 if key == "api_ship_id" {
117 guard let masterId = value as? Int
118 else { return false }
119 setMaster(masterId, to: ship)
122 if key == "api_exp" {
123 guard let v = value as? [Any],
124 let vv = v.first as? Int
125 else { return false }
129 if key == "api_slot" {
130 guard let slotItems = value as? [Any]
131 else { return false }
132 setSlot(slotItems, to: ship)
135 if key == "api_slot_ex" {
136 guard let ex = value as? Int
137 else { return false }
138 setExtraSlot(ex, to: ship)
144 func finishOperating() {
145 if !isDeleteNotExist { return }
146 store?.ships(exclude: registerIds).forEach { store?.delete($0) }
149 private func setMaster(_ masterId: Int, to ship: KCShipObject) {
150 if ship.ship_id == masterId { return }
151 guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
152 let masterShip = store?.object(with: mShip.objectID) as? KCMasterShipObject
153 else { return print("Can not convert to current moc object masterShip") }
154 ship.master_ship = masterShip
155 ship.ship_id = masterId
158 private func setSlot(_ slotItems: [Any], to ship: KCShipObject) {
159 guard let converSlotItems = slotItems as? [Int],
162 let newItems: [KCSlotItemObject] =
163 converSlotItems.flatMap { (item: Int) in
164 if item == 0 || item == -1 { return nil }
165 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
166 let slotItem = store.object(with: found.objectID) as? KCSlotItemObject
168 let maxV = converSlotItems.last
169 if maxV != nil && maxV! < item {
171 print("item is maybe unregistered, so it is new ship's equipment.")
175 print("Can not convert to current moc object slotItem")
180 ship.equippedItem = NSOrderedSet(array: newItems)
182 private func setExtraSlot(_ exSlotItem: Int, to ship: KCShipObject) {
183 guard exSlotItem != -1,
186 guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
187 let ex = store?.object(with: found.objectID) as? KCSlotItemObject
188 else { return print("Can not convert to current moc object") }