OSDN Git Service

MappingConfigurationを簡略化
[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 import SwiftyJSON
11
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"
20 }
21
22 fileprivate func dataKeys(_ apiResponse: APIResponse) -> [String] {
23     guard let shipApi = ShipAPI(rawValue: apiResponse.api)
24         else { return ["api_data"] }
25     switch shipApi {
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"]
33     }
34 }
35
36 extension MappingConfiguration {
37     func change(dataKeys: [String]) -> MappingConfiguration {
38         return MappingConfiguration(entity: self.entity,
39                                     dataKeys: dataKeys,
40                                     primaryKeys: self.primaryKeys,
41                                     editorStore: self.editorStore,
42                                     ignoreKeys: self.ignoreKeys)
43     }
44 }
45
46 class ShipMapper: JSONMapper {
47     typealias ObjectType = Ship
48     let apiResponse: APIResponse
49     let configuration: MappingConfiguration<Ship>
50     
51     required init(_ apiResponse: APIResponse) {
52         self.apiResponse = apiResponse
53         self.configuration = MappingConfiguration(entity: Ship.entity,
54                                                   dataKeys: dataKeys(apiResponse),
55                                                   editorStore: ServerDataStore.oneTimeEditor(),
56                                                   ignoreKeys:
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"])
65         
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()
71         }
72     }
73     private init(_ apiResponse: APIResponse, configuration: MappingConfiguration<Ship>) {
74         self.apiResponse = apiResponse
75         self.configuration = configuration
76     }
77     
78     private var registerIds: [Int] = []
79     private lazy var masterShips: [MasterShip] = {
80         return ServerDataStore.default.sortedMasterShipsById()
81     }()
82     private lazy var slotItems: [SlotItem] = {
83         return ServerDataStore.default.sortedSlotItemsById()
84     }()
85     private var isDeleteNotExist: Bool {
86         guard let shipApi = ShipAPI(rawValue: apiResponse.api)
87             else { return true }
88         switch shipApi {
89         case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck,
90              .kaisouPowerUp, .kaisouSlotDeprive:
91             return false
92         default:
93             return true
94         }
95     }
96     private var store: ServerDataStore? {
97         return configuration.editorStore as? ServerDataStore
98     }
99     
100     func beginRegister(_ ship: Ship) {
101         ship.sally_area = nil
102     }
103     func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool {
104         // 取得後破棄した装備のデータを削除するため保有IDを保存
105         if key == "api_id" {
106             guard let id = value.int
107                 else { return false }
108             registerIds.append(id)
109             return false
110         }
111         
112         if key == "api_ship_id" {
113             guard let masterId = value.int
114                 else { return false }
115             setMaster(masterId, to: ship)
116             return true
117         }
118         if key == "api_exp" {
119             guard let exp = value[0].int
120                 else { return false }
121             ship.exp = exp
122             return true
123         }
124         if key == "api_slot" {
125             setSlot(value, to: ship)
126             return false
127         }
128         if key == "api_slot_ex" {
129             guard let ex = value.int
130                 else { return false }
131             setExtraSlot(ex, to: ship)
132             return false
133         }
134         
135         return false
136     }
137     func finishOperating() {
138         if !isDeleteNotExist { return }
139         store?.ships(exclude: registerIds).forEach { store?.delete($0) }
140     }
141     
142     private func setMaster(_ masterId: Int, to ship: Ship) {
143         if ship.ship_id == masterId { return }
144         guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }),
145             let masterShip = store?.object(with: mShip.objectID) as? MasterShip
146             else { return print("Can not convert to current moc object masterShip") }
147         ship.master_ship = masterShip
148         ship.ship_id = masterId
149     }
150     
151     private func setSlot(_ slotItems: JSON, to ship: Ship) {
152         guard let converSlotItems = slotItems.arrayObject as? [Int],
153             let store = store
154             else { return }
155         let newItems: [SlotItem] =
156             converSlotItems.flatMap { (item: Int) in
157                 if item == 0 || item == -1 { return nil }
158                 guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }),
159                     let slotItem = store.object(with: found.objectID) as? SlotItem
160                     else {
161                         let maxV = converSlotItems.last
162                         if maxV != nil && maxV! < item {
163                             #if DEBUG
164                                 print("item is maybe unregistered, so it is new ship's equipment.")
165                             #endif
166                             return nil
167                         }
168                         print("Can not convert to current moc object slotItem")
169                         return nil
170                 }
171                 return slotItem
172         }
173         ship.equippedItem = NSOrderedSet(array: newItems)
174     }
175     private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) {
176         guard exSlotItem != -1,
177             exSlotItem != 0
178             else { return }
179         guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }),
180             let ex = store?.object(with: found.objectID) as? SlotItem
181             else { return print("Can not convert to current moc object") }
182         ship.extraItem = ex
183     }
184 }