Projekt

Obecné

Profil

Stáhnout (19.8 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
        IDataDownloader 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(IDataDownloader 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
            // get data
118
            string data = downloader.DownloadWeatherPrediction();
119

    
120
            DateTime now = DateTime.Now;
121

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

    
125
            if (data == null || data.Length == 0)
126
                return;
127

    
128
            // parse
129
            try
130
            {
131
                JsonDocument doc = JsonDocument.Parse(data);
132
                JsonElement root = doc.RootElement;
133
                var weatherP = root.EnumerateObject();
134

    
135
                while (weatherP.MoveNext())
136
                {
137
                    string name = weatherP.Current.Name;
138
                    Console.WriteLine(name);
139

    
140
                    switch (name)
141
                    {
142
                        // current weather
143
                        case "current_condition":
144
                            {
145
                                ArrayEnumerator currentWeather = weatherP.Current.Value.EnumerateArray();
146
                                Current = ParseCurrentWeather(currentWeather);
147

    
148
                                break;
149
                            }
150
                        // weather prediction
151
                        case "weather":
152
                            {
153
                                ArrayEnumerator weather = weatherP.Current.Value.EnumerateArray();
154
                                ParseWeatherPredict(weather);
155

    
156
                                break;
157
                            }
158
                    }
159
                }
160

    
161
                // sunrise + sunset into data
162
                EncompassSunRiseSetTimes();
163
            } catch
164
            {
165
                Console.WriteLine("Weather prediction file in incorrect format");
166
                Current = new WeatherInfo();
167
                Predictions = new List<WeatherInfo>();
168
            }
169

    
170
            //TestConsoleOutput();
171
        }
172

    
173
        /// <summary>
174
        /// Test console output
175
        /// </summary>
176
        private void TestConsoleOutput()
177
        {
178
            Console.WriteLine(Current);
179
            foreach (WeatherInfo w in Predictions)
180
                Console.WriteLine(w);
181
        }
182

    
183
        /// <summary>
184
        /// Change data in a way that they now reflect sunrise and sunset times
185
        /// If current time under sunrise or over sunset -> WeatherConditions is Dark
186
        /// If prediction time is under sunrise or over sunset and more than half of the interval is under/over said time -> WeatherCondition is Dark
187
        /// </summary>
188
        private void EncompassSunRiseSetTimes()
189
        {
190
            if (sunsetTime.Count < 1 || sunriseTime.Count < 0)
191
                return;
192

    
193
            // change current weather
194
            if ((Current.startTime.TimeOfDay > sunsetTime[0].TimeOfDay) || (Current.startTime.TimeOfDay < sunriseTime[0].TimeOfDay))
195
                Current.condition = WeatherConditions.Dark;
196

    
197
            // change prediction
198
            int index = 0;
199
            for (int i = 0; i < Predictions.Count - 1; i++)
200
            {
201
                WeatherInfo w = Predictions[i];
202
                WeatherInfo wNext = Predictions[i + 1];
203
                DateTime sunrise = sunriseTime[index];
204
                DateTime sunset = sunsetTime[index];
205

    
206

    
207
                // if wNext time < than w time then it is prediction from the next day -> add 24 to correctly calculate timespan
208
                int timespan = wNext.startTime.Hour - w.startTime.Hour;
209
                bool intoTwo = false;
210
                if (wNext.startTime.Hour < w.startTime.Hour)
211
                {
212
                    intoTwo = true;
213
                    timespan = (wNext.startTime.Hour + 24) - w.startTime.Hour;
214
                }
215
                
216
                w.intervalLength = timespan;
217
                TimeSpan endTime = new TimeSpan(w.startTime.TimeOfDay.Hours + timespan, w.startTime.TimeOfDay.Minutes, 0);
218

    
219
                // if start under sunset
220
                if (w.startTime.TimeOfDay > sunsetTime[index].TimeOfDay)
221
                {
222
                    // when is end - if end after next sunrise need to compute the extent of dark
223
                    if (intoTwo && endTime > sunriseTime[index+1].TimeOfDay)
224
                    {
225
                        double howMuch = ((endTime.Hours * 60 + endTime.Minutes) - (sunriseTime[index + 1].Hour * 60 + sunriseTime[index + 1].Minute)) / 60.0;
226
                        howMuch = w.intervalLength - howMuch;
227

    
228
                        if (howMuch >= timespan / 2.0)
229
                            w.condition = WeatherConditions.Dark;
230
                    }
231
                    else
232
                        w.condition = WeatherConditions.Dark;
233
                }
234

    
235
                // if start under sunrise
236
                if (w.startTime.TimeOfDay < sunriseTime[index].TimeOfDay)
237
                {
238
                    double howMuch = ((sunriseTime[index].Hour * 60 + sunriseTime[index].Minute) - (w.startTime.Hour * 60 + w.startTime.Minute)) / 60.0;
239
                    if (endTime > sunset.TimeOfDay)
240
                        howMuch += ((w.startTime.Hour * 60 + w.startTime.Minute) - (sunset.Hour * 60 + sunset.Minute)) / 60.0;
241

    
242
                    if (howMuch >= timespan / 2.0)
243
                        w.condition = WeatherConditions.Dark;
244
                }
245

    
246
                // if end over sunset
247
                else if (endTime > sunsetTime[index].TimeOfDay)
248
                {
249
                    double howMuch = ((endTime.Hours * 60 + endTime.Minutes) - (sunsetTime[index].Hour * 60 + sunsetTime[index].Minute)) / 60.0;
250

    
251
                    if (howMuch >= timespan / 2.0)
252
                        w.condition = WeatherConditions.Dark;
253
                }
254

    
255
                if (Predictions[i].startTime.Date !=  Predictions[i + 1].startTime.Date)
256
                    index++;
257
            }
258

    
259
            // last prediction
260
            WeatherInfo wLast = Predictions[Predictions.Count - 1];
261
            TimeSpan endTimeW = new TimeSpan(23, 59, 59);
262
            int timespanLast = 24 - wLast.startTime.Hour;
263
            wLast.intervalLength = timespanLast;
264

    
265
            // if start under sunset
266
            if (wLast.startTime.TimeOfDay > sunsetTime[sunsetTime.Count-1].TimeOfDay)
267
                wLast.condition = WeatherConditions.Dark;
268

    
269
            // if start under sunrise
270
            if (wLast.startTime.TimeOfDay < sunriseTime[sunriseTime.Count - 1].TimeOfDay)
271
            {
272
                double howMuch = ((sunriseTime[sunriseTime.Count - 1].Hour * 60 + sunriseTime[sunriseTime.Count - 1].Minute) - (wLast.startTime.Hour * 60 + wLast.startTime.Minute)) / 60.0;
273
                if (endTimeW > sunsetTime[sunriseTime.Count - 1].TimeOfDay)
274
                    howMuch += ((wLast.startTime.Hour * 60 + wLast.startTime.Minute) - (sunsetTime[sunriseTime.Count - 1].Hour * 60 + sunsetTime[sunriseTime.Count - 1].Minute)) / 60.0;
275

    
276
                if (howMuch >= timespanLast / 2.0)
277
                    wLast.condition = WeatherConditions.Dark;
278
            }
279

    
280
            // if start under sunrise
281
            if (endTimeW > sunsetTime[sunsetTime.Count - 1].TimeOfDay)
282
            {
283
                double howMuch = ((endTimeW.Hours * 60 + endTimeW.Minutes) - (sunsetTime[sunsetTime.Count - 1].Hour * 60 + sunsetTime[sunsetTime.Count - 1].Minute)) / 60.0;
284

    
285
                if (howMuch >= timespanLast / 2.0)
286
                    wLast.condition = WeatherConditions.Dark;
287
            }
288
        }
289

    
290
        /// <summary>
291
        /// Parse weather prediction
292
        /// </summary>
293
        /// <param name="weather"> ArrayEnumerator of weather predictions </param>
294
        private void ParseWeatherPredict(ArrayEnumerator weather)
295
        {
296
            while (weather.MoveNext())
297
            {
298
                // prediction for one day
299
                var obj = weather.Current.EnumerateObject();
300

    
301
                while (obj.MoveNext())
302
                {
303
                    switch (obj.Current.Name)
304
                    {
305
                        case "date":
306
                            {
307
                                DateTime.TryParseExact(obj.Current.Value.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out currParsedDay);
308
                                break;
309
                            }
310
                        // hourly predictions
311
                        case "hourly":
312
                            {
313
                                ParseHourly(obj.Current.Value.EnumerateArray());
314
                                break;
315
                            }
316
                        // sunset / sunrise hours
317
                        case "astronomy":
318
                            {
319
                                ParseAstronomy(obj.Current.Value.EnumerateArray());
320
                                break;
321
                            }
322
                    }
323
                }
324
            }
325
        }
326

    
327
        /// <summary>
328
        /// Parse sunrise and sunset times
329
        /// </summary>
330
        /// <param name="astronomy"> Astronomy array enumerator </param>
331
        private void ParseAstronomy(ArrayEnumerator astronomy)
332
        {
333
            while (astronomy.MoveNext())
334
            {
335
                var astrInfo = astronomy.Current.EnumerateObject();
336
                
337
                while (astrInfo.MoveNext())
338
                {
339
                    switch (astrInfo.Current.Name)
340
                    {
341
                        case "sunrise":
342
                            {
343
                                DateTime newSunrise = new DateTime();
344
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out newSunrise);
345
                                sunriseTime.Add(newSunrise);
346
                                //Console.WriteLine("\t sunrise time : " + sunriseTime + " " + astrInfo.Current.Value.GetString());
347
                                break;
348
                            }
349
                        case "sunset":
350
                            {
351
                                DateTime newSunset = new DateTime();
352
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out newSunset);
353
                                sunsetTime.Add(newSunset);
354
                                //Console.WriteLine("\t sunset time : " + sunsetTime + " " + astrInfo.Current.Value.GetString());
355
                                break;
356
                            }
357
                    }
358
                }
359
            }
