Projekt

Obecné

Profil

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

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

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

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

    
56
            List<WeatherInfo> res = new List<WeatherInfo>();
57

    
58
            if (from == null)
59
                from = Predictions[0].startTime;
60

    
61
            if (to == null)
62
                from = Predictions[Predictions.Count].startTime;
63

    
64
            if (from > to)
65
                return null;
66

    
67
            foreach (WeatherInfo pred in Predictions)
68
            {
69
                int hour = pred.startTime.Hour + pred.intervalLength;
70
                Console.WriteLine(pred.intervalLength);
71
                bool addDay = false;
72
                if (hour >= 24)
73
                {
74
                    hour -= 24;
75
                    addDay = true;
76
                }
77
                DateTime endTime = new DateTime(pred.startTime.Year, pred.startTime.Month, pred.startTime.Day, hour, pred.startTime.Minute, pred.startTime.Second);
78
                if (addDay)
79
                    endTime = endTime.AddDays(1);
80

    
81
                // if both end and start not outside of interval
82
                if (!((pred.startTime < from && endTime <= from) || (pred.startTime > to && endTime >= to)))
83
                    res.Add(pred);
84
            }
85

    
86
            return res;
87
        }
88

    
89
        /// <summary>
90
        /// Parse weather prediction
91
        /// Results is in attributes current for current weather and pred for weather prediction for today, tommorrow and day after tommorrow
92
        /// </summary>
93
        override public void ParsePrediction()
94
        {
95
            // TODO ask DataDownloader for download said file and return path to it
96
            
97
            // get file
98
            string file = DownloadWeatherPrediction();
99
            DateTime now = DateTime.Now;
100
            Console.WriteLine(File.Exists(file));
101

    
102
            Current = new WeatherInfo();
103
            Predictions = new List<WeatherInfo>();
104

    
105
            if (!File.Exists(file))
106
                return;
107

    
108
            // read file
109
            string data = File.ReadAllText(file);
110

    
111
            // parse
112
            JsonDocument doc = JsonDocument.Parse(data);
113
            JsonElement root = doc.RootElement;
114
            var weatherP = root.EnumerateObject();
115

    
116
            while (weatherP.MoveNext())
117
            {
118
                string name = weatherP.Current.Name;
119
                Console.WriteLine(name);
120

    
121
                switch (name)
122
                {
123
                    // current weather
124
                    case "current_condition":
125
                        {
126
                            ArrayEnumerator currentWeather = weatherP.Current.Value.EnumerateArray();
127
                            Current = ParseCurrentWeather(currentWeather);
128

    
129
                            break;
130
                        }
131
                    // weather prediction
132
                    case "weather":
133
                        {
134
                            ArrayEnumerator weather = weatherP.Current.Value.EnumerateArray();
135
                            ParseWeatherPredict(weather);
136

    
137
                            break;
138
                        }
139
                }
140
            }
141

    
142
            // sunrise + sunset into data
143
            EncompassSunRiseSetTimes();
144

    
145
            //TestConsoleOutput();
146
        }
147

    
148
        /// <summary>
149
        /// Test console output
150
        /// </summary>
151
        private void TestConsoleOutput()
152
        {
153
            Console.WriteLine(Current);
154
            foreach (WeatherInfo w in Predictions)
155
                Console.WriteLine(w);
156
        }
157

    
158
        // TODO move to data loader
159
        /// <summary>
160
        /// Downloads json file
161
        /// </summary>
162
        /// <returns> Path to file </returns>
163
        private string DownloadWeatherPrediction()
