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
75 public class QuestInfo : IHaveState
\r
77 private readonly QuestCountList _countList;
\r
78 private readonly Func<DateTime> _nowFunc = () => DateTime.Now;
\r
79 private DateTime _now;
\r
80 private DateTime _lastReset;
\r
81 private IEnumerable<QuestStatus> _clearedQuest = new List<QuestStatus>();
\r
83 private readonly Color[] _color =
\r
85 Color.FromArgb(60, 141, 76), Color.FromArgb(232, 57, 41), Color.FromArgb(136, 204, 120),
\r
86 Color.FromArgb(52, 147, 185), Color.FromArgb(220, 198, 126), Color.FromArgb(168, 111, 76),
\r
87 Color.FromArgb(200, 148, 231), Color.FromArgb(232, 57, 41), Color.FromArgb(232, 57, 41)
\r
90 public SortedDictionary<int, QuestStatus> QuestDictionary { get; } = new SortedDictionary<int, QuestStatus>();
\r
92 public QuestStatus[] Quests => QuestDictionary.Values.ToArray();
\r
94 public QuestInfo(QuestCountList countList, Func<DateTime> nowFunc = null)
\r
96 _countList = countList;
\r
97 if (nowFunc != null)
\r
101 public void GetNotifications(out string[] notify, out string[] stop)
\r
103 var cleared = QuestDictionary.Values.Where(q => q.Count.Cleared).ToArray();
\r
104 notify = cleared.Except(_clearedQuest, new QuestComparer()).Select(q => q.Name).ToArray();
\r
105 stop = _clearedQuest.Except(cleared, new QuestComparer()).Select(q => q.Name).ToArray();
\r
106 _clearedQuest = cleared;
\r
109 private class QuestComparer : IEqualityComparer<QuestStatus>
\r
111 public bool Equals(QuestStatus x, QuestStatus y)
\r
113 return x?.Id == y?.Id;
\r
116 public int GetHashCode(QuestStatus obj)
\r
122 private readonly int[] _progress = {0, 50, 80};
\r
124 public void InspectQuestList(string request, dynamic json)
\r
127 var values = HttpUtility.ParseQueryString(request);
\r
128 if (values["api_tab_id"] == "0")
\r
129 QuestDictionary.Clear();
\r
130 if (json.api_list == null)
\r
132 foreach (var entry in json.api_list)
\r
134 if (entry is double) // -1の場合がある。
\r
136 var quest = new QuestStatus
\r
138 Id = (int)entry.api_no,
\r
139 Category = (int)entry.api_category,
\r
140 Progress = _progress[(int)entry.api_progress_flag],
\r
141 Name = (string)entry.api_title,
\r
142 Detail = ((string)entry.api_detail).Replace("<br>", "\r\n"),
\r
143 Material = (int[])entry.api_get_material
\r
145 var state = (int)entry.api_state;
\r
149 quest.Progress = 100;
\r
152 AdjustQuest(quest);
\r
159 private void AdjustQuest(QuestStatus quest)
\r
161 quest.Count = _countList.GetCount(quest.Id);
\r
162 if (quest.Count.AdjustCount(quest.Progress))
\r
164 quest.Material = quest.Material.Concat(quest.Count.Spec.Material).ToArray();
\r
165 if (!QuestDictionary.ContainsKey(quest.Id))
\r
169 private void SetQuest(QuestStatus quest)
\r
171 quest.Count = _countList.GetCount(quest.Id);
\r
172 quest.Color = quest.Category <= _color.Length ? _color[quest.Category - 1] : Control.DefaultBackColor;
\r
173 QuestDictionary[quest.Id] = quest;
\r
176 private void ResetCounts()
\r
179 if (!CrossBoundary(QuestInterval.Daily))
\r
181 foreach (var interval in (QuestInterval[])typeof(QuestInterval).GetEnumValues())
\r
183 if (!CrossBoundary(interval))
\r
185 _countList.Remove(interval);
\r
191 private DateTime LastMorning => _now.Date.AddDays(_now.Hour < 5 ? -1 : 0).AddHours(5);
\r
193 private bool CrossBoundary(QuestInterval interval)
\r
195 return interval switch
\r
197 QuestInterval.Other => false,
\r
198 QuestInterval.Daily => CrossBoundary(LastMorning),
\r
199 QuestInterval.Weekly => CrossBoundary(LastMonday.AddHours(5)),
\r
200 QuestInterval.Monthly => CrossBoundary(new DateTime(_now.Year, _now.Month, 1, 5, 0, 0)),
\r
201 QuestInterval.Quarterly => CrossBoundary(QuarterlyBoundary.AddHours(5)),
\r
202 QuestInterval.Yearly1 => CrossBoundary(new DateTime(_now.Year, 1, 1, 5, 0, 0)),
\r
203 QuestInterval.Yearly2 => CrossBoundary(new DateTime(_now.Year, 2, 1, 5, 0, 0)),
\r
204 QuestInterval.Yearly3 => CrossBoundary(new DateTime(_now.Year, 3, 1, 5, 0, 0)),
\r
205 QuestInterval.Yearly5 => CrossBoundary(new DateTime(_now.Year, 5, 1, 5, 0, 0)),
\r
206 QuestInterval.Yearly8 => CrossBoundary(new DateTime(_now.Year, 8, 1, 5, 0, 0)),
\r
207 QuestInterval.Yearly9 => CrossBoundary(new DateTime(_now.Year, 9, 1, 5, 0, 0)),
\r
208 QuestInterval.Yearly10 => CrossBoundary(new DateTime(_now.Year, 10, 1, 5, 0, 0)),
\r
209 QuestInterval.Yearly11 => CrossBoundary(new DateTime(_now.Year, 11, 1, 5, 0, 0)),
\r
214 private DateTime LastMonday => _now.Date.AddDays(-((6 + (int)_now.DayOfWeek) % 7));
\r
216 private DateTime QuarterlyBoundary =>
\r
217 _now.Month / 3 == 0
\r
218 ? new DateTime(_now.Year - 1, 12, 1)
\r
219 : new DateTime(_now.Year, _now.Month / 3 * 3, 1);
\r
221 private bool CrossBoundary(DateTime boundary)
\r
223 return _lastReset < boundary && boundary <= _now;
\r
226 public void InspectStop(string request)
\r
228 var values = HttpUtility.ParseQueryString(request);
\r
229 QuestDictionary.Remove(int.Parse(values["api_quest_id"]));
\r
233 public void InspectClearItemGet(string request)
\r
235 var values = HttpUtility.ParseQueryString(request);
\r
236 var id = int.Parse(values["api_quest_id"]);
\r
237 _countList.Remove(id);
\r
238 QuestDictionary.Remove(id);
\r
242 public bool NeedSave { get; set; }
\r
244 public void SaveState(Status status)
\r
247 status.QuestLastReset = _lastReset;
\r
248 if (QuestDictionary != null)
\r
249 status.QuestList = QuestDictionary.Values.ToArray();
\r
250 if (_countList != null)
\r
251 status.QuestCountList = _countList.NonZeroCountList.ToArray();
\r
254 public void LoadState(Status status)
\r
256 _lastReset = status.QuestLastReset;
\r
257 if (status.QuestCountList != null)
\r
258 _countList.SetCountList(status.QuestCountList);
\r
259 if (status.QuestList != null)
\r
261 QuestDictionary.Clear();
\r
262 foreach (var quest in status.QuestList)
\r