360
        }
361

    
362
        /// <summary>
363
        /// Parse hourly predictions
364
        /// </summary>
365
        /// <param name="hourly">Enumerated array of hourly predictions</param>
366
        private void ParseHourly(ArrayEnumerator hourly)
367
        {
368
            while (hourly.MoveNext())
369
            {
370
                // one hourly prediction
371
                var oneH = hourly.Current.EnumerateObject();
372
                WeatherInfo weather = new WeatherInfo();
373

    
374
                while (oneH.MoveNext())
375
                {
376
                    switch (oneH.Current.Name)
377
                    {
378
                        case "FeelsLikeC":
379
                            {
380
                                Double.TryParse(oneH.Current.Value.GetString(), out weather.temp);
381
                                break;
382
                            }
383
                        case "cloudcover":
384
                            {
385
                                int cloudCover;
386
                                Int32.TryParse(oneH.Current.Value.GetString(), out cloudCover);
387
                                weather.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
388
                                weather.lum = ValueToConditions.TransferConditionsToLux(weather.condition);
389
                                break;
390
                            }
391
                        // take into account highest value from "chanceofrain" and "chaceofsnow"
392
                        case "chanceofrain":
393
                            {
394
                                int rain;
395
                                Int32.TryParse(oneH.Current.Value.GetString(), out rain);
396
                                weather.rain = rain > weather.rain ? rain : weather.rain;
397
                                break;
398
                            }
399
                        case "chanceofsnow":
400
                            {
401
                                int snow;
402
                                Int32.TryParse(oneH.Current.Value.GetString(), out snow);
403
                                weather.rain = snow > weather.rain ? snow : weather.rain;
404
                                break;
405
                            }
406
                        // wind kmph has to be translated to mps
407
                        case "windspeedKmph":
408
                            {
409
                                double windkmh;
410
                                Double.TryParse(oneH.Current.Value.GetString(), out windkmh);
411
                                weather.wind= windkmh * 1000 / (60.0*60.0);
412
                                break;
413
                            }
414
                        case "time":
415
                            {
416
                                int h;
417
                                Int32.TryParse(oneH.Current.Value.GetString(), out h);
418
                                h /= 100;
419
                                DateTime time = new DateTime(currParsedDay.Year, currParsedDay.Month, currParsedDay.Day, h, 0, 0);
420
                                weather.startTime = time;
421
                                break;
422
                            }
423
                    }
424
                }
425

    
426
                // Console.WriteLine(weather.ToString());
427
                Predictions.Add(weather);
428
            }
429

    
430
        }
