OSDN Git Service

CoreDataのエンティティ名を文字列でアクセスしないようにした
[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
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"
19 }
20
21 fileprivate func dataKey(_ apiResponse: APIResponse) -> String {
22     guard let shipApi = ShipAPI(rawValue: apiResponse.api)
23         else { return "api_data" }
24     switch shipApi {
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"
32     }
33 }
34
35 extension MappingConfiguration {
36     func change(dataKey: String) -> MappingConfiguration {
37         return MappingConfiguration(entity: self.entity,
38                                     dataKey: dataKey,
39                                     primaryKey: self.primaryKey,
40                                     compositPrimaryKeys: self.compositPrimaryKeys,
41                                     editorStore: self.editorStore,
42                                     ignoreKeys: self.ignoreKeys)
43     }
44 }
45
46 class ShipMapper: JSONMapper {
47     let apiResponse: APIResponse
48     let configuration: MappingConfiguration
49     
50     required init(_ apiResponse: APIResponse) {
51         self.apiResponse = apiResponse
52         self.configuration = MappingConfiguration(entity: .ship,
53                                                   dataKey: dataKey(apiResponse),
54                                                   editorStore: ServerDataStore.oneTimeEditor(),
55                                                   ignoreKeys:
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"])
64         
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()
70         }
71     }
72     private init(_ apiResponse: APIResponse, configuration: MappingConfiguration) {
73         self.apiResponse = apiResponse
74         self.configuration = configuration
75     }
76     
77     private var registerIds: [Int] = []
78     private lazy var masterShips: [KCMasterShipObject] = {
79         return ServerDataStore.default.sortedMasterShipsById()
80     }()
81     private lazy var slotItems: [KCSlotItemObject] = {
82         return ServerDataStore.default.sortedSlotItemsById()
83     }()
84     private var isDeleteNotExist: Bool {
85         guard let shipApi = ShipAPI(rawValue: apiResponse.api)
86             else { return true }
87         switch shipApi {
88         case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
89              .kaisouPowerUp, .kaisouSlotDeprive:
90             return false
91         default:
92             return true
93         }
94     }
95     private var store: ServerDataStore? {
96         return configuration.editorStore as? ServerDataStore
97     }
98     
99     func beginRegister(_ object: NSManagedObject) {
100         guard let ship = object as? KCShipObject
101             else { return }
102         ship.sally_area = nil
103     }
104     func handleExtraValue(_ value: Any, forKey key: String, to object: NSManagedObject) -> Bool {
105         guard let ship = object as? KCShipObject
106             else { return false }
107         
108         // 取得後破棄した装備のデータを削除するため保有IDを保存
109         if key == "api_id" {
110             guard let id = value as? Int
111                 else { return false }
112             registerIds.append(id)
113             return false
114         }
115         
116         if key == "api_ship_id" {
117             guard let masterId = value as? Int
118                 else { return false }
119             setMaster(masterId, to: ship)
120             return true
121         }
122         if key == "api_exp" {
123             guard let v = value as? [Any],
124                 let vv = v.first as? Int
125                 else { return false }
126             ship.exp = vv
127             return true
128         }
129         if key == "api_slot" {
130             guard let slotItems = value as? [Any]
131                 else { return false }
132             setSlot(slotItems, to: ship)
133             return false
134         }
135         if key == "api_slot_ex" {
136             guard let ex = value as? Int
137                 else { return false }
138             setExtraSlot(ex, to: ship)
139             return false
140         }
141         
142         return false
143     }
144     func finishOperating() {
145         if !isDeleteNotExist { return }
146         store?.ships(exclude: registerIds).forEach { store?.delete($0) }
147     }
148     
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
156     }
157     
158     private func setSlot(_ slotItems: [Any], to ship: KCShipObject) {
159         guard let converSlotItems = slotItems as? [Int],
160             let store = store
161             else { return }
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
167                     else {
168                         let maxV = converSlotItems.last
169                         if maxV != nil && maxV! < item {
170                             #if DEBUG
171                                 print("item is maybe unregistered, so it is new ship's equipment.")
172                             #endif
173                             return nil
174                         }
175                         print("Can not convert to current moc object slotItem")
176                         return nil
177                 }
178                 return slotItem
179         }
180         ship.equippedItem = NSOrderedSet(array: newItems)
181     }
182     private func setExtraSlot(_ exSlotItem: Int, to ship: KCShipObject) {
183         guard exSlotItem != -1,
184             exSlotItem != 0
185             else { return }
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") }
189         ship.extraItem = ex
190     }
191 }