OSDN Git Service

return文の前に改行を入れるようにした
[kcd/KCD.git] / KCD / ChangeHenseiCommand.swift
1 //
2 //  ChangeHenseiCommand.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/01/09.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 enum ChangeHenseiType: Int {
12     
13     case append
14     
15     case replace
16     
17     case remove
18     
19     case removeAllWithoutFlagship
20 }
21
22 extension Notification.Name {
23     
24     static let HenseiDidChange = Notification.Name("com.masakih.KCD.Notification.HenseiDidChange")
25 }
26
27 final class HenseiDidChangeUserInfo: NSObject {
28     
29     let type: ChangeHenseiType
30     
31     let fleetNumber: Int
32     let position: Int
33     let shipID: Int
34     
35     let replaceFleetNumber: Int?
36     let replacePosition: Int?
37     let replaceShipID: Int?
38     
39     required init(type: ChangeHenseiType,
40                   fleetNumber: Int,
41                   position: Int,
42                   shipID: Int,
43                   replaceFleetNumber: Int? = nil,
44                   replacePosition: Int? = nil,
45                   replaceShipID: Int? = nil) {
46         
47         self.type = type
48         self.fleetNumber = fleetNumber
49         self.position = position
50         self.shipID = shipID
51         self.replaceFleetNumber = replaceFleetNumber
52         self.replacePosition = replacePosition
53         self.replaceShipID = replaceShipID
54         
55         super.init()
56     }
57 }
58
59 final class ChangeHenseiCommand: JSONCommand {
60     
61     static let userInfoKey = "HenseiDidChangeUserInfoKey"
62     
63     override class func canExecuteAPI(_ api: API) -> Bool {
64         
65         return api.endpoint == .change
66     }
67     
68     // api_ship_id の値
69     // ship_id > 0 : 艦娘のID append or replace
70     // ship_id == -1 : remove.
71     // ship_id == -2 : remove all without flag ship.
72     override func execute() {
73         
74         guard let deckNumber = parameter["api_id"].int,
75             let shipId = parameter["api_ship_id"].int,
76             let shipIndex = parameter["api_ship_idx"].int else {
77                 
78                 Logger.shared.log("parameter is wrong")
79                 
80                 return
81         }
82         
83         if shipId == -1 {
84             
85             guard let shipId = removeShip(deckNumber: deckNumber, index: shipIndex) else {
86                 
87                 return
88             }
89             notify(type: .remove, fleetNumber: deckNumber, position: shipIndex, shipID: shipId)
90             
91             return
92         }
93         
94         if shipId == -2 {
95             
96             excludeShipsWithoutFlagShip(deckNumber: deckNumber)
97             notify(type: .removeAllWithoutFlagship)
98             
99             return
100         }
101         
102         guard case 0..<Deck.maxShipCount = shipIndex else {
103             
104             return
105         }
106         
107         let store = ServerDataStore.oneTimeEditor()
108         guard let deck = store.sync(execute: { store.deck(by: deckNumber) }) else {
109             
110             return
111         }
112         
113         // すでに編成されているか? どこに?
114         let (shipDeckNumber, shipDeckIndex) = position(of: shipId)
115         
116         // 配置しようとする位置に今配置されている艦娘
117         let replaceShipId = store.sync { deck[shipIndex]?.id }
118         
119         // 艦隊に配備
120         store.sync { deck.setShip(id: shipId, for: shipIndex) }
121         
122         // 入れ替え
123         if shipDeckNumber != nil {
124             
125             let shipDeck = store.sync { store.deck(by: shipDeckNumber!) }
126             store.sync { shipDeck?.setShip(id: replaceShipId ?? -1, for: shipDeckIndex) }
127             shipDeck.map { packFleet(store: store, deck: $0) }
128         }
129         
130         packFleet(store: store, deck: deck)
131         
132         // Notify
133         if shipDeckNumber != nil {
134             
135             notify(type: .replace,
136                    fleetNumber: deckNumber,
137                    position: shipIndex,
138                    shipID: shipId,
139                    replaceFleetNumber: shipDeckNumber!,
140                    replacePosition: shipDeckIndex,
141                    replaceShipID: replaceShipId)
142             
143         } else {
144             
145             notify(type: .append, fleetNumber: deckNumber, position: shipIndex, shipID: shipId)
146         }
147     }
148     
149     private func position(of shipId: Int) -> (deckNumber: Int?, shipId: Int) {
150         
151         let store = ServerDataStore.default
152         
153         return store.sync {
154             
155             store
156                 .decksSortedById()
157                 .lazy
158                 .enumerated()
159                 .map { (idx, deck) -> (Int, [Ship]) in (idx + 1, deck[0..<Deck.maxShipCount]) }
160                 .filter { $0.1.contains { $0.id == shipId } }
161                 .map { (deck, ships) in (deck, ships.index(where: { $0.id == shipId })!) }
162                 .first ?? (nil, -1)
163         }
164     }
165     
166     private func removeShip(deckNumber: Int, index: Int) -> Int? {
167         
168         let store = ServerDataStore.oneTimeEditor()
169         
170         guard let deck = store.sync(execute: { store.deck(by: deckNumber) }) else {
171             
172             Logger.shared.log("Deck not found")
173             
174             return nil
175         }
176         
177         let shipId = store.sync { deck[index]?.id ?? -1 }
178         store.sync { deck.setShip(id: -1, for: index) }
179         
180         packFleet(store: store, deck: deck)
181         
182         return shipId
183     }
184     
185     private func excludeShipsWithoutFlagShip(deckNumber: Int) {
186         
187         let store = ServerDataStore.oneTimeEditor()
188         store.sync {
189             guard let deck = store.deck(by: deckNumber) else {
190                 
191                 Logger.shared.log("Deck not found")
192                 
193                 return
194             }
195             
196             (1..<Deck.maxShipCount).forEach { deck.setShip(id: -1, for: $0) }
197         }
198     }
199     
200     private func packFleet(store: ServerDataStore, deck: Deck) {
201         
202         func set(_ ships: [Ship], at index: Int, in deck: Deck) {
203             
204             guard index < Deck.maxShipCount else {
205                 
206                 return
207             }
208             
209             deck.setShip(id: ships.first?.id ?? -1, for: index)
210             
211             let newShips = ships.isEmpty ? [] : Array(ships[1...])
212             
213             set(newShips, at: index + 1, in: deck)
214         }
215         
216         store.sync { set(deck[0..<Deck.maxShipCount], at: 0, in: deck) }
217     }
218     
219     private func notify(type: ChangeHenseiType,
220                         fleetNumber: Int = 0,
221                         position: Int = 0,
222                         shipID: Int = 0,
223                         replaceFleetNumber: Int? = nil,
224                         replacePosition: Int? = nil,
225                         replaceShipID: Int? = nil) {
226         
227         let userInfo = HenseiDidChangeUserInfo(type: type,
228                                                fleetNumber: fleetNumber,
229                                                position: position,
230                                                shipID: shipID,
231                                                replaceFleetNumber: replaceFleetNumber,
232                                                replacePosition: replacePosition,
233                                                replaceShipID: replaceShipID)
234         NotificationCenter.default
235             .post(name: .HenseiDidChange,
236                   object: self,
237                   userInfo: [ChangeHenseiCommand.userInfoKey: userInfo])
238     }
239 }