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
20 namespace KancolleSniffer
\r
22 public class NotificationManager
\r
24 private readonly NotificationQueue _notificationQueue;
\r
34 private class Notification
\r
36 public string Key { get; set; }
\r
37 public int Fleet { get; set; }
\r
38 public string Subject { get; set; }
\r
39 public int Repeat { get; set; }
\r
40 public Mode Mode { get; set; }
\r
41 public DateTime Schedule { get; set; }
\r
44 public NotificationManager(Action<string, string, string> alarm, Func<DateTime> nowFunc = null)
\r
46 _notificationQueue = new NotificationQueue(alarm, nowFunc);
\r
49 public void Enqueue(string key, int fleet, string subject, int repeat = 0, bool preliminary = false)
\r
51 _notificationQueue.Enqueue(new Notification
\r
57 Mode = preliminary ? Mode.Preliminary : Mode.Normal
\r
61 public void Enqueue(string key, string subject, int repeat = 0)
\r
63 Enqueue(key, 0, subject, repeat);
\r
68 _notificationQueue.Flash();
\r
71 public void StopRepeat(string key, bool cont = false)
\r
73 _notificationQueue.StopRepeat(key, cont);
\r
76 public void StopRepeat(string key, int fleet)
\r
78 _notificationQueue.StopRepeat(key, fleet);
\r
81 public void SuspendRepeat()
\r
83 _notificationQueue.SuspendRepeat();
\r
86 public void ResumeRepeat()
\r
88 _notificationQueue.ResumeRepeat();
\r
91 public string KeyToName(string key) => NotificationConfig.KeyToName(key);
\r
93 private class NotificationConfig
\r
95 public class Message
\r
97 public string Title { get; set; }
\r
98 public string Body { get; set; }
\r
99 public string Name { get; set; }
\r
102 private readonly Dictionary<string, Message> _config = new Dictionary<string, Message>();
\r
104 private readonly Dictionary<string, Message> _default = new Dictionary<string, Message>
\r
107 "遠征終了", new Message
\r
109 Title = "遠征が終わりました",
\r
114 "入渠終了", new Message
\r
116 Title = "入渠が終わりました",
\r
121 "建造完了", new Message
\r
123 Title = "建造が終わりました",
\r
128 "艦娘数超過", new Message
\r
130 Title = "艦娘が多すぎます",
\r
135 "装備数超過", new Message
\r
137 Title = "装備が多すぎます",
\r
142 "大破警告", new Message
\r
144 Title = "大破した艦娘がいます",
\r
149 "泊地修理20分経過", new Message
\r
151 Title = "泊地修理 %f艦隊",
\r
152 Body = "20分経過しました。"
\r
156 "泊地修理進行", new Message
\r
158 Title = "泊地修理 %f艦隊",
\r
163 "泊地修理完了", new Message
\r
165 Title = "泊地修理 %f艦隊",
\r
170 "疲労回復40", new Message
\r
172 Title = "疲労が回復しました",
\r
177 "疲労回復49", new Message
\r
179 Title = "疲労が回復しました",
\r
185 public static string KeyToName(string key) => key.StartsWith("疲労回復") ? key.Substring(0, 4) : key;
\r
187 private void LoadConfig()
\r
189 const string fileName = "notification.json";
\r
193 dynamic config = JsonParser.Parse(File.ReadAllText(fileName));
\r
194 foreach (var entry in config)
\r
196 if (!_default.ContainsKey(entry.key))
\r
198 _config[entry.key] = new Message
\r
200 Title = entry.title,
\r
205 catch (FileNotFoundException)
\r
208 catch (Exception ex)
\r
210 throw new Exception($"{fileName}に誤りがあります。: ${ex.Message}", ex);
\r
214 public Message GenerateMessage(Notification notification)
\r
217 var format = _config.TryGetValue(notification.Key, out Message value)
\r
219 : _default[notification.Key];
\r
220 var prefix = new[] {"", "[リピート] ", "[継続] ", "[予告] "}[(int)notification.Mode];
\r
223 Title = prefix + ProcessFormatString(format.Title, notification.Fleet, notification.Subject),
\r
224 Body = ProcessFormatString(format.Body, notification.Fleet, notification.Subject),
\r
225 Name = KeyToName(notification.Key)
\r
229 private string ProcessFormatString(string format, int fleet, string subject)
\r
231 var fn = new[] {"第一", "第二", "第三", "第四"};
\r
233 var percent = false;
\r
234 foreach (var ch in format)
\r
254 result += fn[fleet];
\r
260 result += '%'.ToString() + ch;
\r
273 private class NotificationQueue
\r
275 private readonly Action<string, string, string> _alarm;
\r
276 private readonly List<Notification> _queue = new List<Notification>();
\r
277 private readonly Func<DateTime> _nowFunc = () => DateTime.Now;
\r
278 private readonly NotificationConfig _notificationConfig = new NotificationConfig();
\r
279 private DateTime _lastAlarm;
\r
280 private bool _suspend;
\r
282 public NotificationQueue(Action<string, string, string> alarm, Func<DateTime> nowFunc = null)
\r
285 if (nowFunc != null)
\r
286 _nowFunc = nowFunc;
\r
289 public void Enqueue(Notification notification)
\r
291 _queue.Add(notification);
\r
294 public void Flash()
\r
299 public void StopRepeat(string key, bool cont = false)
\r
303 _queue.RemoveAll(n => IsMatch(n, key));
\r
307 foreach (var n in _queue.Where(n => IsMatch(n, key)))
\r
310 n.Mode = Mode.Cont;
\r
315 public void StopRepeat(string key, int fleet)
\r
317 _queue.RemoveAll(n => IsMatch(n, key) && n.Fleet == fleet);
\r
320 private bool IsMatch(Notification n, string key) =>
\r
321 n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default;
\r
323 public void SuspendRepeat()
\r
328 public void ResumeRepeat()
\r
333 private void Alarm()
\r
335 var now = _nowFunc();
\r
336 if (now - _lastAlarm < TimeSpan.FromSeconds(2))
\r
338 var first = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0 &&
\r
339 !(_suspend && n.Schedule != default));
\r
342 var message = _notificationConfig.GenerateMessage(first);
\r
343 var similar = _queue.Where(n =>
\r
344 _notificationConfig.GenerateMessage(n).Name == message.Name && n.Schedule.CompareTo(now) <= 0)
\r
346 var body = string.Join("\r\n", similar.Select(n => _notificationConfig.GenerateMessage(n).Body));
\r
347 foreach (var n in similar)
\r
355 n.Schedule = now + TimeSpan.FromSeconds(n.Repeat);
\r
356 if (n.Mode == Mode.Normal)
\r
357 n.Mode = Mode.Repeat;
\r
360 _alarm(message.Title, body, message.Name);
\r