5 // Created by Hori,Masaki on 2017/02/23.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
12 fileprivate enum ShipAPI: String {
13 case getMemberShip = "/kcsapi/api_get_member/ship"
14 case port = "/kcsapi/api_port/port"
15 case getMemberShip3 = "/kcsapi/api_get_member/ship3"
16 case kousyouGetShip = "/kcsapi/api_req_kousyou/getship"
17 case getMemberShipDeck = "/kcsapi/api_get_member/ship_deck"
18 case kaisouPowerUp = "/kcsapi/api_req_kaisou/powerup"
19 case kaisouSlotDeprive = "/kcsapi/api_req_kaisou/slot_deprive"
22 fileprivate func dataKeys(_ apiResponse: APIResponse) -> [String] {
23 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
24 else { return ["api_data"] }
26 case .port: return ["api_data", "api_ship"]
27 case .getMemberShip3: return ["api_data", "api_ship_data"]
28 case .kousyouGetShip: return ["api_data", "api_ship"]
29 case .getMemberShipDeck: return ["api_data", "api_ship_data"]
30 case .kaisouPowerUp: return ["api_data", "api_ship"]
31 case .kaisouSlotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
32 case .getMemberShip: return ["api_data"]
36 extension MappingConfiguration {
37 func change(dataKeys: [String]) -> MappingConfiguration {
38 return MappingConfiguration(entity: self.entity,
40 primaryKeys: self.primaryKeys,
41 editorStore: self.editorStore,
42 ignoreKeys: self.ignoreKeys)
46 class ShipMapper: JSONMapper {
47 typealias ObjectType = Ship
48 let apiResponse: APIResponse
49 let configuration: MappingConfiguration<Ship>
51 required init(_ apiResponse: APIResponse) {
52 self.apiResponse = apiResponse
53 self.configuration = MappingConfiguration(entity: Ship.entity,
54 dataKeys: dataKeys(apiResponse),
55 editorStore: ServerDataStore.oneTimeEditor(),
57 ["api_gomes", "api_gomes2", "api_broken", "api_powup",
58 "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
59 "api_slotnum", "api_stype", "api_name", "api_yomi",
60 "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
61 "api_taik", "api_houg", "api_houm", "api_tyku",
62 "api_ndock_item", "api_star",
63 "api_ndock_time_str", "api_member_id",
64 "api_fuel_max", "api_bull_max"])
66 // kaisouSlotDepriveでは同時に2種類のデータが入る
67 if let api = ShipAPI(rawValue: apiResponse.api),
68 api == .kaisouSlotDeprive {
69 let conf = self.configuration.change(dataKeys: ["api_data", "api_ship_data", "api_unset_ship"])
70 ShipMapper(apiResponse, configuration: conf).commit()
73 private init(_ apiResponse: APIResponse, configuration: MappingConfiguration<Ship>) {
74 self.apiResponse = apiResponse
75 self.configuration = configuration
78 private var registerIds: [Int] = []
79 private lazy var masterShips: [MasterShip] = {
80 return ServerDataStore.default.sortedMasterShipsById()
82 private lazy var slotItems: [SlotItem] = {
83 return ServerDataStore.default.sortedSlotItemsById()
85 private var isDeleteNotExist: Bool {
86 guard let shipApi = ShipAPI(rawValue: apiResponse.api)
89 case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
90 .kaisouPowerUp, .kaisouSlotDeprive:
96 private var store: ServerDataStore? {
97 return configuration.editorStore as? ServerDataStore
100 func beginRegister(_ ship: Ship) {
101 ship.sally_area = nil
103 func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool {
104 // 取得後破棄した装備のデータを削除するため保有IDを保存
106 guard let id = value.int else { return false }
107 registerIds.append(id)
111 if key == "api_ship_id" {
112 guard let masterId = value.int else { return false }
113 setMaster(masterId, to: ship)
116 if key == "api_exp" {
117 guard let exp = value[0].int else { return false }
121 if key == "api_slot" {
122 setSlot(value, to: ship)
125 if key == "api_slot_ex" {
126 guard let ex = value.int else { return false }
127 setExtraSlot(ex, to: ship)
133 func finishOperating() {
134 if !isDeleteNotExist { return }
135 store?.ships(exclude: registerIds).forEach { store?.delete($0) }
138 private func setMaster(_ masterId: Int, to ship: Ship) {
139 if ship.ship_id == masterId { return }
140 guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
141 let masterShip = store?.object(with: mShip.objectID) as? MasterShip
142 else { return print("Can not convert to current moc object masterShip") }
143 ship.master_ship = masterShip
144 ship.ship_id = masterId
147 private func setSlot(_ slotItems: JSON, to ship: Ship) {
148 guard let converSlotItems = slotItems.arrayObject as? [Int],
151 let newItems: [SlotItem] =
152 converSlotItems.flatMap { item in
153 if item == 0 || item == -1 { return nil }
154 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
155 let slotItem = store.object(with: found.objectID) as? SlotItem
157 let maxV = converSlotItems.last
158 if maxV != nil, maxV! < item {
160 print("item is maybe unregistered, so it is new ship's equipment.")
164 print("Can not convert to current moc object slotItem")
169 ship.equippedItem = NSOrderedSet(array: newItems)
171 private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
172 guard exSlotItem != -1,
175 guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
176 let ex = store?.object(with: found.objectID) as? SlotItem
177 else { return print("Can not convert to current moc object") }