Projekt

Obecné

Profil

Stáhnout (15.1 KB) Statistiky
| Větev: | Tag: | Revize:
1
using ServerApp.DataDownload;
2
using ServerApp.Parser.OutputInfo;
3
using System;
4
using System.Collections.Generic;
5
using System.Globalization;
6
using System.IO;
7
using System.Net;
8
using System.Text.Json;
9
using static System.Text.Json.JsonElement;
10

    
11
namespace ServerApp.Parser.Parsers
12
{
13
    /// <summary>
14
    /// Class representing a parser for json prediction data
15
    /// </summary>
16
    /// <author>A. Konig</author>
17
    class JsonParser
18
    {
19
        /// <summary> Current weather </summary>
20
        public WeatherInfo current;
21
        /// <summary> Prediction for today, tommorrow and day after tommorrow </summary>
22
        public List<WeatherInfo> predictions;
23
        
24
        /// <summary> Data loader </summary>
25
        DataDownloader loader;
26
        /// <summary> Currently parsed day </summary>
27
        DateTime currParsedDay;
28
        /// <summary> Sunrise time of currently parsed day </summary>
29
        DateTime sunriseTime;
30
        /// <summary> Sunset time of currently parsed day </summary>
31
        DateTime sunsetTime;
32

    
33
        /// <summary>
34
        /// Constructor
35
        /// </summary>
36
        /// <param name="loader"></param>
37
        public JsonParser(DataDownloader loader)
38
        {
39
            this.loader = loader;
40
        }
41

    
42
        /// <summary>
43
        /// Parse weather prediction
44
        /// Results is in attributes current for current weather and pred for weather prediction for today, tommorrow and day after tommorrow
45
        /// </summary>
46
        public void ParsePrediction()
47
        {
48
            // TODO ask DataDownloader for download said file and return path to it
49
            
50
            // get file
51
            string file = DownloadWeatherPrediction();
52
            DateTime now = DateTime.Now;
53
            Console.WriteLine(File.Exists(file));
54

    
55
            // parse file
56
            string data = File.ReadAllText(file);
57

    
58
            JsonDocument doc = JsonDocument.Parse(data);
59
            JsonElement root = doc.RootElement;
60
            var weatherP = root.EnumerateObject();
61
            predictions = new List<WeatherInfo>();
62

    
63
            while (weatherP.MoveNext())
64
            {
65
                string name = weatherP.Current.Name;
66
                Console.WriteLine(name);
67

    
68
                switch (name)
69
                {
70
                    // current weather
71
                    case "current_condition":
72
                        {
73
                            ArrayEnumerator currentWeather = weatherP.Current.Value.EnumerateArray();
74
                            current = ParseCurrentWeather(currentWeather);
75

    
76
                            break;
77

    
78
                        }
79
                    // weather prediction
80
                    case "weather":
81
                        {
82
                            ArrayEnumerator weather = weatherP.Current.Value.EnumerateArray();
83
                            ParseWeatherPredict(weather);
84

    
85
                            break;
86
                        }
87
                }
88
            }
89

    
90
            // sunrise + sunset into data
91
            EncompassSunRiseSetTimes();
92

    
93
            TestConsoleOutput();
94
        }
95

    
96
        private void TestConsoleOutput()
97
        {
98
            Console.WriteLine(current);
99
            foreach (WeatherInfo w in predictions)
100
                Console.WriteLine(w);
101
        }
102

    
103
        // TODO move to data loader
104
        /// <summary>
105
        /// Downloads json file
106
        /// </summary>
107
        /// <returns> Path to file </returns>
108
        private string DownloadWeatherPrediction()
109
        {
110
            DateTime now = DateTime.Now;
111
            WebClient webClient = new WebClient();
112
            webClient.DownloadFile("http://wttr.in/Plzen,czechia?format=j1", $"data/{now.Year}{now.Month}{now.Day}.json");
113

    
114
            return $"data/{now.Year}{now.Month}{now.Day}.json";
115
        }
116

    
117
        /// <summary>
118
        /// Change data in a way that they now reflect sunrise and sunset times
119
        /// If current time under sunrise or over sunset -> WeatherConditions is Dark
120
        /// If prediction time is under sunrise or over sunset and more than half of the interval is under/over said time -> WeatherCondition is Dark
121
        /// </summary>
122
        private void EncompassSunRiseSetTimes()
123
        {
124
            // change current weather
125
            if ((current.startTime.TimeOfDay > sunsetTime.TimeOfDay) || (current.startTime.TimeOfDay < sunriseTime.TimeOfDay))
126
                current.condition = WeatherConditions.Dark;
127

    
128
            // change prediction
129
            for (int i = 0; i < predictions.Count - 1; i++)
130
            {
131
                // TODO what about when days change -> detect end / start of day and do differently ?
132

    
133
                WeatherInfo w = predictions[i];
134
                WeatherInfo wNext = predictions[i + 1];
135

    
136
                int timespan = wNext.startTime.Hour - w.startTime.Hour;
137
                w.intervalLength = timespan;
138

    
139
                // if start under sunset
140
                if (w.startTime.TimeOfDay > sunsetTime.TimeOfDay)
141
                    w.condition = WeatherConditions.Dark;
142

    
143
                // if start under sunrise
144
                if (w.startTime.TimeOfDay < sunriseTime.TimeOfDay)
145
                {
146
                    double howMuch = ((sunriseTime.Hour * 60 + sunriseTime.Minute) - (w.startTime.Hour * 60 + w.startTime.Minute)) / 60.0;
147

    
148
                    if (howMuch >= timespan / 2.0)
149
                        w.condition = WeatherConditions.Dark;
150
                }
151

    
152
                // if start under sunrise
153
                TimeSpan endTime = new TimeSpan(w.startTime.TimeOfDay.Hours + timespan, w.startTime.TimeOfDay.Minutes, 0);
154
                if (endTime > sunsetTime.TimeOfDay)
155
                {
156
                    double howMuch = ((endTime.Hours * 60 + endTime.Minutes) - (sunsetTime.Hour * 60 + sunsetTime.Minute)) / 60.0;
157

    
158
                    if (howMuch >= timespan / 2.0)
159
                        w.condition = WeatherConditions.Dark;
160
                }
161
            }
162

    
163
            // last prediction
164
            WeatherInfo wLast = predictions[predictions.Count - 1];
165
            TimeSpan endTimeW = new TimeSpan(24, 0, 0);
166
            int timespanLast = endTimeW.Hours - wLast.startTime.Hour;
167
            wLast.intervalLength = timespanLast;
168

    
169
            // if start under sunset
170
            if (wLast.startTime.TimeOfDay > sunsetTime.TimeOfDay)
171
                wLast.condition = WeatherConditions.Dark;
172

    
173
            // if start under sunrise
174
            if (wLast.startTime.TimeOfDay < sunriseTime.TimeOfDay)
175
            {
176
                double howMuch = ((sunriseTime.Hour * 60 + sunriseTime.Minute) - (wLast.startTime.Hour * 60 + wLast.startTime.Minute)) / 60.0;
177

    
178
                if (howMuch >= timespanLast / 2.0)
179
                    wLast.condition = WeatherConditions.Dark;
180
            }
181

    
182
            // if start under sunrise
183
            if (endTimeW > sunsetTime.TimeOfDay)
184
            {
185
                double howMuch = ((endTimeW.Hours * 60 + endTimeW.Minutes) - (sunsetTime.Hour * 60 + sunsetTime.Minute)) / 60.0;
186

    
187
                if (howMuch >= timespanLast / 2.0)
188
                    wLast.condition = WeatherConditions.Dark;
189
            }
190
        }
191

    
192
        /// <summary>
193
        /// Parse weather prediction
194
        /// </summary>
195
        /// <param name="weather"> ArrayEnumerator of weather predictions </param>
196
        private void ParseWeatherPredict(ArrayEnumerator weather)
197
        {
198
            while (weather.MoveNext())
199
            {
200
                // prediction for one day
201
                var obj = weather.Current.EnumerateObject();
202

    
203
                while (obj.MoveNext())
204
                {
205
                    switch (obj.Current.Name)
206
                    {
207
                        case "date":
208
                            {
209
                                DateTime.TryParseExact(obj.Current.Value.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out currParsedDay);
210
                                break;
211
                            }
212
                        // hourly predictions
213
                        case "hourly":
214
                            {
215
                                ParseHourly(obj.Current.Value.EnumerateArray());
216
                                break;
217
                            }
218
                        // sunset / sunrise hours
219
                        case "astronomy":
220
                            {
221
                                ParseAstronomy(obj.Current.Value.EnumerateArray());
222
                                break;
223
                            }
224
                    }
225
                }
226
            }
227
        }
228

    
229
        /// <summary>
230
        /// Parse sunrise and sunset times
231
        /// </summary>
232
        /// <param name="astronomy"> Astronomy array enumerator </param>
233
        private void ParseAstronomy(ArrayEnumerator astronomy)
234
        {
235
            while (astronomy.MoveNext())
236
            {
237
                var astrInfo = astronomy.Current.EnumerateObject();
238
                
239
                while (astrInfo.MoveNext())
240
                {
241
                    switch (astrInfo.Current.Name)
242
                    {
243
                        case "sunrise":
244
                            {
245
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out sunriseTime);
246
                                Console.WriteLine("\t sunrise time : " + sunriseTime + " " + astrInfo.Current.Value.GetString());
247
                                break;
248
                            }
249
                        case "sunset":
250
                            {
251
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out sunsetTime);
252
                                Console.WriteLine("\t sunset time : " + sunsetTime + " " + astrInfo.Current.Value.GetString());
253
                                break;
254
                            }
255
                    }
256
                }
257
            }
258
        }
