Projekt

Obecné

Profil

Stáhnout (18.1 KB) Statistiky
| Větev: | Tag: | Revize:
1
//
2
// Author: A. Konig
3
//
4

    
5
using ServerApp.DataDownload;
6
using ServerApp.Parser.InputData;
7
using ServerApp.Parser.OutputInfo;
8
using System;
9
using System.Collections.Generic;
10
using System.Globalization;
11
using System.IO;
12
using System.Net;
13
using System.Text.Json;
14
using static System.Text.Json.JsonElement;
15

    
16
namespace ServerApp.WeatherPredictionParser
17
{
18
    /// <summary>
19
    /// Class representing a parser for json prediction data
20
    /// </summary>
21
    /// <author>A. Konig</author>
22
    public class JsonParser : IJsonParser
23
    {
24
        /// <summary> Data downloader </summary>
25
        DataDownloader downloader;
26
        /// <summary> Data loader </summary>
27
        IDataLoader loader;
28
        /// <summary> Currently parsed day </summary>
29
        DateTime currParsedDay;
30
        /// <summary> Sunrise time of currently parsed day </summary>
31
        List<DateTime> sunriseTime;
32
        /// <summary> Sunset time of currently parsed day </summary>
33
        List<DateTime> sunsetTime;
34

    
35
        /// <summary>
36
        /// Constructor
37
        /// </summary>
38
        /// <param name="downloader"></param>
39
        public JsonParser(DataDownloader downloader, IDataLoader loader)
40
        {
41
            this.downloader = downloader;
42
            this.loader = loader;
43
        }
44

    
45
        /// <summary>
46
        /// Get predictions from Predictions that are within specified time span
47
        /// From-to including
48
        /// If from == DateTime.Min then all until to
49
        /// If to  == DateTime.Max then all starting from from
50
        /// </summary>
51
        /// <param name="from">DateTime from</param>
52
        /// <param name="to">DateTime to</param>
53
        /// <returns>List of predictions that fit specified criteria or null if incorrect input</returns>
54
        public override List<WeatherInfo> GetPredictionForTime(DateTime from, DateTime to)
55
        {
56
            if (Predictions == null)
57
                return null;
58

    
59
            List<WeatherInfo> res = new List<WeatherInfo>();
60

    
61
            if (from == DateTime.MinValue)
62
                from = Predictions[0].startTime;
63

    
64
            if (to == DateTime.MaxValue) {
65
                DateTime dt = Predictions[Predictions.Count - 1].startTime;
66
                int hour = dt.Hour + Predictions[Predictions.Count - 1].intervalLength;
67
                bool addDay = false;
68
                if (hour >= 24)
69
                {
70
                    hour -= 24;
71
                    addDay = true;
72
                }
73
                to = new DateTime(dt.Year, dt.Month, dt.Day, hour, dt.Minute, dt.Second);
74
                if (addDay)
75
                    to = to.AddDays(1);
76
            }
77

    
78
            if (from > to)
79
                return null;
80

    
81
            // for all parsed weather info
82
            foreach (WeatherInfo pred in Predictions)
83
            {
84
                int hour = pred.startTime.Hour + pred.intervalLength;
85
                bool addDay = false;
86
                if (hour >= 24)
87
                {
88
                    hour -= 24;
89
                    addDay = true;
90
                }
91
                DateTime endTime = new DateTime(pred.startTime.Year, pred.startTime.Month, pred.startTime.Day, hour, pred.startTime.Minute, pred.startTime.Second);
92
                if (addDay)
93
                    endTime = endTime.AddDays(1);
94

    
95
                // if both end and start not outside of interval
96
                if (!((pred.startTime < from && endTime <= from) || (pred.startTime > to && endTime > to)))
97
                    res.Add(pred);
98
            }
99

    
100
            return res;
101
        }
102

    
103

    
104
        /// <summary>
105
        /// Parse weather prediction
106
        /// Results is in attributes current for current weather and pred for weather prediction for today, tommorrow and day after tommorrow
107
        /// </summary>
108
        override public void ParsePrediction()
109
        {
110
            sunriseTime = new List<DateTime>();
111
            sunsetTime = new List<DateTime>();
112

    
113
            // get file
114
            string file = downloader.DownloadWeatherPrediction();
115
            string data = loader.LoadPredictionFile(file);
116

    
117
            if (data == null)
118
                return;
119

    
120
            DateTime now = DateTime.Now;
121

    
122
            Current = new WeatherInfo();
123
            Predictions = new List<WeatherInfo>();
124

    
125
            // parse
126
            JsonDocument doc = JsonDocument.Parse(data);
127
            JsonElement root = doc.RootElement;
128
            var weatherP = root.EnumerateObject();
129

    
130
            while (weatherP.MoveNext())
131
            {
132
                string name = weatherP.Current.Name;
133
                Console.WriteLine(name);
134

    
135
                switch (name)
136
                {
137
                    // current weather
138
                    case "current_condition":
139
                        {
140
                            ArrayEnumerator currentWeather = weatherP.Current.Value.EnumerateArray();
141
                            Current = ParseCurrentWeather(currentWeather);
142

    
143
                            break;
144
                        }
145
                    // weather prediction
146
                    case "weather":
147
                        {
148
                            ArrayEnumerator weather = weatherP.Current.Value.EnumerateArray();
149
                            ParseWeatherPredict(weather);
150

    
151
                            break;
152
                        }
153
                }
154
            }
155

    
156
            // sunrise + sunset into data
157
            EncompassSunRiseSetTimes();
158

    
159
            //TestConsoleOutput();
160
        }
161

    
162
        /// <summary>
163
        /// Test console output
164
        /// </summary>
165
        private void TestConsoleOutput()
166
        {
167
            Console.WriteLine(Current);
168
            foreach (WeatherInfo w in Predictions)
169
                Console.WriteLine(w);
170
        }
171

    
172
        /// <summary>
173
        /// Change data in a way that they now reflect sunrise and sunset times
174
        /// If current time under sunrise or over sunset -> WeatherConditions is Dark
175
        /// If prediction time is under sunrise or over sunset and more than half of the interval is under/over said time -> WeatherCondition is Dark
176
        /// </summary>
177
        private void EncompassSunRiseSetTimes()
178
        {
179
            if (sunsetTime.Count < 1 || sunriseTime.Count < 0)
180
                return;
181

    
182
            // change current weather
183
            if ((Current.startTime.TimeOfDay > sunsetTime[0].TimeOfDay) || (Current.startTime.TimeOfDay < sunriseTime[0].TimeOfDay))
184
                Current.condition = WeatherConditions.Dark;
185

    
186
            // change prediction
187
            int index = 0;
188
            for (int i = 0; i < Predictions.Count - 1; i++)
189
            {
190
                WeatherInfo w = Predictions[i];
191
                WeatherInfo wNext = Predictions[i + 1];
192

    
193
                // if wNext time < than w time then it is prediction from the next day -> add 24 to correctly calculate timespan
194
                int timespan = wNext.startTime.Hour - w.startTime.Hour;
195
                if (wNext.startTime.Hour < w.startTime.Hour)
196
                {
197
                    timespan = (wNext.startTime.Hour + 24) - w.startTime.Hour;
198
                }
199
                
200
                w.intervalLength = timespan;
201

    
202
                // if start under sunset
203
                if (w.startTime.TimeOfDay > sunsetTime[index].TimeOfDay)
204
                    w.condition = WeatherConditions.Dark;
205

    
206
                // if start under sunrise
207
                if (w.startTime.TimeOfDay < sunriseTime[index].TimeOfDay)
208
                {
209
                    double howMuch = ((sunriseTime[index].Hour * 60 + sunriseTime[index].Minute) - (w.startTime.Hour * 60 + w.startTime.Minute)) / 60.0;
210

    
211
                    if (howMuch >= timespan / 2.0)
212
                        w.condition = WeatherConditions.Dark;
213
                }
214

    
215
                // if start under sunrise
216
                TimeSpan endTime = new TimeSpan(w.startTime.TimeOfDay.Hours + timespan, w.startTime.TimeOfDay.Minutes, 0);
217
                if (endTime > sunsetTime[index].TimeOfDay)
218
                {
219
                    double howMuch = ((endTime.Hours * 60 + endTime.Minutes) - (sunsetTime[index].Hour * 60 + sunsetTime[index].Minute)) / 60.0;
220

    
221
                    if (howMuch >= timespan / 2.0)
222
                        w.condition = WeatherConditions.Dark;
223
                }
224

    
225
                if (Predictions[i].startTime.Date !=  Predictions[i + 1].startTime.Date)
226
                    index++;
227
            }
228

    
229
            // last prediction
230
            WeatherInfo wLast = Predictions[Predictions.Count - 1];
231
            TimeSpan endTimeW = new TimeSpan(24, 0, 0);
232
            int timespanLast = 24 - wLast.startTime.Hour;
233
            wLast.intervalLength = timespanLast;
234

    
235
            // if start under sunset
236
            if (wLast.startTime.TimeOfDay > sunsetTime[sunsetTime.Count-1].TimeOfDay)
237
                wLast.condition = WeatherConditions.Dark;
238

    
239
            // if start under sunrise
240
            if (wLast.startTime.TimeOfDay < sunriseTime[sunriseTime.Count - 1].TimeOfDay)
241
            {
242
                double howMuch = ((sunriseTime[sunriseTime.Count - 1].Hour * 60 + sunriseTime[sunriseTime.Count - 1].Minute) - (wLast.startTime.Hour * 60 + wLast.startTime.Minute)) / 60.0;
243

    
244
                if (howMuch >= timespanLast / 2.0)
245
                    wLast.condition = WeatherConditions.Dark;
246
            }
247

    
248
            // if start under sunrise
249
            if (endTimeW > sunsetTime[sunsetTime.Count - 1].TimeOfDay)
250
            {
251
                double howMuch = ((endTimeW.Hours * 60 + endTimeW.Minutes) - (sunsetTime[sunsetTime.Count - 1].Hour * 60 + sunsetTime[sunsetTime.Count - 1].Minute)) / 60.0;
252

    
253
                if (howMuch >= timespanLast / 2.0)
254
                    wLast.condition = WeatherConditions.Dark;
255
            }
256
        }
257

    
258
        /// <summary>
259
        /// Parse weather prediction
260
        /// </summary>
261
        /// <param name="weather"> ArrayEnumerator of weather predictions </param>
262
        private void ParseWeatherPredict(ArrayEnumerator weather)
263
        {
264
            while (weather.MoveNext())
265
            {
266
                // prediction for one day
267
                var obj = weather.Current.EnumerateObject();
268

    
269
                while (obj.MoveNext())
270
                {
271
                    switch (obj.Current.Name)
272
                    {
273
                        case "date":
274
                            {
275
                                DateTime.TryParseExact(obj.Current.Value.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out currParsedDay);
276
                                break;
277
                            }
278
                        // hourly predictions
279
                        case "hourly":
280
                            {
281
                                ParseHourly(obj.Current.Value.EnumerateArray());
282
                                break;
283
                            }
284
                        // sunset / sunrise hours
285
                        case "astronomy":
286
                            {
287
                                ParseAstronomy(obj.Current.Value.EnumerateArray());
288
                                break;
289
                            }
290
                    }
291
                }
292
            }
293
        }
294

    
295
        /// <summary>
296
        /// Parse sunrise and sunset times
297
        /// </summary>
298
        /// <param name="astronomy"> Astronomy array enumerator </param>
299
        private void ParseAstronomy(ArrayEnumerator astronomy)
300
        {
301
            while (astronomy.MoveNext())
302
            {
303
                var astrInfo = astronomy.Current.EnumerateObject();
304
                
305
                while (astrInfo.MoveNext())
306
                {
307
                    switch (astrInfo.Current.Name)
308
                    {
309
                        case "sunrise":
310
                            {
311
                                DateTime newSunrise = new DateTime();
312
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out newSunrise);
313
                                sunriseTime.Add(newSunrise);
314
                                //Console.WriteLine("\t sunrise time : " + sunriseTime + " " + astrInfo.Current.Value.GetString());
315
                                break;
316
                            }
317
                        case "sunset":
318
                            {
319
                                DateTime newSunset = new DateTime();
320
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out newSunset);
321
                                sunsetTime.Add(newSunset);
322
                                //Console.WriteLine("\t sunset time : " + sunsetTime + " " + astrInfo.Current.Value.GetString());
323
                                break;
324
                            }
325
                    }
326
                }
327
            }
328
        }
