1 // Copyright (C) 2013, 2015 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
17 using System.Drawing;
\r
19 using System.Windows.Forms;
\r
20 using System.Xml.Serialization;
\r
21 using KancolleSniffer.Util;
\r
23 namespace KancolleSniffer.Model
\r
25 public class QuestStatus
\r
27 public int Id { get; set; }
\r
28 public int Category { get; set; }
\r
29 public string Name { get; set; }
\r
30 public string Detail { get; set; }
\r
31 public int[] Material { get; set; }
\r
32 public int Progress { get; set; }
\r
35 public QuestCount Count { get; set; }
\r
38 public Color Color { get; set; }
\r
40 public string ToToolTip() =>
\r
42 (Material == null || Material.All(x => x == 0)
\r
44 : "\r\n" + string.Join(" ",
\r
45 new[] {"燃", "弾", "鋼", "ボ", "建造", "修復", "開発", "改修"}
\r
46 .Zip(Material, (m, num) => num == 0 ? "" : m + num)
\r
47 .Where(s => !string.IsNullOrEmpty(s))));
\r
49 public QuestStatus Clone()
\r
51 var clone = (QuestStatus)MemberwiseClone();
\r
52 clone.Count = Count.Clone();
\r
57 public enum QuestInterval
\r
59 // ReSharper disable once UnusedMember.Global
\r
74 public class QuestInfo : IHaveState
\r
76 private readonly QuestCountList _countList;
\r
77 private readonly Func<DateTime> _nowFunc = () => DateTime.Now;
\r
78 private DateTime _now;
\r
79 private DateTime _lastReset;
\r
80 private IEnumerable<QuestStatus> _clearedQuest = new List<QuestStatus>();
\r
82 private readonly Color[] _color =
\r
84 Color.FromArgb(60, 141, 76), Color.FromArgb(232, 57, 41), Color.FromArgb(136, 204, 120),
\r
85 Color.FromArgb(52, 147, 185), Color.FromArgb(220, 198, 126), Color.FromArgb(168, 111, 76),
\r
86 Color.FromArgb(200, 148, 231), Color.FromArgb(232, 57, 41), Color.FromArgb(232, 57, 41)
\r
89 public SortedDictionary<int, QuestStatus> QuestDictionary { get; } = new SortedDictionary<int, QuestStatus>();
\r
91 public QuestStatus[] Quests => QuestDictionary.Values.ToArray();
\r
93 public QuestInfo(QuestCountList countList, Func<DateTime> nowFunc = null)
\r
95 _countList = countList;
\r
96 if (nowFunc != null)
\r
100 public void GetNotifications(out string[] notify, out string[] stop)
\r
102 var cleared = QuestDictionary.Values.Where(q => q.Count.Cleared).ToArray();
\r
103 notify = cleared.Except(_clearedQuest, new QuestComparer()).Select(q => q.Name).ToArray();
\r
104 stop = _clearedQuest.Except(cleared, new QuestComparer()).Select(q => q.Name).ToArray();
\r
105 _clearedQuest = cleared;
\r
108 private class QuestComparer : IEqualityComparer<QuestStatus>
\r
110 public bool Equals(QuestStatus x, QuestStatus y)
\r
112 return x?.Id == y?.Id;
\r
115 public int GetHashCode(QuestStatus obj)
\r
121 private readonly int[] _progress = {0, 50, 80};
\r
123 public void InspectQuestList(string request, dynamic json)
\r
126 var values = HttpUtility.ParseQueryString(request);
\r
127 if (values["api_tab_id"] == "0")
\r
128 QuestDictionary.Clear();
\r
129 if (json.api_list == null)
\r
131 foreach (var entry in json.api_list)
\r
133 if (entry is double) // -1の場合がある。
\r
135 var quest = new QuestStatus
\r
137 Id = (int)entry.api_no,
\r
138 Category = (int)entry.api_category,
\r
139 Progress = _progress[(int)entry.api_progress_flag],
\r
140 Name = (string)entry.api_title,
\r
141 Detail = ((string)entry.api_detail).Replace("<br>", "\r\n"),
\r
142 Material = (int[])entry.api_get_material
\r
144 var state = (int)entry.api_state;
\r
148 quest.Progress = 100;
\r
151 AdjustQuest(quest);
\r
158 private void AdjustQuest(QuestStatus quest)
\r
160 quest.Count = _countList.GetCount(quest.Id);
\r
161 if (quest.Count.AdjustCount(quest.Progress))
\r
163 quest.Material = quest.Material.Concat(quest.Count.Spec.Material).ToArray();
\r
164 if (!QuestDictionary.ContainsKey(quest.Id))
\r
168 private void SetQuest(QuestStatus quest)
\r
170 quest.Count = _countList.GetCount(quest.Id);
\r
171 quest.Color = quest.Category <= _color.Length ? _color[quest.Category - 1] : Control.DefaultBackColor;
\r
172 QuestDictionary[quest.Id] = quest;
\r
175 private void ResetCounts()
\r
178 if (!CrossBoundary(QuestInterval.Daily))
\r
180 foreach (var interval in (QuestInterval[])typeof(QuestInterval).GetEnumValues())
\r
182 if (!CrossBoundary(interval))
\r
184 _countList.Remove(interval);
\r
190 private DateTime LastMorning => _now.Date.AddDays(_now.Hour < 5 ? -1 : 0).AddHours(5);
\r
192 private bool CrossBoundary(QuestInterval interval)
\r
194 return interval switch
\r
196 QuestInterval.Other => false,
\r
197 QuestInterval.Daily => CrossBoundary(LastMorning),
\r
198 QuestInterval.Weekly => CrossBoundary(LastMonday.AddHours(5)),
\r
199 QuestInterval.Monthly => CrossBoundary(new DateTime(_now.Year, _now.Month, 1, 5, 0, 0)),
\r
200 QuestInterval.Quarterly => CrossBoundary(QuarterlyBoundary.AddHours(5)),
\r
201 QuestInterval.Yearly2 => CrossBoundary(new DateTime(_now.Year, 2, 1, 5, 0, 0)),
\r
202 QuestInterval.Yearly3 => CrossBoundary(new DateTime(_now.Year, 3, 1, 5, 0, 0)),
\r
203 QuestInterval.Yearly5 => CrossBoundary(new DateTime(_now.Year, 5, 1, 5, 0, 0)),
\r
204 QuestInterval.Yearly8 => CrossBoundary(new DateTime(_now.Year, 8, 1, 5, 0, 0)),
\r
205 QuestInterval.Yearly9 => CrossBoundary(new DateTime(_now.Year, 9, 1, 5, 0, 0)),
\r
206 QuestInterval.Yearly10 => CrossBoundary(new DateTime(_now.Year, 10, 1, 5, 0, 0)),
\r
207 QuestInterval.Yearly11 => CrossBoundary(new DateTime(_now.Year, 11, 1, 5, 0, 0)),
\r
212 private DateTime LastMonday => _now.Date.AddDays(-((6 + (int)_now.DayOfWeek) % 7));
\r
214 private DateTime QuarterlyBoundary =>
\r
215 _now.Month / 3 == 0
\r
216 ? new DateTime(_now.Year - 1, 12, 1)
\r
217 : new DateTime(_now.Year, _now.Month / 3 * 3, 1);
\r
219 private bool CrossBoundary(DateTime boundary)
\r
221 return _lastReset < boundary && boundary <= _now;
\r
224 public void InspectStop(string request)
\r
226 var values = HttpUtility.ParseQueryString(request);
\r
227 QuestDictionary.Remove(int.Parse(values["api_quest_id"]));
\r
231 public void InspectClearItemGet(string request)
\r
233 var values = HttpUtility.ParseQueryString(request);
\r
234 var id = int.Parse(values["api_quest_id"]);
\r
235 _countList.Remove(id);
\r
236 QuestDictionary.Remove(id);
\r
240 public bool NeedSave { get; set; }
\r
242 public void SaveState(Status status)
\r
245 status.QuestLastReset = _lastReset;
\r
246 if (QuestDictionary != null)
\r
247 status.QuestList = QuestDictionary.Values.ToArray();
\r
248 if (_countList != null)
\r
249 status.QuestCountList = _countList.NonZeroCountList.ToArray();
\r
252 public void LoadState(Status status)
\r
254 _lastReset = status.QuestLastReset;
\r
255 if (status.QuestCountList != null)
\r
256 _countList.SetCountList(status.QuestCountList);
\r
257 if (status.QuestList != null)
\r
259 QuestDictionary.Clear();
\r
260 foreach (var quest in status.QuestList)
\r