259

    
260
        /// <summary>
261
        /// Parse hourly predictions
262
        /// </summary>
263
        /// <param name="hourly">Enumerated array of hourly predictions</param>
264
        private void ParseHourly(ArrayEnumerator hourly)
265
        {
266
            while (hourly.MoveNext())
267
            {
268
                // one hourly prediction
269
                var oneH = hourly.Current.EnumerateObject();
270
                WeatherInfo weather = new WeatherInfo();
271

    
272
                while (oneH.MoveNext())
273
                {
274
                    switch (oneH.Current.Name)
275
                    {
276
                        case "FeelsLikeC":
277
                            {
278
                                Double.TryParse(oneH.Current.Value.GetString(), out weather.temp);
279
                                break;
280
                            }
281
                        case "cloudcover":
282
                            {
283
                                int cloudCover;
284
                                Int32.TryParse(oneH.Current.Value.GetString(), out cloudCover);
285
                                weather.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
286
                                break;
287
                            }
288
                        // take into account highest value from "chanceofrain" and "chaceofsnow"
289
                        case "chanceofrain":
290
                            {
291
                                int rain;
292
                                Int32.TryParse(oneH.Current.Value.GetString(), out rain);
293
                                weather.rain = rain > weather.rain ? rain : weather.rain;
294
                                break;
295
                            }
296
                        case "chanceofsnow":
297
                            {
298
                                int snow;
299
                                Int32.TryParse(oneH.Current.Value.GetString(), out snow);
300
                                weather.rain = snow > weather.rain ? snow : weather.rain;
301
                                break;
302
                            }
303
                        // wind kmph has to be translated to mps
304
                        case "WindGustKmph":
305
                            {
306
                                double windkmh;
307
                                Double.TryParse(oneH.Current.Value.GetString(), out windkmh);
308
                                weather.wind= windkmh * 1000 / (60.0*60.0);
309
                                break;
310
                            }
311
                        case "time":
312
                            {
313
                                int h;
314
                                Int32.TryParse(oneH.Current.Value.GetString(), out h);
315
                                h /= 100;
316
                                DateTime time = new DateTime(currParsedDay.Year, currParsedDay.Month, currParsedDay.Day, h, 0, 0);
317
                                weather.startTime = time;
318
                                break;
319
                            }
320
                    }
321
                }
322

    
323
                // Console.WriteLine(weather.ToString());
324
                predictions.Add(weather);
325

    
326
            }
327

    
328
        }