329

    
330
        /// <summary>
331
        /// Parse hourly predictions
332
        /// </summary>
333
        /// <param name="hourly">Enumerated array of hourly predictions</param>
334
        private void ParseHourly(ArrayEnumerator hourly)
335
        {
336
            while (hourly.MoveNext())
337
            {
338
                // one hourly prediction
339
                var oneH = hourly.Current.EnumerateObject();
340
                WeatherInfo weather = new WeatherInfo();
341

    
342
                while (oneH.MoveNext())
343
                {
344
                    switch (oneH.Current.Name)
345
                    {
346
                        case "FeelsLikeC":
347
                            {
348
                                Double.TryParse(oneH.Current.Value.GetString(), out weather.temp);
349
                                break;
350
                            }
351
                        case "cloudcover":
352
                            {
353
                                int cloudCover;
354
                                Int32.TryParse(oneH.Current.Value.GetString(), out cloudCover);
355
                                weather.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
356
                                weather.lum = ValueToConditions.TransferConditionsToLux(weather.condition);
357
                                break;
358
                            }
359
                        // take into account highest value from "chanceofrain" and "chaceofsnow"
360
                        case "chanceofrain":
361
                            {
362
                                int rain;
363
                                Int32.TryParse(oneH.Current.Value.GetString(), out rain);
364
                                weather.rain = rain > weather.rain ? rain : weather.rain;
365
                                break;
366
                            }
367
                        case "chanceofsnow":
368
                            {
369
                                int snow;
370
                                Int32.TryParse(oneH.Current.Value.GetString(), out snow);
371
                                weather.rain = snow > weather.rain ? snow : weather.rain;
372
                                break;
373
                            }
374
                        // wind kmph has to be translated to mps
375
                        case "windspeedKmph":
376
                            {
377
                                double windkmh;
378
                                Double.TryParse(oneH.Current.Value.GetString(), out windkmh);
379
                                weather.wind= windkmh * 1000 / (60.0*60.0);
380
                                break;
381
                            }
382
                        case "time":
383
                            {
384
                                int h;
385
                                Int32.TryParse(oneH.Current.Value.GetString(), out h);
386
                                h /= 100;
387
                                DateTime time = new DateTime(currParsedDay.Year, currParsedDay.Month, currParsedDay.Day, h, 0, 0);
388
                                weather.startTime = time;
389
                                break;
390
                            }
391
                    }
392
                }
393

    
394
                // Console.WriteLine(weather.ToString());
395
                Predictions.Add(weather);
396
            }
397

    
398
        }