164
        {
165
            DateTime now = DateTime.Now;
166
            WebClient webClient = new WebClient();
167
            webClient.DownloadFile("http://wttr.in/Plzen,czechia?format=j1", $"data/{now.Year}{now.Month}{now.Day}.json");
168

    
169
            return $"data/{now.Year}{now.Month}{now.Day}.json";
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
            // change current weather
180
            if ((Current.startTime.TimeOfDay > sunsetTime.TimeOfDay) || (Current.startTime.TimeOfDay < sunriseTime.TimeOfDay))
181
                Current.condition = WeatherConditions.Dark;
182

    
183
            // change prediction
184
            for (int i = 0; i < Predictions.Count - 1; i++)
185
            {
186
                WeatherInfo w = Predictions[i];
187
                WeatherInfo wNext = Predictions[i + 1];
188

    
189
                // if wNext time < than w time then it is prediction from the next day -> add 24 to correctly calculate timespan
190
                int timespan = wNext.startTime.Hour - w.startTime.Hour;
191
                if (wNext.startTime.Hour < w.startTime.Hour)
192
                    timespan = (wNext.startTime.Hour+24) - w.startTime.Hour;
193
                
194
                w.intervalLength = timespan;
195

    
196
                // if start under sunset
197
                if (w.startTime.TimeOfDay > sunsetTime.TimeOfDay)
198
                    w.condition = WeatherConditions.Dark;
199

    
200
                // if start under sunrise
201
                if (w.startTime.TimeOfDay < sunriseTime.TimeOfDay)
202
                {
203
                    double howMuch = ((sunriseTime.Hour * 60 + sunriseTime.Minute) - (w.startTime.Hour * 60 + w.startTime.Minute)) / 60.0;
204

    
205
                    if (howMuch >= timespan / 2.0)
206
                        w.condition = WeatherConditions.Dark;
207
                }
208

    
209
                // if start under sunrise
210
                TimeSpan endTime = new TimeSpan(w.startTime.TimeOfDay.Hours + timespan, w.startTime.TimeOfDay.Minutes, 0);
211
                if (endTime > sunsetTime.TimeOfDay)
212
                {
213
                    double howMuch = ((endTime.Hours * 60 + endTime.Minutes) - (sunsetTime.Hour * 60 + sunsetTime.Minute)) / 60.0;
214

    
215
                    if (howMuch >= timespan / 2.0)
216
                        w.condition = WeatherConditions.Dark;
217
                }
218
            }
219

    
220
            // last prediction
221
            WeatherInfo wLast = Predictions[Predictions.Count - 1];
222
            TimeSpan endTimeW = new TimeSpan(24, 0, 0);
223
            int timespanLast = 24 - wLast.startTime.Hour;
224
            wLast.intervalLength = timespanLast;
225

    
226
            // if start under sunset
227
            if (wLast.startTime.TimeOfDay > sunsetTime.TimeOfDay)
228
                wLast.condition = WeatherConditions.Dark;
229

    
230
            // if start under sunrise
231
            if (wLast.startTime.TimeOfDay < sunriseTime.TimeOfDay)
232
            {
233
                double howMuch = ((sunriseTime.Hour * 60 + sunriseTime.Minute) - (wLast.startTime.Hour * 60 + wLast.startTime.Minute)) / 60.0;
234

    
235
                if (howMuch >= timespanLast / 2.0)
236
                    wLast.condition = WeatherConditions.Dark;
237
            }
238

    
239
            // if start under sunrise
240
            if (endTimeW > sunsetTime.TimeOfDay)
241
            {
242
                double howMuch = ((endTimeW.Hours * 60 + endTimeW.Minutes) - (sunsetTime.Hour * 60 + sunsetTime.Minute)) / 60.0;
243

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

    
249
        /// <summary>
250
        /// Parse weather prediction
251
        /// </summary>
252
        /// <param name="weather"> ArrayEnumerator of weather predictions </param>
253
        private void ParseWeatherPredict(ArrayEnumerator weather)
254
        {
255
            while (weather.MoveNext())
256
            {
257
                // prediction for one day
258
                var obj = weather.Current.EnumerateObject();
259

    
260
                while (obj.MoveNext())
261
                {
262
                    switch (obj.Current.Name)
263
                    {
264
                        case "date":
265
                            {
266
                                DateTime.TryParseExact(obj.Current.Value.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out currParsedDay);
267
                                break;
268
                            }
269
                        // hourly predictions
270
                        case "hourly":
271
                            {
272
                                ParseHourly(obj.Current.Value.EnumerateArray());
273
                                break;
274
                            }
275
                        // sunset / sunrise hours
276
                        case "astronomy":
277
                            {
278
                                ParseAstronomy(obj.Current.Value.EnumerateArray());
279
                                break;
280
                            }
281
                    }
282
                }
283
            }
284
        }
285

    
286
        /// <summary>
287
        /// Parse sunrise and sunset times
288
        /// </summary>
289
        /// <param name="astronomy"> Astronomy array enumerator </param>
290
        private void ParseAstronomy(ArrayEnumerator astronomy)
291
        {
292
            while (astronomy.MoveNext())
293
            {
294
                var astrInfo = astronomy.Current.EnumerateObject();
295
                
296
                while (astrInfo.MoveNext())
297
                {
298
                    switch (astrInfo.Current.Name)
299
                    {
300
                        case "sunrise":
301
                            {
302
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out sunriseTime);
303
                                Console.WriteLine("\t sunrise time : " + sunriseTime + " " + astrInfo.Current.Value.GetString());
304
                                break;
305
                            }
306
                        case "sunset":
307
                            {
308
                                DateTime.TryParseExact(astrInfo.Current.Value.GetString(), "hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out sunsetTime);
309
                                Console.WriteLine("\t sunset time : " + sunsetTime + " " + astrInfo.Current.Value.GetString());
310
                                break;
311
                            }
312
                    }
313
                }
314
            }
315
        }
316

    
317
        /// <summary>
318
        /// Parse hourly predictions
319
        /// </summary>
320
        /// <param name="hourly">Enumerated array of hourly predictions</param>
321
        private void ParseHourly(ArrayEnumerator hourly)
322
        {
323
            while (hourly.MoveNext())
324
            {
325
                // one hourly prediction
326
                var oneH = hourly.Current.EnumerateObject();
327
                WeatherInfo weather = new WeatherInfo();
328

    
329
                while (oneH.MoveNext())
330
                {
331
                    switch (oneH.Current.Name)
332
                    {
333
                        case "FeelsLikeC":
334
                            {
335
                                Double.TryParse(oneH.Current.Value.GetString(), out weather.temp);
336
                                break;
337
                            }
338
                        case "cloudcover":
339
                            {
340
                                int cloudCover;
341
                                Int32.TryParse(oneH.Current.Value.GetString(), out cloudCover);
342
                                weather.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
343
                                break;
344
                            }
345
                        // take into account highest value from "chanceofrain" and "chaceofsnow"
346
                        case "chanceofrain":
347
                            {
348
                                int rain;
349
                                Int32.TryParse(oneH.Current.Value.GetString(), out rain);
350
                                weather.rain = rain > weather.rain ? rain : weather.rain;
351
                                break;
352
                            }
353
                        case "chanceofsnow":
354
                            {
355
                                int snow;
356
                                Int32.TryParse(oneH.Current.Value.GetString(), out snow);
357
                                weather.rain = snow > weather.rain ? snow : weather.rain;
358
                                break;
359
                            }
360
                        // wind kmph has to be translated to mps
361
                        case "WindGustKmph":
362
                            {
363
                                double windkmh;
364
                                Double.TryParse(oneH.Current.Value.GetString(), out windkmh);
365
                                weather.wind= windkmh * 1000 / (60.0*60.0);
366
                                break;
367
                            }
368
                        case "time":
369
                            {
370
                                int h;
371
                                Int32.TryParse(oneH.Current.Value.GetString(), out h);
372
                                h /= 100;
373
                                DateTime time = new DateTime(currParsedDay.Year, currParsedDay.Month, currParsedDay.Day, h, 0, 0);
374
                                weather.startTime = time;
375
                                break;
376
                            }
377
                    }
378
                }
379

    
380
                // Console.WriteLine(weather.ToString());
381
                Predictions.Add(weather);
382

    
383
            }
384

    
385
        }
386

    
387
        /// <summary>
388
        /// Parse current weather
389
        /// </summary>
390
        /// <param name="currentWeather">Enumerated hour of weather data</param>
391
        /// <returns>WeatherInfo with current weather</returns>
392
        private WeatherInfo ParseCurrentWeather(ArrayEnumerator currentWeather)
393
        {
394
            WeatherInfo res = new WeatherInfo();
395
            //res.current = true;
396

    
397
            while (currentWeather.MoveNext())
398
            {
399
                var obj = currentWeather.Current.EnumerateObject();
400

    
401
                while (obj.MoveNext())
402
                {
403
                    switch (obj.Current.Name)
404
                    {
405
                        case "localObsDateTime":
406
                            {
407
                                DateTime.TryParse(obj.Current.Value.GetString(), out res.startTime);
408
                                break;
409
                            }
410
                        case "FeelsLikeC":
411
                            {
412
                                Double.TryParse(obj.Current.Value.GetString(), out res.temp);
413
                                break;
414
                            }
415
                        case "cloudcover":
416
                            {
417
                                int cloudCover;
418
                                Int32.TryParse(obj.Current.Value.GetString(), out cloudCover);
419
                                res.condition = ValueToConditions.CloudCoverToConditions(cloudCover);
420
                                break;
421
                            }
422
                        case "precipMM":
423
                            {
424
                                double rainMM;
425
                                Double.TryParse(obj.Current.Value.GetString(), out rainMM);
426
                                res.rain = rainMM > 0 ? 100 : 0;
427
                                break;
428
                            }
429
                        case "windspeedKmph":
430
                            {
431
                                double wind;
432
                                Double.TryParse(obj.Current.Value.GetString(), out wind);
433
                                res.wind = wind * 1000 / (60.0 * 60.0);
434
                                break;
435
                            }
436
                    }
437
                }
438

    
439
            }
440

    
441
            return res;
442
        }
443

    
444
      
445
    }
446
}
(2-2/2)