431

    
432
        /// <summary>
433
        /// Parse current weather
434
        /// </summary>
435
        /// <param name="currentWeather">Enumerated hour of weather data</param>
436
        /// <returns>WeatherInfo with current weather</returns>
437
        private WeatherInfo ParseCurrentWeather(ArrayEnumerator currentWeather)
438
        {
439
            WeatherInfo res = new WeatherInfo();
440
            res.intervalLength = 0;
441
            //res.current = true;
442

    
443
            while (currentWeather.MoveNext())
444
            {
445
                var obj = currentWeather.Current.EnumerateObject();
446

    
447
                while (obj.MoveNext())
448
                {
449
                    switch (obj.Current.Name)
450
                    {
451
                        case "localObsDateTime":
452
                            {
453
                                DateTime.TryParse(obj.Current.Value.GetString(), out res.startTime);
454
                                break;
455
                            }
456
                        case "FeelsLikeC":
457
                            {
458
                                Double.TryParse(obj.Current.Value.GetString(), out res.temp);
459
                                break;
460
                            }
461
                        case "cloudcover":
462
                            {
463
                                int cloudCover;
464
                                Int32.TryParse(obj.Current.Value.GetString(), out cloudCover);
465
                                res.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
466
                                break;
467
                            }
468
                        case "precipMM":
469
                            {
470
                                double rainMM;
471
                                Double.TryParse(obj.Current.Value.GetString(), out rainMM);
472
                                res.rain = rainMM > 0 ? 100 : 0;
473
                                break;
474
                            }
475
                        case "windspeedKmph":
476
                            {
477
                                double wind;
478
                                Double.TryParse(obj.Current.Value.GetString(), out wind);
479
                                res.wind = wind * 1000 / (60.0 * 60.0);
480
                                break;
481
                            }
482
                    }
483
                }
484

    
485
            }
486

    
487
            res.lum = ValueToConditions.TransferConditionsToLux(res.condition);
488
            return res;
489
        }
490

    
491
      
492
    }
493
}
(2-2/2)