399

    
400
        /// <summary>
401
        /// Parse current weather
402
        /// </summary>
403
        /// <param name="currentWeather">Enumerated hour of weather data</param>
404
        /// <returns>WeatherInfo with current weather</returns>
405
        private WeatherInfo ParseCurrentWeather(ArrayEnumerator currentWeather)
406
        {
407
            WeatherInfo res = new WeatherInfo();
408
            res.intervalLength = 0;
409
            //res.current = true;
410

    
411
            while (currentWeather.MoveNext())
412
            {
413
                var obj = currentWeather.Current.EnumerateObject();
414

    
415
                while (obj.MoveNext())
416
                {
417
                    switch (obj.Current.Name)
418
                    {
419
                        case "localObsDateTime":
420
                            {
421
                                DateTime.TryParse(obj.Current.Value.GetString(), out res.startTime);
422
                                break;
423
                            }
424
                        case "FeelsLikeC":
425
                            {
426
                                Double.TryParse(obj.Current.Value.GetString(), out res.temp);
427
                                break;
428
                            }
429
                        case "cloudcover":
430
                            {
431
                                int cloudCover;
432
                                Int32.TryParse(obj.Current.Value.GetString(), out cloudCover);
433
                                res.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
434
                                break;
435
                            }
436
                        case "precipMM":
437
                            {
438
                                double rainMM;
439
                                Double.TryParse(obj.Current.Value.GetString(), out rainMM);
440
                                res.rain = rainMM > 0 ? 100 : 0;
441
                                break;
442
                            }
443
                        case "windspeedKmph":
444
                            {
445
                                double wind;
446
                                Double.TryParse(obj.Current.Value.GetString(), out wind);
447
                                res.wind = wind * 1000 / (60.0 * 60.0);
448
                                break;
449
                            }
450
                    }
451
                }
452

    
453
            }
454

    
455
            res.lum = ValueToConditions.TransferConditionsToLux(res.condition);
456
            return res;
457
        }
458

    
459
      
460
    }
461
}
(2-2/2)