OSDN Git Service

ReSharperの警告を抑制する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Config.cs
1 // Copyright (C) 2014, 2015 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.Drawing;\r
18 using System.IO;\r
19 using System.Linq;\r
20 using System.Xml.Serialization;\r
21 // ReSharper disable MemberCanBePrivate.Global\r
22 // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\r
23 \r
24 namespace KancolleSniffer\r
25 {\r
26     public class ProxyConfig\r
27     {\r
28         public const int DefaultListenPort = 8080;\r
29         public bool Auto { get; set; }\r
30         public int Listen { get; set; }\r
31         public bool UseUpstream { get; set; }\r
32         public int UpstreamPort { get; set; }\r
33 \r
34         public ProxyConfig()\r
35         {\r
36             Auto = true;\r
37             Listen = DefaultListenPort;\r
38             UseUpstream = false;\r
39             UpstreamPort = 8888;\r
40         }\r
41     }\r
42 \r
43     [Flags]\r
44     public enum ShipCategory\r
45     {\r
46         // ReSharper disable UnusedMember.Global\r
47         None = 0,\r
48         BattleShip = 1,\r
49         AircraftCarrier = 1 << 1,\r
50         HeavyCruiser = 1 << 2,\r
51         LightCruiser = 1 << 3,\r
52         Destroyer = 1 << 4,\r
53         Escort = 1 << 5,\r
54         Submarine = 1 << 6,\r
55         Assistant = 1 << 7,\r
56         // ReSharper restore UnusedMember.Global\r
57         All = (1 << 8) - 1\r
58     }\r
59 \r
60     public class ShipListConfig\r
61     {\r
62         public bool Visible { get; set; }\r
63         public Point Location { get; set; }\r
64         public Size Size { get; set; }\r
65         public string Mode { get; set; }\r
66         public ShipCategory ShipCategories { get; set; } = ShipCategory.All;\r
67         public bool ShipType { get; set; }\r
68         public bool ShowHpInPercent { get; set; }\r
69         public ListForm.SortOrder SortOrder { get; set; } = ListForm.SortOrder.ExpToNext;\r
70         public List<List<int>> ShipGroup { get; set; }\r
71         public bool AutoBattleResult { get; set; } = true;\r
72 \r
73         public ShipListConfig()\r
74         {\r
75             Location = new Point(int.MinValue, int.MinValue);\r
76             ShipGroup = new List<List<int>>();\r
77         }\r
78     }\r
79 \r
80     public class LogConfig\r
81     {\r
82         public bool On { get; set; }\r
83         public string OutputDir { get; set; }\r
84         public int MaterialLogInterval { get; set; }\r
85 \r
86         public LogConfig()\r
87         {\r
88             On = true;\r
89             OutputDir = "";\r
90             MaterialLogInterval = 10;\r
91         }\r
92     }\r
93 \r
94     public class PushbulletConfig\r
95     {\r
96         public bool On { get; set; }\r
97         public string Token { get; set; } = "";\r
98     }\r
99 \r
100     public class PushoverConfig\r
101     {\r
102         public bool On { get; set; }\r
103         public string ApiKey { get; set; } = "";\r
104         public string UserKey { get; set; } = "";\r
105     }\r
106 \r
107     public class SoundConfig\r
108     {\r
109         public int Volume { get; set; } = 100;\r
110 \r
111         public string[] Files =\r
112         {\r
113             "ensei.mp3",\r
114             "nyuukyo.mp3",\r
115             "kenzou.mp3",\r
116             "kanmusu.mp3",\r
117             "soubi.mp3",\r
118             "taiha.mp3",\r
119             "20min.mp3",\r
120             "syuuri.mp3",\r
121             "syuuri2.mp3",\r
122             "hirou.mp3",\r
123             "ninmu.mp3"\r
124         };\r
125 \r
126         public string this[string name]\r
127         {\r
128             get => Files[Config.NotificationIndex[name]];\r
129             set => Files[Config.NotificationIndex[name]] = value;\r
130         }\r
131 \r
132         public void Upgrade()\r
133         {\r
134             var expected = Config.NotificationNames.Length;\r
135             if (Files.Length == expected)\r
136                 return;\r
137             Array.Resize(ref Files, expected);\r
138             Files[expected - 1] = "ninmu.mp3";\r
139         }\r
140     }\r
141 \r
142     [Flags]\r
143     public enum NotificationType\r
144     {\r
145         FlashWindow = 1,\r
146         // ReSharper disable once IdentifierTypo\r
147         ShowBaloonTip = 1 << 1,\r
148         PlaySound = 1 << 2,\r
149         All = (1 << 3) - 1,\r
150         Pushbullet = 1 << 3,\r
151         Push = 1 << 4,\r
152         Repeat = 1 << 5,\r
153         Cont = 1 << 6,\r
154         Preliminary = 1 << 7\r
155     }\r
156 \r
157     public class NotificationSpec\r
158     {\r
159         public string Name { get; set; }\r
160         public NotificationType Flags { get; set; }\r
161         public int RepeatInterval { get; set; }\r
162         public int PreliminaryPeriod { get; set; }\r
163     }\r
164 \r
165     public class NotificationConfig\r
166     {\r
167         public NotificationType[] Settings =\r
168             Config.NotificationNames.Select(x => NotificationType.All).ToArray();\r
169 \r
170         public int[] RepeatIntervals =\r
171             Config.NotificationNames.Select(x => 0).ToArray();\r
172 \r
173         public int[] PreliminaryPeriods =\r
174             Config.NotificationNames.Select(x => 0).ToArray();\r
175 \r
176         public NotificationSpec this[string name]\r
177         {\r
178             get => new NotificationSpec\r
179             {\r
180                 Name = name,\r
181                 Flags = Settings[Config.NotificationIndex[name]],\r
182                 RepeatInterval = RepeatIntervals[Config.NotificationIndex[name]],\r
183                 PreliminaryPeriod = PreliminaryPeriods[Config.NotificationIndex[name]]\r
184             };\r
185             set\r
186             {\r
187                 Settings[Config.NotificationIndex[name]] = value.Flags;\r
188                 RepeatIntervals[Config.NotificationIndex[name]] = value.RepeatInterval;\r
189                 PreliminaryPeriods[Config.NotificationIndex[name]] = value.PreliminaryPeriod;\r
190             }\r
191         }\r
192 \r
193         public void Upgrade()\r
194         {\r
195             UpgradeSettings(ref Settings);\r
196             UpgradeParameterArray(ref RepeatIntervals);\r
197             UpgradeParameterArray(ref PreliminaryPeriods);\r
198         }\r
199 \r
200         private void UpgradeSettings(ref NotificationType[] settings)\r
201         {\r
202             for (var i = 0; i < settings.Length; i++)\r
203             {\r
204                 if ((settings[i] & NotificationType.Pushbullet) != 0)\r
205                     settings[i] = settings[i] ^ NotificationType.Pushbullet | NotificationType.Push;\r
206             }\r
207             var expected = Config.NotificationNames.Length;\r
208             if (expected == settings.Length)\r
209                 return;\r
210             Array.Resize(ref settings, expected);\r
211             settings[expected - 1] = NotificationType.All;\r
212         }\r
213 \r
214         private void UpgradeParameterArray(ref int[] array)\r
215         {\r
216             Array.Resize(ref array, Config.NotificationNames.Length);\r
217             for (var i = 0; i < array.Length; i++)\r
218             {\r
219                 if (array[i] < 0)\r
220                     array[i] = 0;\r
221             }\r
222         }\r
223     }\r
224 \r
225     public class LocationPerMachine\r
226     {\r
227         public string MachineName { get; set; }\r
228         public Point Location { get; set; }\r
229         public int Zoom { get; set; } = 100;\r
230         public Point ListLocation { get; set; }\r
231         public Size ListSize { get; set; }\r
232     }\r
233 \r
234     [Flags]\r
235     public enum Spoiler\r
236     {\r
237         ResultRank = 1,\r
238         AirBattleResult = 1 << 1,\r
239         BattleResult = 1 << 2,\r
240         NextCell = 1 << 3,\r
241         All = (1 << 4) - 1\r
242     }\r
243 \r
244     [Flags]\r
245     public enum TimerKind\r
246     {\r
247         Mission = 1,\r
248         NDock = 1 << 1\r
249     }\r
250 \r
251     public class Config\r
252     {\r
253         public Point Location { get; set; } = new Point(int.MinValue, int.MinValue);\r
254         public bool TopMost { get; set; }\r
255         public bool HideOnMinimized { get; set; }\r
256         public bool ExitSilently { get; set; }\r
257         public int Zoom { get; set; } = 100;\r
258         public int QuestLines { get; set; } = 6;\r
259         public bool SaveLocationPerMachine { get; set; }\r
260         public List<LocationPerMachine> LocationList { get; set; } = new List<LocationPerMachine>();\r
261         public bool ShowHpInPercent { get; set; }\r
262         public TimerKind ShowEndTime { get; set; }\r
263         public bool FlashWindow { get; set; } = true;\r
264         // ReSharper disable once IdentifierTypo\r
265         public bool ShowBaloonTip { get; set; } = true;\r
266         public bool PlaySound { get; set; } = true;\r
267         public NotificationType NotificationFlags { get; set; } = NotificationType.All;\r
268         public NotificationConfig Notifications { get; set; } = new NotificationConfig();\r
269         public int MarginShips { get; set; } = 5;\r
270         public int MarginEquips { get; set; } = 5;\r
271         public List<int> NotifyConditions { get; set; }\r
272         public List<int> ResetHours { get; set; }\r
273         public bool AlwaysShowResultRank { get; set; }\r
274         public Spoiler Spoilers { get; set; }\r
275         public bool UsePresetAkashi { get; set; }\r
276         public bool WarnBadDamageWithDameCon { get; set; }\r
277         public SoundConfig Sounds { get; set; } = new SoundConfig();\r
278         public bool DebugLogging { get; set; }\r
279         public string DebugLogFile { get; set; } = "log.txt";\r
280         public ProxyConfig Proxy { get; set; } = new ProxyConfig();\r
281         public ShipListConfig ShipList { get; set; } = new ShipListConfig();\r
282         public List<ShipListConfig> ListFormGroup { get; set; } = new List<ShipListConfig>();\r
283         public LogConfig Log { get; set; } = new LogConfig();\r
284         public PushbulletConfig Pushbullet { get; set; } = new PushbulletConfig();\r
285         public PushoverConfig Pushover { get; set; } = new PushoverConfig();\r
286 \r
287         public static readonly string[] NotificationNames =\r
288         {\r
289             "遠征終了", "入渠終了", "建造完了", "艦娘数超過", "装備数超過",\r
290             "大破警告", "泊地修理20分経過", "泊地修理進行", "泊地修理完了", "疲労回復", "任務達成"\r
291         };\r
292 \r
293         public static readonly Dictionary<string, int> NotificationIndex =\r
294             NotificationNames.Select((name, i) => new {name, i}).ToDictionary(entry => entry.name, entry => entry.i);\r
295 \r
296 \r
297         private const string FileName = "config.xml";\r
298         public static readonly string BaseDir = AppDomain.CurrentDomain.BaseDirectory;\r
299         private static readonly string ConfigFile = Path.Combine(BaseDir, FileName);\r
300 \r
301         public Config()\r
302         {\r
303             ConvertPath(PrependBaseDir);\r
304         }\r
305 \r
306         private void InitializeValues()\r
307         {\r
308             NotifyConditions = new List<int>(new[] {40, 49});\r
309             ResetHours = new List<int>(new[] {2});\r
310         }\r
311 \r
312         public void Load()\r
313         {\r
314             try\r
315             {\r
316                 var serializer = new XmlSerializer(typeof(Config));\r
317                 Config config;\r
318                 using (var file = File.OpenText(ConfigFile))\r
319                     config = (Config)serializer.Deserialize(file);\r
320                 foreach (var property in GetType().GetProperties())\r
321                     property.SetValue(this, property.GetValue(config, null), null);\r
322                 Notifications.Upgrade();\r
323                 ComposeNotificationFlags();\r
324                 Sounds.Upgrade();\r
325                 if (AlwaysShowResultRank)\r
326                 {\r
327                     Spoilers = Spoiler.All;\r
328                     AlwaysShowResultRank = false;\r
329                 }\r
330                 if (SaveLocationPerMachine)\r
331                 {\r
332                     foreach (var l in LocationList)\r
333                     {\r
334                         if (l.MachineName != Environment.MachineName)\r
335                             continue;\r
336                         Location = l.Location;\r
337                         Zoom = l.Zoom;\r
338                         ShipList.Location = l.ListLocation;\r
339                         ShipList.Size = l.ListSize;\r
340                     }\r
341                 }\r
342             }\r
343             catch (FileNotFoundException)\r
344             {\r
345                 InitializeValues();\r
346                 Save();\r
347             }\r
348             catch (InvalidOperationException ex)\r
349             {\r
350                 File.Delete(ConfigFile);\r
351                 throw new Exception(FileName + "が壊れています。", ex);\r
352             }\r
353             ConvertPath(PrependBaseDir);\r
354         }\r
355 \r
356         private void ComposeNotificationFlags()\r
357         {\r
358             NotificationFlags = (NotificationFlags & ~NotificationType.All) |\r
359                                 (FlashWindow ? NotificationType.FlashWindow : 0) |\r
360                                 (ShowBaloonTip ? NotificationType.ShowBaloonTip : 0) |\r
361                                 (PlaySound ? NotificationType.PlaySound : 0);\r
362         }\r
363 \r
364         public void Save()\r
365         {\r
366             if (SaveLocationPerMachine)\r
367             {\r
368                 LocationList = LocationList.Where(l => l.MachineName != Environment.MachineName).ToList();\r
369                 LocationList.Add(new LocationPerMachine\r
370                 {\r
371                     MachineName = Environment.MachineName,\r
372                     Location = Location,\r
373                     Zoom = Zoom,\r
374                     ListLocation = ShipList.Location,\r
375                     ListSize = ShipList.Size\r
376                 });\r
377             }\r
378             else\r
379             {\r
380                 LocationList = new List<LocationPerMachine>();\r
381             }\r
382             DecomposeNotificationFlags();\r
383             ConvertPath(StripBaseDir);\r
384             var serializer = new XmlSerializer(typeof(Config));\r
385             using (var file = File.CreateText(ConfigFile + ".tmp"))\r
386                 serializer.Serialize(file, this);\r
387             File.Copy(ConfigFile + ".tmp", ConfigFile, true);\r
388             File.Delete(ConfigFile + ".tmp");\r
389             ConvertPath(PrependBaseDir);\r
390         }\r
391 \r
392         private void DecomposeNotificationFlags()\r
393         {\r
394             FlashWindow = (NotificationFlags & NotificationType.FlashWindow) != 0;\r
395             ShowBaloonTip = (NotificationFlags & NotificationType.ShowBaloonTip) != 0;\r
396             PlaySound = (NotificationFlags & NotificationType.PlaySound) != 0;\r
397         }\r
398 \r
399         private void ConvertPath(Func<string, string> func)\r
400         {\r
401             DebugLogFile = func(DebugLogFile);\r
402             Log.OutputDir = func(Log.OutputDir);\r
403             for (var i = 0; i < Sounds.Files.Length; i++)\r
404                 Sounds.Files[i] = func(Sounds.Files[i]);\r
405         }\r
406 \r
407         private string StripBaseDir(string path)\r
408         {\r
409             if (!path.StartsWith(BaseDir))\r
410                 return path;\r
411             path = path.Substring(BaseDir.Length);\r
412             return path.TrimStart(Path.DirectorySeparatorChar);\r
413         }\r
414 \r
415         private string PrependBaseDir(string path) => Path.IsPathRooted(path) ? path : Path.Combine(BaseDir, path);\r
416     }\r
417 }