OSDN Git Service

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