OSDN Git Service

13d0da7762f586e6ea37f03c1c0faea57327c063
[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: String) -> Bool {
61         
62         if api == "/kcsapi/api_req_hensei/change" { return true }
63         
64         return false
65     }
66     
67     // api_ship_id の値
68     // ship_id > 0 : 艦娘のID append or replace
69     // ship_id == -1 : remove.
70     // ship_id == -2 : remove all without flag ship.
71     override func execute() {
72         
73         guard let deckNumber = parameter["api_id"].int,
74             let shipId = parameter["api_ship_id"].int,
75             let shipIndex = parameter["api_ship_idx"].int else {
76                 
77                 return Logger.shared.log("parameter is wrong")
78         }
79         
80         if shipId == -1 {
81             
82             guard let ship = removeShip(deckNumber: deckNumber, index: shipIndex) else { return }
83             notify(type: .remove, fleetNumber: deckNumber, position: shipIndex, shipID: ship.id)
84             return
85         }
86         
87         if shipId == -2 {
88             
89             excludeShipsWithoutFlagShip(deckNumber: deckNumber)
90             notify(type: .removeAllWithoutFlagship)
91             return
92         }
93         
94         guard case 0..<Deck.maxShipCount = shipIndex else { return }
95         
96         let store = ServerDataStore.oneTimeEditor()
97         guard let deck = store.deck(by: deckNumber) else { return }
98         
99         // すでに編成されているか? どこに?
100         let (shipDeckNumber, shipDeckIndex) = position(of: shipId)
101         
102         // 配置しようとする位置に今配置されている艦娘
103         let replaceShipId = deck[shipIndex]?.id
104         
105         // 艦隊に配備
106         deck.setShip(id: shipId, for: shipIndex)
107         
108         // 入れ替え
109         if shipDeckNumber != nil {
110             
111             let shipDeck = store.deck(by: shipDeckNumber!)
112             shipDeck?.setShip(id: replaceShipId ?? -1, for: shipDeckIndex)
113             shipDeck.map { packFleet(store: store, deck: $0) }
114         }
115         
116         packFleet(store: store, deck: deck)
117         
118         // Notify
119         if shipDeckNumber != nil {
120             
121             notify(type: .replace,
122                    fleetNumber: deckNumber,
123                    position: shipIndex,
124                    shipID: shipId,
125                    replaceFleetNumber: shipDeckNumber!,
126                    replacePosition: shipDeckIndex,
127                    replaceShipID: replaceShipId)
128             
129         } else {
130             
131             notify(type: .append, fleetNumber: deckNumber, position: shipIndex, shipID: shipId)
132         }
133     }
134     
135     private func position(of shipId: Int) -> (deckNumber: Int?, shipId: Int) {
136         
137         return ServerDataStore.default
138             .decksSortedById()
139             .lazy
140             .enumerated()
141             .map { (idx, deck) -> (Int, [Ship]) in (idx + 1, deck[0..<Deck.maxShipCount]) }
142             .filter { $0.1.contains { $0.id == shipId } }
143             .map { (deck, ships) in (deck, ships.index(where: { $0.id == shipId })!) }
144             .first ?? (nil, -1)
145     }
146     
147     private func removeShip(deckNumber: Int, index: Int) -> Ship? {
148         
149         let store = ServerDataStore.oneTimeEditor()
150         
151         guard let deck = store.deck(by: deckNumber) else { return Logger.shared.log("Deck not found", value: nil) }
152         
153         let shipId = deck[index]?.id ?? -1
154         deck.setShip(id: -1, for: index)
155         
156         packFleet(store: store, deck: deck)
157         
158         return ServerDataStore.default.ship(by: shipId)
159     }
160     
161     private func excludeShipsWithoutFlagShip(deckNumber: Int) {
162         
163         let store = ServerDataStore.oneTimeEditor()
164         
165         guard let deck = store.deck(by: deckNumber) else {
166             
167             return Logger.shared.log("Deck not found")
168         }
169         
170         (1..<Deck.maxShipCount).forEach { deck.setShip(id: -1, for: $0) }
171     }
172     
173     private func packFleet(store: ServerDataStore, deck: Deck) {
174         
175         func set(_ ships: [Ship], at index: Int, in deck: Deck) {
176             
177             guard index < Deck.maxShipCount else { return }
178             
179             deck.setShip(id: ships.first?.id ?? -1, for: index)
180             
181             let newShips = ships.isEmpty ? [] : Array(ships[1...])
182             
183             set(newShips, at: index + 1, in: deck)
184         }
185         
186         set(deck[0..<Deck.maxShipCount], at: 0, in: deck)
187     }
188     
189     private func notify(type: ChangeHenseiType,
190                         fleetNumber: Int = 0,
191                         position: Int = 0,
192                         shipID: Int = 0,
193                         replaceFleetNumber: Int? = nil,
194                         replacePosition: Int? = nil,
195                         replaceShipID: Int? = nil) {
196         
197         let userInfo = HenseiDidChangeUserInfo(type: type,
198                                                fleetNumber: fleetNumber,
199                                                position: position,
200                                                shipID: shipID,
201                                                replaceFleetNumber: replaceFleetNumber,
202                                                replacePosition: replacePosition,
203                                                replaceShipID: replaceShipID)
204         NotificationCenter.default
205             .post(name: .HenseiDidChange,
206                   object: self,
207                   userInfo: [ChangeHenseiCommand.userInfoKey: userInfo])
208     }
209 }