329

    
330
        /// <summary>
331
        /// Parse current weather
332
        /// </summary>
333
        /// <param name="currentWeather">Enumerated hour of weather data</param>
334
        /// <returns>WeatherInfo with current weather</returns>
335
        private WeatherInfo ParseCurrentWeather(ArrayEnumerator currentWeather)
336
        {
337
            WeatherInfo res = new WeatherInfo();
338
            //res.current = true;
339

    
340
            while (currentWeather.MoveNext())
341
            {
342
                var obj = currentWeather.Current.EnumerateObject();
343

    
344
                while (obj.MoveNext())
345
                {
346
                    switch (obj.Current.Name)
347
                    {
348
                        case "localObsDateTime":
349
                            {
350
                                DateTime.TryParse(obj.Current.Value.GetString(), out res.startTime);
351
                                break;
352
                            }
353
                        case "FeelsLikeC":
354
                            {
355
                                Double.TryParse(obj.Current.Value.GetString(), out res.temp);
356
                                break;
357
                            }
358
                        case "cloudcover":
359
                            {
360
                                int cloudCover;
361
                                Int32.TryParse(obj.Current.Value.GetString(), out cloudCover);
362
                                res.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
363
                                break;
364
                            }
365
                        case "precipMM":
366
                            {
367
                                double rainMM;
368
                                Double.TryParse(obj.Current.Value.GetString(), out rainMM);
369
                                res.rain = rainMM > 0 ? 100 : 0;
370
                                break;
371
                            }
372
                        case "windspeedKmph":
373
                            {
374
                                double wind;
375
                                Double.TryParse(obj.Current.Value.GetString(), out wind);
376
                                res.wind = wind * 1000 / (60.0 * 60.0);
377
                                break;
378
                            }
379
                    }
380
                }
381

    
382
            }
383

    
384
            return res;
385
        }
386

    
387
    }
388
}
(3-3/6)