OSDN Git Service

containsを多用するArrayのうちSetに置換可能なものをSetに変更
[kcd/KCD.git] / KCD / ShipMapper.swift
index fdecaa0..64398df 100644 (file)
 import Cocoa
 import SwiftyJSON
 
-extension MappingConfiguration {
-    
-    func change(dataKeys: [String]) -> MappingConfiguration {
-        
-        return MappingConfiguration(entity: self.entity,
-                                    dataKeys: dataKeys,
-                                    primaryKeys: self.primaryKeys,
-                                    editorStore: self.editorStore,
-                                    ignoreKeys: self.ignoreKeys)
-    }
-}
-
 final class ShipMapper: JSONMapper {
     
-    typealias ObjectType = Ship
+    private static let ignoreKeys: Set<String> = ["api_gomes", "api_gomes2", "api_broken", "api_powup",
+                                                  "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
+                                                  "api_slotnum", "api_stype", "api_name", "api_yomi",
+                                                  "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
+                                                  "api_taik", "api_houg", "api_houm", "api_tyku",
+                                                  "api_ndock_item", "api_star",
+                                                  "api_ndock_time_str", "api_member_id",
+                                                  "api_fuel_max", "api_bull_max"]
+    
     let apiResponse: APIResponse
     let configuration: MappingConfiguration<Ship>
     
     required init(_ apiResponse: APIResponse) {
         
         self.apiResponse = apiResponse
-        self.configuration = MappingConfiguration(entity: Ship.entity,
+        self.configuration = MappingConfiguration(entity: Ship.self,
                                                   dataKeys: ShipMapper.dataKeys(apiResponse),
                                                   editorStore: ServerDataStore.oneTimeEditor(),
-                                                  ignoreKeys:
-            ["api_gomes", "api_gomes2", "api_broken", "api_powup",
-             "api_voicef", "api_afterlv", "api_aftershipid", "api_backs",
-             "api_slotnum", "api_stype", "api_name", "api_yomi",
-             "api_raig", "api_luck", "api_saku", "api_raim", "api_baku",
-             "api_taik", "api_houg", "api_houm", "api_tyku",
-             "api_ndock_item", "api_star",
-             "api_ndock_time_str", "api_member_id",
-             "api_fuel_max", "api_bull_max"])
-        
-        // kaisouSlotDepriveでは同時に2種類のデータが入る
-        if let api = ShipAPI(rawValue: apiResponse.api),
-            api == .kaisouSlotDeprive {
-            
-            let conf = self.configuration.change(dataKeys: ["api_data", "api_ship_data", "api_unset_ship"])
-            ShipMapper(apiResponse, configuration: conf).commit()
-        }
+                                                  ignoreKeys: ShipMapper.ignoreKeys)
     }
     
-    private init(_ apiResponse: APIResponse, configuration: MappingConfiguration<Ship>) {
+    // slotDepriveの時に2種類のデータが来るため
+    init(forSlotDepriveUnset apiResponse: APIResponse) {
         
         self.apiResponse = apiResponse
-        self.configuration = configuration
-    }
-    
-    
-    private enum ShipAPI: String {
-        
-        case getMemberShip = "/kcsapi/api_get_member/ship"
-        case port = "/kcsapi/api_port/port"
-        case getMemberShip3 = "/kcsapi/api_get_member/ship3"
-        case kousyouGetShip = "/kcsapi/api_req_kousyou/getship"
-        case getMemberShipDeck = "/kcsapi/api_get_member/ship_deck"
-        case kaisouPowerUp = "/kcsapi/api_req_kaisou/powerup"
-        case kaisouSlotDeprive = "/kcsapi/api_req_kaisou/slot_deprive"
+        self.configuration = MappingConfiguration(entity: Ship.self,
+                                                  dataKeys: ["api_data", "api_ship_data", "api_unset_ship"],
+                                                  editorStore: ServerDataStore.oneTimeEditor(),
+                                                  ignoreKeys: ShipMapper.ignoreKeys)
     }
     
     private class func dataKeys(_ apiResponse: APIResponse) -> [String] {
         
-        guard let shipApi = ShipAPI(rawValue: apiResponse.api)
-            else { return ["api_data"] }
-        
-        switch shipApi {
-        case .port: return ["api_data", "api_ship"]
+        switch apiResponse.api.endpoint {
             
-        case .getMemberShip3: return ["api_data", "api_ship_data"]
+        case .port, .getShip, .powerup: return ["api_data", "api_ship"]
             
-        case .kousyouGetShip: return ["api_data", "api_ship"]
+        case .ship3, .shipDeck: return ["api_data", "api_ship_data"]
             
-        case .getMemberShipDeck: return ["api_data", "api_ship_data"]
+        case .slotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
             
-        case .kaisouPowerUp: return ["api_data", "api_ship"]
+        case .ship, .ship2: return ["api_data"]
             
-        case .kaisouSlotDeprive: return ["api_data", "api_ship_data", "api_set_ship"]
+        default:
+            
+            Logger.shared.log("Missing API: \(apiResponse.api)")
             
-        case .getMemberShip: return ["api_data"]
+            return ["api_data"]
         }
     }
     
     private var registerIds: [Int] = []
     private lazy var masterShips: [MasterShip] = {
         
-        return ServerDataStore.default.sortedMasterShipsById()
+        guard let store = configuration.editorStore as? ServerDataStore else {
+            
+            return []
+        }
+        
+        return store.sortedMasterShipsById()
+        
     }()
     private lazy var slotItems: [SlotItem] = {
         
-        return ServerDataStore.default.sortedSlotItemsById()
-    }()
-    private var isDeleteNotExist: Bool {
+        guard let store = configuration.editorStore as? ServerDataStore else {
+            
+            return []
+        }
         
-        guard let shipApi = ShipAPI(rawValue: apiResponse.api)
-            else { return true }
+        return store.sortedSlotItemsById()
+    }()
+    
+    private var needsDeleteUnregisteredShip: Bool {
         
-        switch shipApi {
-        case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
-             .kaisouPowerUp, .kaisouSlotDeprive:
+        switch apiResponse.api.endpoint {
+            
+        case .ship3, .getShip, .shipDeck, .powerup, .slotDeprive:
+            
             return false
             
+        case .ship2:
+            // 特殊任務のクリア時にship2がapi_shipid付きでリクエストされ、その艦娘のデータしかない時があるため
+            
+            return !apiResponse.parameter["api_shipid"].valid
+            
         default:
+            
             return true
+            
         }
     }
     
@@ -131,8 +118,10 @@ final class ShipMapper: JSONMapper {
         // 取得後破棄した装備のデータを削除するため保有IDを保存
         if key == "api_id" {
             
-            guard let id = value.int
-                else { return false }
+            guard let id = value.int else {
+                
+                return false
+            }
             
             registerIds.append(id)
             
@@ -141,8 +130,15 @@ final class ShipMapper: JSONMapper {
         
         if key == "api_ship_id" {
             
-            guard let masterId = value.int
-                else { return false }
+            guard let masterId = value.int else {
+                
+                return false
+            }
+            
+            if ship.ship_id == masterId {
+                
+                return true
+            }
             
             setMaster(masterId, to: ship)
             
@@ -151,8 +147,15 @@ final class ShipMapper: JSONMapper {
         
         if key == "api_exp" {
             
-            guard let exp = value[0].int
-                else { return false }
+            guard let exp = value[0].int else {
+                
+                return false
+            }
+            
+            if ship.exp == exp {
+                
+                return true
+            }
             
             ship.exp = exp
             
@@ -168,12 +171,23 @@ final class ShipMapper: JSONMapper {
         
         if key == "api_slot_ex" {
             
-            guard let ex = value.int
-                else { return false }
+            guard let ex = value.int else {
+                
+                ship.extraItem = nil
+                
+                return false
+            }
+            
+            if ship.slot_ex == ex {
+                
+                return true
+            }
             
             setExtraSlot(ex, to: ship)
             
-            return false
+            ship.slot_ex = ex
+            
+            return true
         }
         
         return false
@@ -181,18 +195,23 @@ final class ShipMapper: JSONMapper {
     
     func finishOperating() {
         
-        if !isDeleteNotExist { return }
+        if !needsDeleteUnregisteredShip {
+            
+            return
+        }
         
         store?.ships(exclude: registerIds).forEach { store?.delete($0) }
     }
     
     private func setMaster(_ masterId: Int, to ship: Ship) {
         
-        if ship.ship_id == masterId { return }
-        
         guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
-            let masterShip = store?.object(with: mShip.objectID) as? MasterShip
-            else { return print("Can not convert to current moc object masterShip") }
+            let masterShip = store?.exchange(mShip) else {
+                
+                Logger.shared.log("Can not convert to current moc object masterShip")
+                
+                return
+        }
         
         ship.master_ship = masterShip
         ship.ship_id = masterId
@@ -200,28 +219,31 @@ final class ShipMapper: JSONMapper {
     
     private func setSlot(_ slotItems: JSON, to ship: Ship) {
         
-        guard let converSlotItems = slotItems.arrayObject as? [Int],
-            let store = store
-            else { return }
+        guard let convertedSlotItems = slotItems.arrayObject as? [Int] else {
+            
+            return
+        }
+        guard let store = store else {
+            
+            return
+        }
         
-        let newItems: [SlotItem] =
-            converSlotItems.flatMap { item in
-                
-                if item == 0 || item == -1 { return nil }
+        let newItems: [SlotItem] = convertedSlotItems
+            .filter { $0 != 0 && $0 != -1 }
+            .compactMap { item in
                 
                 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
-                    let slotItem = store.object(with: found.objectID) as? SlotItem
-                    else {
+                    let slotItem = store.exchange(found) else {
                         
-                        let maxV = converSlotItems.last
+                        let maxV = convertedSlotItems.last
                         if maxV != nil, maxV! < item {
                             
-                            #if DEBUG
-                                print("item is maybe unregistered, so it is new ship's equipment.")
-                            #endif
+                            Debug.print("item is maybe unregistered, so it is new ship's equipment.")
+                            
                             return nil
                         }
-                        print("Can not convert to current moc object slotItem")
+                        Logger.shared.log("Can not convert to current moc object slotItem")
+                        
                         return nil
                 }
                 
@@ -233,13 +255,19 @@ final class ShipMapper: JSONMapper {
     
     private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
         
-        guard exSlotItem != -1,
-            exSlotItem != 0
-            else { return }
-        
+        guard exSlotItem != -1, exSlotItem != 0 else {
+            
+            ship.extraItem = nil
+            
+            return
+        }
         guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
-            let ex = store?.object(with: found.objectID) as? SlotItem
-            else { return print("Can not convert to current moc object") }
+            let ex = store?.exchange(found) else {
+                
+                Logger.shared.log("Can not convert to current moc object")
+                
+                return
+        }
         
         ship.extraItem = ex
     }