1 // Copyright (C) 2017 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // Licensed under the Apache License, Version 2.0 (the "License");
\r
4 // you may not use this file except in compliance with the License.
\r
5 // You may obtain a copy of the License at
\r
7 // http://www.apache.org/licenses/LICENSE-2.0
\r
9 // Unless required by applicable law or agreed to in writing, software
\r
10 // distributed under the License is distributed on an "AS IS" BASIS,
\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 // See the License for the specific language governing permissions and
\r
13 // limitations under the License.
\r
16 using System.Collections.Generic;
\r
19 using KancolleSniffer.Util;
\r
21 namespace KancolleSniffer
\r
23 public class NotificationManager
\r
25 private readonly NotificationQueue _notificationQueue;
\r
35 private class Notification
\r
37 public string Key { get; set; }
\r
38 public int Fleet { get; set; }
\r
39 public string Subject { get; set; }
\r
40 public int Repeat { get; set; }
\r
41 public Mode Mode { get; set; }
\r
42 public DateTime Schedule { get; set; }
\r
45 public NotificationManager(Action<string, string, string> alarm, Func<DateTime> nowFunc = null)
\r
47 _notificationQueue = new NotificationQueue(alarm, nowFunc);
\r
50 public void Enqueue(string key, int fleet, string subject, int repeat = 0, bool preliminary = false)
\r
52 _notificationQueue.Enqueue(new Notification
\r
58 Mode = preliminary ? Mode.Preliminary : Mode.Normal
\r
62 public void Enqueue(string key, string subject, int repeat = 0)
\r
64 Enqueue(key, 0, subject, repeat);
\r
69 _notificationQueue.Flash();
\r
72 public void StopRepeat(string key, bool cont = false)
\r
74 _notificationQueue.StopRepeat(key, cont);
\r
77 public void StopRepeat(string key, int fleet)
\r
79 _notificationQueue.StopRepeat(key, fleet);
\r
82 public void StopRepeat(string key, string subject)
\r
84 _notificationQueue.StopRepeat(key, subject);
\r
87 public void StopAllRepeat()
\r
89 _notificationQueue.StopAllRepeat();
\r
92 public void SuspendRepeat(string exception = "")
\r
94 _notificationQueue.SuspendRepeat(exception);
\r
97 public void ResumeRepeat()
\r
99 _notificationQueue.ResumeRepeat();
\r
102 public string KeyToName(string key) => NotificationConfig.KeyToName(key);
\r
104 private class NotificationConfig
\r
106 public class Message
\r
108 public string Title { get; set; }
\r
109 public string Body { get; set; }
\r
110 public string Name { get; set; }
\r
113 private readonly Dictionary<string, Message> _config = new Dictionary<string, Message>();
\r
115 private readonly Dictionary<string, Message> _default = new Dictionary<string, Message>
\r
118 "遠征終了", new Message
\r
120 Title = "遠征が終わりました",
\r
125 "入渠終了", new Message
\r
127 Title = "入渠が終わりました",
\r
132 "建造完了", new Message
\r
134 Title = "建造が終わりました",
\r
139 "艦娘数超過", new Message
\r
141 Title = "艦娘が多すぎます",
\r
146 "装備数超過", new Message
\r
148 Title = "装備が多すぎます",
\r
153 "大破警告", new Message
\r
155 Title = "大破した艦娘がいます",
\r
160 "泊地修理20分経過", new Message
\r
162 Title = "泊地修理 %f艦隊",
\r
163 Body = "20分経過しました。"
\r
167 "泊地修理進行", new Message
\r
169 Title = "泊地修理 %f艦隊",
\r
174 "泊地修理完了", new Message
\r
176 Title = "泊地修理 %f艦隊",
\r
181 "疲労回復40", new Message
\r
183 Title = "疲労が回復しました",
\r
188 "疲労回復49", new Message
\r
190 Title = "疲労が回復しました",
\r
195 "任務達成", new Message
\r
197 Title = "任務を達成しました",
\r
203 public static string KeyToName(string key) => key.StartsWith("疲労回復") ? key.Substring(0, 4) : key;
\r
205 private void LoadConfig()
\r
207 const string fileName = "notification.json";
\r
211 dynamic config = JsonParser.Parse(File.ReadAllText(fileName));
\r
212 foreach (var entry in config)
\r
214 if (!_default.ContainsKey(entry.key))
\r
216 _config[entry.key] = new Message
\r
218 Title = entry.title,
\r
223 catch (FileNotFoundException)
\r
226 catch (Exception ex)
\r
228 throw new Exception($"{fileName}に誤りがあります。: ${ex.Message}", ex);
\r
232 public Message GenerateMessage(Notification notification)
\r
235 var format = _config.TryGetValue(notification.Key, out Message value)
\r
237 : _default[notification.Key];
\r
238 var prefix = new[] {"", "[リピート] ", "[継続] ", "[予告] "}[(int)notification.Mode];
\r
241 Title = prefix + ProcessFormatString(format.Title, notification.Fleet, notification.Subject),
\r
242 Body = ProcessFormatString(format.Body, notification.Fleet, notification.Subject),
\r
243 Name = KeyToName(notification.Key)
\r
247 private string ProcessFormatString(string format, int fleet, string subject)
\r
249 var fn = new[] {"第一", "第二", "第三", "第四"};
\r
251 var percent = false;
\r
252 foreach (var ch in format)
\r
272 result += fn[fleet];
\r
278 result += '%'.ToString() + ch;
\r
291 private class NotificationQueue
\r
293 private readonly Action<string, string, string> _alarm;
\r
294 private readonly List<Notification> _queue = new List<Notification>();
\r
295 private readonly Func<DateTime> _nowFunc = () => DateTime.Now;
\r
296 private readonly NotificationConfig _notificationConfig = new NotificationConfig();
\r
297 private DateTime _lastAlarm;
\r
298 private bool _suspend;
\r
299 private string _suspendException;
\r
301 public NotificationQueue(Action<string, string, string> alarm, Func<DateTime> nowFunc = null)
\r
304 if (nowFunc != null)
\r
305 _nowFunc = nowFunc;
\r
308 public void Enqueue(Notification notification)
\r
310 _queue.Add(notification);
\r
313 public void Flash()
\r
318 public void StopRepeat(string key, bool cont = false)
\r
322 _queue.RemoveAll(n => IsMatch(n, key));
\r
326 foreach (var n in _queue.Where(n => IsMatch(n, key)))
\r
329 n.Mode = Mode.Cont;
\r
334 public void StopRepeat(string key, int fleet)
\r
336 _queue.RemoveAll(n => IsMatch(n, key) && n.Fleet == fleet);
\r
339 public void StopRepeat(string key, string subject)
\r
341 _queue.RemoveAll(n => IsMatch(n, key) && n.Subject == subject);
\r
344 private bool IsMatch(Notification n, string key) =>
\r
345 n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default;
\r
347 public void StopAllRepeat()
\r
349 _queue.RemoveAll(n => n.Schedule != default);
\r
352 public void SuspendRepeat(string exception = null)
\r
355 _suspendException = exception;
\r
358 public void ResumeRepeat()
\r
363 private void Alarm()
\r
365 var now = _nowFunc();
\r
366 if (now - _lastAlarm < TimeSpan.FromSeconds(2))
\r
368 var first = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0 &&
\r
369 !(n.Schedule != default && _suspend && n.Key != _suspendException));
\r
372 var message = _notificationConfig.GenerateMessage(first);
\r
373 var similar = _queue.Where(n =>
\r
374 _notificationConfig.GenerateMessage(n).Name == message.Name && n.Schedule.CompareTo(now) <= 0)
\r
376 var body = string.Join("\r\n", similar.Select(n => _notificationConfig.GenerateMessage(n).Body));
\r
377 foreach (var n in similar)
\r
385 n.Schedule = now + TimeSpan.FromSeconds(n.Repeat);
\r
386 if (n.Mode == Mode.Normal)
\r
387 n.Mode = Mode.Repeat;
\r
390 _alarm(message.Title, body, message.Name);
\r