OSDN Git Service

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