package eirb.pg203; import org.json.JSONObject; import org.json.JSONArray; import eirb.pg203.utils.JSONFetcher; import java.io.IOException; import java.net.URI; import java.net.URL; import java.time.Clock; import java.time.DayOfWeek; import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; import java.util.Locale; import eirb.pg203.WeatherData.Condition; /** * OpenWeatherMap api implementation */ public class OpenWeatherMap implements WeatherDataAPI { private static final String forecastBaseURL = "https://api.openweathermap.org/data/2.5/forecast"; private String APIKey; Clock clock = Clock.systemUTC(); JSONFetcher JSONFetcher = new JSONFetcher(); OpenWeatherMap(String APIKey) { this.APIKey = APIKey; } private JSONObject fetchWeather(City city) throws IOException { URL url = URI.create( String.format(Locale.ENGLISH, forecastBaseURL + "?appid=%s&lat=%.2f&lon=%.2f&units=metric", APIKey, city.getCityCoords().getLat(), city.getCityCoords().getLon() ) ).toURL(); return JSONFetcher.fetch(url); } private WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) { JSONArray list = response.getJSONArray("list"); DayOfWeek targetedDay = Instant.now(clock).plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek(); DayOfWeek dayOfWeek; int dataCount = 0; float temp_c = 0; float windSpeed = 0; float windDirection = 0; float pop = 0; // probability of precipitation float cloudiness = 0; // percent for (int i = 0 ; i < list.length() ; ++i) { JSONObject data = list.getJSONObject(i); int timestamp = data.getInt("dt"); dayOfWeek = Instant.ofEpochSecond(timestamp).atZone(ZoneId.systemDefault()).getDayOfWeek(); if (dayOfWeek == targetedDay) { temp_c += data.getJSONObject("main").getFloat("temp"); windSpeed += data.getJSONObject("wind").getFloat("speed"); windDirection += data.getJSONObject("wind").getFloat("deg"); cloudiness += data.getJSONObject("clouds").getFloat("all"); pop += data.getFloat("pop"); dataCount++; } } if (dataCount != 0) { temp_c /= dataCount; windSpeed /= dataCount; windDirection /= dataCount; pop /= dataCount; cloudiness /= dataCount; } Condition condition = Condition.SUNNY; if (pop > 50) condition = Condition.RAINY; else if (cloudiness > 75) condition = Condition.CLOUDY; else if (cloudiness > 25) condition = Condition.PARTIAL; return new WeatherData( new City(city), Instant.now(clock).plusSeconds(day * 24 * 3600), temp_c, windSpeed, windDirection, condition ); } /** * @param day Day, 0 ≤ day ≤ 14 */ @Override public WeatherData getTemperature(int day, String city) throws IOException { JSONObject result = fetchWeather(new City(city)); return getWeatherDataFromForecast(result, day, city); } @Override public WeatherData getTemperature(int day, int hour, String city) throws IOException{ return getTemperature(day, city); } @Override public ArrayList getTemperatures(int days, String city) throws IOException { JSONObject result = fetchWeather(new City(city)); ArrayList weatherDatas = new ArrayList<>(); for (int day = 0; day < days ; ++day) { weatherDatas.add( getWeatherDataFromForecast(result, day, city) ); } return weatherDatas; } @Override public String getAPIName() { return "OpenWeatherMap"; } @Override public String toString() { return this.getAPIName(); } }