package org.royaldev.royalbot.commands.impl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.pircbotx.hooks.types.GenericMessageEvent; import org.royaldev.royalbot.BotUtils; import org.royaldev.royalbot.RoyalBot; import org.royaldev.royalbot.commands.CallInfo; import org.royaldev.royalbot.commands.NoticeableCommand; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.DecimalFormat; public class WeatherCommand extends NoticeableCommand { private final ObjectMapper om = new ObjectMapper(); private final DecimalFormat df = new DecimalFormat("###.##"); private final String DEGREE = "\u00ba"; private double kelvinToCelsius(double kelvin) { return kelvin - 273.15D; } private double kelvinToFahrenheit(double kelvin) { return celsiusToFahrenheit(kelvinToCelsius(kelvin)); } private double celsiusToFahrenheit(double celsius) { return ((9D / 5D) * celsius) + 32D; } private String[] getOpenWeatherMapData(JsonNode jn) { JsonNode main = jn.path("main"); String cityName = jn.path("name").asText(); if (cityName.trim().isEmpty()) cityName = "area"; String weather = jn.path("weather").path(0).path("description").asText(); double cloudiness = jn.path("clouds").path("all").asDouble(); double wind = jn.path("wind").path("speed").asDouble(); double humidity = main.path("humidity").asDouble(); double kelvin = main.path("temp").asDouble(); double low = main.path("temp_min").asDouble(); double high = main.path("temp_max").asDouble(); return new String[]{ cityName, df.format(kelvinToCelsius(kelvin)) + DEGREE, df.format(kelvinToFahrenheit(kelvin)) + DEGREE, df.format(kelvinToCelsius(high)) + DEGREE, df.format(kelvinToFahrenheit(high)) + DEGREE, df.format(kelvinToCelsius(low)) + DEGREE, df.format(kelvinToFahrenheit(low)) + DEGREE, StringUtils.capitalize(weather), df.format(cloudiness) + "% cloudy", df.format(wind * 3.6D), df.format(humidity) + "%" }; } private String[] getWundergroundData(JsonNode jn) { JsonNode co = jn.path("current_observation"); JsonNode fo = jn.path("forecast").path("simpleforecast").path("forecastday").path(0); return new String[]{ co.path("display_location").path("city").asText(), df.format(co.path("temp_c").asDouble()) + DEGREE, df.format(co.path("temp_f").asDouble()) + DEGREE, df.format(fo.path("high").path("celsius").asDouble()) + DEGREE, df.format(fo.path("high").path("fahrenheit").asDouble()) + DEGREE, df.format(fo.path("low").path("celsius").asDouble()) + DEGREE, df.format(fo.path("low").path("fahrenheit").asDouble()) + DEGREE, fo.path("conditions").asText(), co.path("weather").asText(), co.path("wind_kph").asText(), co.path("relative_humidity").asText() }; } @Override public void onCommand(GenericMessageEvent event, CallInfo callInfo, String[] args) { final RoyalBot rb = RoyalBot.getInstance(); if (args.length < 1) { notice(event, "Not enough arguments."); return; } String url; try { final String query = URLEncoder.encode(StringUtils.join(args, ' '), "UTF-8"); if (rb.getConfig().isWundergroundEnabled()) url = String.format("http://api.wunderground.com/api/%s/conditions/forecast/q/%s.json", URLEncoder.encode(rb.getConfig().getWundergroundAPIKey(), "UTF-8"), query); else url = String.format("http://api.openweathermap.org/data/2.5/weather?q=%s", query); } catch (UnsupportedEncodingException ex) { notice(event, "Couldn't encode in UTF-8."); return; } JsonNode jn; try { jn = om.readTree(BotUtils.getContent(url)); } catch (Exception ex) { notice(event, "Unknown area."); return; } event.respond(String.format("Weather in %s: Currently %sC (%sF). High is %sC (%sF); low is %sC (%sF). %s. %s. Wind at %skm/h. Humidity is %s.", rb.getConfig().isWundergroundEnabled() ? getWundergroundData(jn) : getOpenWeatherMapData(jn) )); } @Override public String getName() { return "weather"; } @Override public String getUsage() { return "<command> [area]"; } @Override public String getDescription() { return "Gets the current weather for an area"; } @Override public String[] getAliases() { return new String[]{"temp", "temperature", "w"}; } @Override public CommandType getCommandType() { return CommandType.BOTH; } @Override public AuthLevel getAuthLevel() { return AuthLevel.PUBLIC; } }