OSDN Git Service

タイマーの時刻を保持するTimeStepクラスを導入する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Notification / Scheduler.cs
1 // Copyright (C) 2017 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\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
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\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
14 \r
15 using System;\r
16 using System.Collections.Generic;\r
17 using System.Linq;\r
18 \r
19 namespace KancolleSniffer.Notification\r
20 {\r
21     public class Scheduler\r
22     {\r
23         private readonly Action<string, string, string> _alarm;\r
24         private readonly List<Notification> _queue = new List<Notification>();\r
25         private readonly Func<DateTime> _nowFunc = () => DateTime.Now;\r
26         private readonly Formatter _formatter = new Formatter();\r
27         private DateTime _lastAlarm;\r
28         private bool _suspend;\r
29         private string _suspendException;\r
30 \r
31         public enum Mode\r
32         {\r
33             Normal,\r
34             Repeat,\r
35             Cont,\r
36             Preliminary\r
37         }\r
38 \r
39         public class Notification\r
40         {\r
41             public string Key { get; set; }\r
42             public int Fleet { get; set; }\r
43             public string Subject { get; set; }\r
44             public int Repeat { get; set; }\r
45             public Mode Mode { get; set; }\r
46             public DateTime Schedule { get; set; }\r
47         }\r
48 \r
49         public Scheduler(Action<string, string, string> alarm, Func<DateTime> nowFunc = null)\r
50         {\r
51             _alarm = alarm;\r
52             if (nowFunc != null)\r
53                 _nowFunc = nowFunc;\r
54         }\r
55 \r
56         public void Enqueue(string key, int fleet, string subject, int repeat = 0, bool preliminary = false)\r
57         {\r
58             _queue.Add(new Notification\r
59             {\r
60                 Key = key,\r
61                 Fleet = fleet,\r
62                 Subject = subject,\r
63                 Repeat = repeat,\r
64                 Mode = preliminary ? Mode.Preliminary : Mode.Normal\r
65             });\r
66         }\r
67 \r
68         public void Enqueue(string key, string subject, int repeat = 0)\r
69         {\r
70             Enqueue(key, 0, subject, repeat);\r
71         }\r
72 \r
73         public void Flush()\r
74         {\r
75             Alarm();\r
76         }\r
77 \r
78         public void StopRepeat(string key, bool cont = false)\r
79         {\r
80             if (!cont)\r
81             {\r
82                 _queue.RemoveAll(n => IsMatch(n, key));\r
83             }\r
84             else\r
85             {\r
86                 foreach (var n in _queue.Where(n => IsMatch(n, key)))\r
87                 {\r
88                     n.Subject = "";\r
89                     n.Mode = Mode.Cont;\r
90                 }\r
91             }\r
92         }\r
93 \r
94         public void StopRepeat(string key, int fleet)\r
95         {\r
96             _queue.RemoveAll(n => IsMatch(n, key) && n.Fleet == fleet);\r
97         }\r
98 \r
99         public void StopRepeat(string key, string subject)\r
100         {\r
101             _queue.RemoveAll(n => IsMatch(n, key) && n.Subject == subject);\r
102         }\r
103 \r
104         public void StopAllRepeat()\r
105         {\r
106             _queue.RemoveAll(n => n.Schedule != default);\r
107         }\r
108 \r
109         public void SuspendRepeat(string exception = "")\r
110         {\r
111             _suspend = true;\r
112             _suspendException = exception;\r
113         }\r
114 \r
115         public void ResumeRepeat()\r
116         {\r
117             _suspend = false;\r
118         }\r
119 \r
120         public string KeyToName(string key) => Formatter.KeyToName(key);\r
121 \r
122         private bool IsMatch(Notification n, string key) =>\r
123             n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default;\r
124 \r
125         private void Alarm()\r
126         {\r
127             var now = _nowFunc();\r
128             if (now - _lastAlarm < TimeSpan.FromSeconds(2))\r
129                 return;\r
130             var first = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0 &&\r
131                                                    !(n.Schedule != default && _suspend && n.Key != _suspendException));\r
132             if (first == null)\r
133                 return;\r
134             var message = _formatter.GenerateMessage(first);\r
135             var similar = _queue.Where(n =>\r
136                     _formatter.GenerateMessage(n).Name == message.Name && n.Schedule.CompareTo(now) <= 0)\r
137                 .ToArray();\r
138             var body = string.Join("\r\n", similar.Select(n => _formatter.GenerateMessage(n).Body));\r
139             foreach (var n in similar)\r
140             {\r
141                 if (n.Repeat == 0)\r
142                 {\r
143                     _queue.Remove(n);\r
144                 }\r
145                 else\r
146                 {\r
147                     n.Schedule = now + TimeSpan.FromSeconds(n.Repeat);\r
148                     if (n.Mode == Mode.Normal)\r
149                         n.Mode = Mode.Repeat;\r
150                 }\r
151             }\r
152             _alarm(message.Title, body, message.Name);\r
153             _lastAlarm = now;\r
154         }\r
155     }\r
156 }